

























@@ -1,3 +1,9 @@
1+/**
2+ * Interactive skill dependency setup for onboarding.
3+ *
4+ * It reports workspace skill readiness, offers safe dependency installs, and
5+ * records per-skill API keys entered during setup.
6+ */
17import { formatCliCommand } from "../cli/command-format.js";
28import type { OpenClawConfig } from "../config/types.openclaw.js";
39import { resolveBrewExecutable } from "../infra/brew.js";
@@ -44,6 +50,7 @@ function isBrewOnlyInstallableSkill(skill: {
4450);
4551}
465253+/** Runs the interactive skills setup step and returns the updated config. */
4754export async function setupSkills(
4855cfg: OpenClawConfig,
4956workspaceDir: string,
@@ -83,12 +90,16 @@ export async function setupSkills(
8390);
8491let brewAvailable: boolean | undefined;
8592const detectBrewOnce = async () => {
93+// Brew detection can shell out; cache it for the whole skills step because
94+// install filtering and prompts both need the same answer.
8695brewAvailable ??= (await detectBinary("brew")) || resolveBrewExecutable() !== undefined;
8796return brewAvailable;
8897};
8998const inLinuxContainer = process.platform === "linux" && isContainerEnvironment();
9099let installable = baseInstallable;
91100if (inLinuxContainer && baseInstallable.length > 0 && !(await detectBrewOnce())) {
101+// Linux containers without brew cannot use brew-only recipes reliably; hide
102+// them from install selection and leave manual instructions in the note.
92103const hiddenBrewOnly = baseInstallable.filter(isBrewOnlyInstallableSkill);
93104installable = baseInstallable.filter((skill) => !isBrewOnlyInstallableSkill(skill));
94105if (hiddenBrewOnly.length > 0) {
@@ -165,6 +176,8 @@ export async function setupSkills(
165176skill.install.some((option) => option.kind === "node"),
166177);
167178if (needsNodeManagerPrompt) {
179+// Persist the package manager before invoking installers so node recipes
180+// and later skill lifecycle commands agree on the selected tool.
168181const nodeManager = (await prompter.select({
169182message: t("wizard.skills.nodeManager"),
170183options: resolveNodeManagerOptions(),
@@ -190,6 +203,8 @@ export async function setupSkills(
190203if (!installId) {
191204continue;
192205}
206+// Onboarding installs the primary recipe only; alternative recipes remain
207+// visible through `openclaw skills list --verbose`.
193208const spin = prompter.progress(t("wizard.skills.installing", { name }));
194209const result = await installSkill({
195210 workspaceDir,
@@ -233,6 +248,8 @@ export async function setupSkills(
233248if (!skill.primaryEnv || skill.missing.env.length === 0) {
234249continue;
235250}
251+// API keys entered here patch the skill entry, not process.env, so future
252+// agent sessions can resolve the same skill configuration.
236253const wantsKey = await prompter.confirm({
237254message: t("wizard.skills.setEnv", { env: skill.primaryEnv, name: skill.name }),
238255initialValue: false,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。