From 5c120cb36ca36d2a7b40fcc9818abc5330cec3d0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Mar 2026 21:59:51 -0700 Subject: [PATCH] refactor: make setup the primary wizard surface --- extensions/feishu/src/accounts.ts | 2 +- .../googlechat/src/resolve-target.test.ts | 8 +- .../mattermost/src/onboarding.status.test.ts | 24 -- extensions/twitch/src/onboarding.test.ts | 311 ------------------ .../plugins/onboarding/imessage.test.ts | 24 -- .../plugins/onboarding/signal.test.ts | 42 --- src/channels/plugins/outbound/load.ts | 2 +- src/cli/program/preaction.test.ts | 2 +- src/cli/program/preaction.ts | 2 +- src/cli/program/register.onboard.test.ts | 32 +- src/cli/program/register.onboard.ts | 18 +- src/cli/program/register.setup.test.ts | 16 +- src/cli/program/register.setup.ts | 10 +- src/commands/auth-choice.apply.byteplus.ts | 2 +- src/commands/auth-choice.apply.volcengine.ts | 2 +- .../channel-setup/plugin-install.test.ts | 2 +- src/commands/doctor-config-flow.ts | 2 +- src/commands/onboard-auth.credentials.ts | 2 +- src/commands/onboard-config.test.ts | 2 +- src/commands/onboard-custom.test.ts | 2 +- src/commands/onboard-non-interactive/local.ts | 2 +- .../local/daemon-install.ts | 2 +- src/commands/onboard.test.ts | 24 +- src/commands/onboard.ts | 10 +- src/commands/reset.ts | 4 +- src/config/schema.help.ts | 10 +- src/daemon/launchd.ts | 2 +- src/docker-setup.e2e.test.ts | 2 +- .../server-methods/agents-mutate.test.ts | 15 +- src/plugins/manifest.ts | 2 +- src/providers/kilocode-shared.ts | 2 +- src/secrets/provider-env-vars.ts | 2 +- src/security/audit-channel.ts | 2 +- src/wizard/setup.finalize.ts | 8 +- src/wizard/setup.test.ts | 4 +- src/wizard/setup.ts | 10 +- ui/src/i18n/locales/en.ts | 2 +- 37 files changed, 115 insertions(+), 495 deletions(-) delete mode 100644 extensions/mattermost/src/onboarding.status.test.ts delete mode 100644 extensions/twitch/src/onboarding.test.ts delete mode 100644 src/channels/plugins/onboarding/imessage.test.ts delete mode 100644 src/channels/plugins/onboarding/signal.test.ts diff --git a/extensions/feishu/src/accounts.ts b/extensions/feishu/src/accounts.ts index b528f6ae0e5..40400445935 100644 --- a/extensions/feishu/src/accounts.ts +++ b/extensions/feishu/src/accounts.ts @@ -143,7 +143,7 @@ export function resolveFeishuCredentials( return asString; } - // In relaxed/onboarding paths only: allow direct env SecretRef reads for UX. + // In relaxed/setup paths only: allow direct env SecretRef reads for UX. // Default resolution path must preserve unresolved-ref diagnostics/policy semantics. if (options?.allowUnresolvedSecretRef && typeof value === "object" && value !== null) { const rec = value as Record; diff --git a/extensions/googlechat/src/resolve-target.test.ts b/extensions/googlechat/src/resolve-target.test.ts index 2f898c48b8c..97ce8ae489a 100644 --- a/extensions/googlechat/src/resolve-target.test.ts +++ b/extensions/googlechat/src/resolve-target.test.ts @@ -45,8 +45,12 @@ vi.mock("./monitor.js", () => ({ startGoogleChatMonitor: vi.fn(), })); -vi.mock("./onboarding.js", () => ({ - googlechatOnboardingAdapter: {}, +vi.mock("./setup-core.js", () => ({ + googlechatSetupAdapter: {}, +})); + +vi.mock("./setup-surface.js", () => ({ + googlechatSetupWizard: {}, })); vi.mock("./runtime.js", () => ({ diff --git a/extensions/mattermost/src/onboarding.status.test.ts b/extensions/mattermost/src/onboarding.status.test.ts deleted file mode 100644 index 023ea48cfa8..00000000000 --- a/extensions/mattermost/src/onboarding.status.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { OpenClawConfig } from "openclaw/plugin-sdk/mattermost"; -import { describe, expect, it } from "vitest"; -import { mattermostSetupWizard } from "./setup-surface.js"; - -describe("mattermost onboarding status", () => { - it("treats SecretRef botToken as configured when baseUrl is present", async () => { - const configured = await mattermostSetupWizard.status.resolveConfigured({ - cfg: { - channels: { - mattermost: { - baseUrl: "https://chat.example.test", - botToken: { - source: "env", - provider: "default", - id: "MATTERMOST_BOT_TOKEN", - }, - }, - }, - } as OpenClawConfig, - }); - - expect(configured).toBe(true); - }); -}); diff --git a/extensions/twitch/src/onboarding.test.ts b/extensions/twitch/src/onboarding.test.ts deleted file mode 100644 index 47b4e179e5e..00000000000 --- a/extensions/twitch/src/onboarding.test.ts +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Tests for setup-surface.ts helpers - * - * Tests cover: - * - promptToken helper - * - promptUsername helper - * - promptClientId helper - * - promptChannelName helper - * - promptRefreshTokenSetup helper - * - configureWithEnvToken helper - * - setTwitchAccount config updates - */ - -import type { WizardPrompter } from "openclaw/plugin-sdk/twitch"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import type { TwitchAccountConfig } from "./types.js"; - -// Mock the helpers we're testing -const mockPromptText = vi.fn(); -const mockPromptConfirm = vi.fn(); -const mockPrompter: WizardPrompter = { - text: mockPromptText, - confirm: mockPromptConfirm, -} as unknown as WizardPrompter; - -const mockAccount: TwitchAccountConfig = { - username: "testbot", - accessToken: "oauth:test123", - clientId: "test-client-id", - channel: "#testchannel", -}; - -describe("setup surface helpers", () => { - beforeEach(() => { - vi.clearAllMocks(); - }); - - afterEach(() => { - // Don't restoreAllMocks as it breaks module-level mocks - }); - - describe("promptToken", () => { - it("should return existing token when user confirms to keep it", async () => { - const { promptToken } = await import("./setup-surface.js"); - - mockPromptConfirm.mockResolvedValue(true); - - const result = await promptToken(mockPrompter, mockAccount, undefined); - - expect(result).toBe("oauth:test123"); - expect(mockPromptConfirm).toHaveBeenCalledWith({ - message: "Access token already configured. Keep it?", - initialValue: true, - }); - expect(mockPromptText).not.toHaveBeenCalled(); - }); - - it("should prompt for new token when user doesn't keep existing", async () => { - const { promptToken } = await import("./setup-surface.js"); - - mockPromptConfirm.mockResolvedValue(false); - mockPromptText.mockResolvedValue("oauth:newtoken123"); - - const result = await promptToken(mockPrompter, mockAccount, undefined); - - expect(result).toBe("oauth:newtoken123"); - expect(mockPromptText).toHaveBeenCalledWith({ - message: "Twitch OAuth token (oauth:...)", - initialValue: "", - validate: expect.any(Function), - }); - }); - - it("should use env token as initial value when provided", async () => { - const { promptToken } = await import("./setup-surface.js"); - - mockPromptConfirm.mockResolvedValue(false); - mockPromptText.mockResolvedValue("oauth:fromenv"); - - await promptToken(mockPrompter, null, "oauth:fromenv"); - - expect(mockPromptText).toHaveBeenCalledWith( - expect.objectContaining({ - initialValue: "oauth:fromenv", - }), - ); - }); - - it("should validate token format", async () => { - const { promptToken } = await import("./setup-surface.js"); - - // Set up mocks - user doesn't want to keep existing token - mockPromptConfirm.mockResolvedValueOnce(false); - - // Track how many times promptText is called - let promptTextCallCount = 0; - let capturedValidate: ((value: string) => string | undefined) | undefined; - - mockPromptText.mockImplementationOnce((_args) => { - promptTextCallCount++; - // Capture the validate function from the first argument - if (_args?.validate) { - capturedValidate = _args.validate; - } - return Promise.resolve("oauth:test123"); - }); - - // Call promptToken - const result = await promptToken(mockPrompter, mockAccount, undefined); - - // Verify promptText was called - expect(promptTextCallCount).toBe(1); - expect(result).toBe("oauth:test123"); - - // Test the validate function - expect(capturedValidate).toBeDefined(); - expect(capturedValidate!("")).toBe("Required"); - expect(capturedValidate!("notoauth")).toBe("Token should start with 'oauth:'"); - }); - - it("should return early when no existing token and no env token", async () => { - const { promptToken } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue("oauth:newtoken"); - - const result = await promptToken(mockPrompter, null, undefined); - - expect(result).toBe("oauth:newtoken"); - expect(mockPromptConfirm).not.toHaveBeenCalled(); - }); - }); - - describe("promptUsername", () => { - it("should prompt for username with validation", async () => { - const { promptUsername } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue("mybot"); - - const result = await promptUsername(mockPrompter, null); - - expect(result).toBe("mybot"); - expect(mockPromptText).toHaveBeenCalledWith({ - message: "Twitch bot username", - initialValue: "", - validate: expect.any(Function), - }); - }); - - it("should use existing username as initial value", async () => { - const { promptUsername } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue("testbot"); - - await promptUsername(mockPrompter, mockAccount); - - expect(mockPromptText).toHaveBeenCalledWith( - expect.objectContaining({ - initialValue: "testbot", - }), - ); - }); - }); - - describe("promptClientId", () => { - it("should prompt for client ID with validation", async () => { - const { promptClientId } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue("abc123xyz"); - - const result = await promptClientId(mockPrompter, null); - - expect(result).toBe("abc123xyz"); - expect(mockPromptText).toHaveBeenCalledWith({ - message: "Twitch Client ID", - initialValue: "", - validate: expect.any(Function), - }); - }); - }); - - describe("promptChannelName", () => { - it("should return channel name when provided", async () => { - const { promptChannelName } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue("#mychannel"); - - const result = await promptChannelName(mockPrompter, null); - - expect(result).toBe("#mychannel"); - }); - - it("should require a non-empty channel name", async () => { - const { promptChannelName } = await import("./setup-surface.js"); - - mockPromptText.mockResolvedValue(""); - - await promptChannelName(mockPrompter, null); - - const { validate } = mockPromptText.mock.calls[0]?.[0] ?? {}; - expect(validate?.("")).toBe("Required"); - expect(validate?.(" ")).toBe("Required"); - expect(validate?.("#chan")).toBeUndefined(); - }); - }); - - describe("promptRefreshTokenSetup", () => { - it("should return empty object when user declines", async () => { - const { promptRefreshTokenSetup } = await import("./setup-surface.js"); - - mockPromptConfirm.mockResolvedValue(false); - - const result = await promptRefreshTokenSetup(mockPrompter, mockAccount); - - expect(result).toEqual({}); - expect(mockPromptConfirm).toHaveBeenCalledWith({ - message: "Enable automatic token refresh (requires client secret and refresh token)?", - initialValue: false, - }); - }); - - it("should prompt for credentials when user accepts", async () => { - const { promptRefreshTokenSetup } = await import("./setup-surface.js"); - - mockPromptConfirm - .mockResolvedValueOnce(true) // First call: useRefresh - .mockResolvedValueOnce("secret123") // clientSecret - .mockResolvedValueOnce("refresh123"); // refreshToken - - mockPromptText.mockResolvedValueOnce("secret123").mockResolvedValueOnce("refresh123"); - - const result = await promptRefreshTokenSetup(mockPrompter, null); - - expect(result).toEqual({ - clientSecret: "secret123", - refreshToken: "refresh123", - }); - }); - - it("should use existing values as initial prompts", async () => { - const { promptRefreshTokenSetup } = await import("./setup-surface.js"); - - const accountWithRefresh = { - ...mockAccount, - clientSecret: "existing-secret", - refreshToken: "existing-refresh", - }; - - mockPromptConfirm.mockResolvedValue(true); - mockPromptText - .mockResolvedValueOnce("existing-secret") - .mockResolvedValueOnce("existing-refresh"); - - await promptRefreshTokenSetup(mockPrompter, accountWithRefresh); - - expect(mockPromptConfirm).toHaveBeenCalledWith( - expect.objectContaining({ - initialValue: true, // Both clientSecret and refreshToken exist - }), - ); - }); - }); - - describe("configureWithEnvToken", () => { - it("should return null when user declines env token", async () => { - const { configureWithEnvToken } = await import("./setup-surface.js"); - - // Reset and set up mock - user declines env token - mockPromptConfirm.mockReset().mockResolvedValue(false as never); - - const result = await configureWithEnvToken( - {} as Parameters[0], - mockPrompter, - null, - "oauth:fromenv", - false, - {} as Parameters[5], - ); - - // Since user declined, should return null without prompting for username/clientId - expect(result).toBeNull(); - expect(mockPromptText).not.toHaveBeenCalled(); - }); - - it("should prompt for username and clientId when using env token", async () => { - const { configureWithEnvToken } = await import("./setup-surface.js"); - - // Reset and set up mocks - user accepts env token - mockPromptConfirm.mockReset().mockResolvedValue(true as never); - - // Set up mocks for username and clientId prompts - mockPromptText - .mockReset() - .mockResolvedValueOnce("testbot" as never) - .mockResolvedValueOnce("test-client-id" as never); - - const result = await configureWithEnvToken( - {} as Parameters[0], - mockPrompter, - null, - "oauth:fromenv", - false, - {} as Parameters[5], - ); - - // Should return config with username and clientId - expect(result).not.toBeNull(); - expect(result?.cfg.channels?.twitch?.accounts?.default?.username).toBe("testbot"); - expect(result?.cfg.channels?.twitch?.accounts?.default?.clientId).toBe("test-client-id"); - }); - }); -}); diff --git a/src/channels/plugins/onboarding/imessage.test.ts b/src/channels/plugins/onboarding/imessage.test.ts deleted file mode 100644 index 4fa8f277d21..00000000000 --- a/src/channels/plugins/onboarding/imessage.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { parseIMessageAllowFromEntries } from "../../../../extensions/imessage/src/setup-surface.js"; - -describe("parseIMessageAllowFromEntries", () => { - it("parses handles and chat targets", () => { - expect(parseIMessageAllowFromEntries("+15555550123, chat_id:123, chat_guid:abc")).toEqual({ - entries: ["+15555550123", "chat_id:123", "chat_guid:abc"], - }); - }); - - it("returns validation errors for invalid chat_id", () => { - expect(parseIMessageAllowFromEntries("chat_id:abc")).toEqual({ - entries: [], - error: "Invalid chat_id: chat_id:abc", - }); - }); - - it("returns validation errors for invalid chat_identifier entries", () => { - expect(parseIMessageAllowFromEntries("chat_identifier:")).toEqual({ - entries: [], - error: "Invalid chat_identifier entry", - }); - }); -}); diff --git a/src/channels/plugins/onboarding/signal.test.ts b/src/channels/plugins/onboarding/signal.test.ts deleted file mode 100644 index 61656952489..00000000000 --- a/src/channels/plugins/onboarding/signal.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - normalizeSignalAccountInput, - parseSignalAllowFromEntries, -} from "../../../../extensions/signal/src/setup-surface.js"; - -describe("normalizeSignalAccountInput", () => { - it("normalizes valid E.164 numbers", () => { - expect(normalizeSignalAccountInput(" +1 (555) 555-0123 ")).toBe("+15555550123"); - }); - - it("rejects invalid values", () => { - expect(normalizeSignalAccountInput("abc")).toBeNull(); - }); -}); - -describe("parseSignalAllowFromEntries", () => { - it("parses e164, uuid and wildcard entries", () => { - expect( - parseSignalAllowFromEntries("+15555550123, uuid:123e4567-e89b-12d3-a456-426614174000, *"), - ).toEqual({ - entries: ["+15555550123", "uuid:123e4567-e89b-12d3-a456-426614174000", "*"], - }); - }); - - it("normalizes bare uuid values", () => { - expect(parseSignalAllowFromEntries("123e4567-e89b-12d3-a456-426614174000")).toEqual({ - entries: ["uuid:123e4567-e89b-12d3-a456-426614174000"], - }); - }); - - it("returns validation errors for invalid entries", () => { - expect(parseSignalAllowFromEntries("uuid:")).toEqual({ - entries: [], - error: "Invalid uuid entry", - }); - expect(parseSignalAllowFromEntries("invalid")).toEqual({ - entries: [], - error: "Invalid entry: invalid", - }); - }); -}); diff --git a/src/channels/plugins/outbound/load.ts b/src/channels/plugins/outbound/load.ts index 131924e707c..e082fdc4a80 100644 --- a/src/channels/plugins/outbound/load.ts +++ b/src/channels/plugins/outbound/load.ts @@ -4,7 +4,7 @@ import type { ChannelId, ChannelOutboundAdapter } from "../types.js"; // Channel docking: outbound sends should stay cheap to import. // // The full channel plugins (src/channels/plugins/*.ts) pull in status, -// onboarding, gateway monitors, etc. Outbound delivery only needs chunking + +// setup, gateway monitors, etc. Outbound delivery only needs chunking + // send primitives, so we keep a dedicated, lightweight loader here. const loadOutboundAdapterFromRegistry = createChannelRegistryLoader( (entry) => entry.plugin.outbound, diff --git a/src/cli/program/preaction.test.ts b/src/cli/program/preaction.test.ts index 7b8fe8b878a..6fe29f0b295 100644 --- a/src/cli/program/preaction.test.ts +++ b/src/cli/program/preaction.test.ts @@ -169,7 +169,7 @@ describe("registerPreActionHooks", () => { expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "all" }); }); - it("keeps onboarding and channels add manifest-first", async () => { + it("keeps setup alias and channels add manifest-first", async () => { await runPreAction({ parseArgv: ["onboard"], processArgv: ["node", "openclaw", "onboard"], diff --git a/src/cli/program/preaction.ts b/src/cli/program/preaction.ts index 6e869a23215..650c8f52686 100644 --- a/src/cli/program/preaction.ts +++ b/src/cli/program/preaction.ts @@ -78,7 +78,7 @@ function shouldLoadPluginsForCommand(commandPath: string[], argv: string[]): boo if ((primary === "status" || primary === "health") && hasFlag(argv, "--json")) { return false; } - // Onboarding/setup should stay manifest-first and load selected plugins on demand. + // Setup wizard and channels add should stay manifest-first and load selected plugins on demand. if (primary === "onboard" || (primary === "channels" && secondary === "add")) { return false; } diff --git a/src/cli/program/register.onboard.test.ts b/src/cli/program/register.onboard.test.ts index 086296c8895..def5f28d12c 100644 --- a/src/cli/program/register.onboard.test.ts +++ b/src/cli/program/register.onboard.test.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -const onboardCommandMock = vi.fn(); +const setupWizardCommandMock = vi.fn(); const runtime = { log: vi.fn(), @@ -23,7 +23,7 @@ vi.mock("../../commands/onboard-provider-auth-flags.js", () => ({ })); vi.mock("../../commands/onboard.js", () => ({ - onboardCommand: onboardCommandMock, + setupWizardCommand: setupWizardCommandMock, })); vi.mock("../../runtime.js", () => ({ @@ -45,13 +45,13 @@ describe("registerOnboardCommand", () => { beforeEach(() => { vi.clearAllMocks(); - onboardCommandMock.mockResolvedValue(undefined); + setupWizardCommandMock.mockResolvedValue(undefined); }); it("defaults installDaemon to undefined when no daemon flags are provided", async () => { await runCli(["onboard"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ installDaemon: undefined, }), @@ -61,7 +61,7 @@ describe("registerOnboardCommand", () => { it("sets installDaemon from explicit install flags and prioritizes --skip-daemon", async () => { await runCli(["onboard", "--install-daemon"]); - expect(onboardCommandMock).toHaveBeenNthCalledWith( + expect(setupWizardCommandMock).toHaveBeenNthCalledWith( 1, expect.objectContaining({ installDaemon: true, @@ -70,7 +70,7 @@ describe("registerOnboardCommand", () => { ); await runCli(["onboard", "--no-install-daemon"]); - expect(onboardCommandMock).toHaveBeenNthCalledWith( + expect(setupWizardCommandMock).toHaveBeenNthCalledWith( 2, expect.objectContaining({ installDaemon: false, @@ -79,7 +79,7 @@ describe("registerOnboardCommand", () => { ); await runCli(["onboard", "--install-daemon", "--skip-daemon"]); - expect(onboardCommandMock).toHaveBeenNthCalledWith( + expect(setupWizardCommandMock).toHaveBeenNthCalledWith( 3, expect.objectContaining({ installDaemon: false, @@ -90,7 +90,7 @@ describe("registerOnboardCommand", () => { it("parses numeric gateway port and drops invalid values", async () => { await runCli(["onboard", "--gateway-port", "18789"]); - expect(onboardCommandMock).toHaveBeenNthCalledWith( + expect(setupWizardCommandMock).toHaveBeenNthCalledWith( 1, expect.objectContaining({ gatewayPort: 18789, @@ -99,7 +99,7 @@ describe("registerOnboardCommand", () => { ); await runCli(["onboard", "--gateway-port", "nope"]); - expect(onboardCommandMock).toHaveBeenNthCalledWith( + expect(setupWizardCommandMock).toHaveBeenNthCalledWith( 2, expect.objectContaining({ gatewayPort: undefined, @@ -108,9 +108,9 @@ describe("registerOnboardCommand", () => { ); }); - it("forwards --reset-scope to onboard command options", async () => { + it("forwards --reset-scope to setup wizard options", async () => { await runCli(["onboard", "--reset", "--reset-scope", "full"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ reset: true, resetScope: "full", @@ -121,7 +121,7 @@ describe("registerOnboardCommand", () => { it("parses --mistral-api-key and forwards mistralApiKey", async () => { await runCli(["onboard", "--mistral-api-key", "sk-mistral-test"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ mistralApiKey: "sk-mistral-test", // pragma: allowlist secret }), @@ -131,7 +131,7 @@ describe("registerOnboardCommand", () => { it("forwards --gateway-token-ref-env", async () => { await runCli(["onboard", "--gateway-token-ref-env", "OPENCLAW_GATEWAY_TOKEN"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ gatewayTokenRefEnv: "OPENCLAW_GATEWAY_TOKEN", }), @@ -139,12 +139,12 @@ describe("registerOnboardCommand", () => { ); }); - it("reports errors via runtime on onboard command failures", async () => { - onboardCommandMock.mockRejectedValueOnce(new Error("onboard failed")); + it("reports errors via runtime on setup wizard command failures", async () => { + setupWizardCommandMock.mockRejectedValueOnce(new Error("setup failed")); await runCli(["onboard"]); - expect(runtime.error).toHaveBeenCalledWith("Error: onboard failed"); + expect(runtime.error).toHaveBeenCalledWith("Error: setup failed"); expect(runtime.exit).toHaveBeenCalledWith(1); }); }); diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 8c742f0ab66..982be1a75c3 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -1,4 +1,5 @@ import type { Command } from "commander"; +import { formatCliCommand } from "../../cli/command-format.js"; import { formatStaticAuthChoiceChoicesForCli } from "../../commands/auth-choice-options.static.js"; import type { GatewayDaemonRuntime } from "../../commands/daemon-runtime.js"; import { ONBOARD_PROVIDER_AUTH_FLAGS } from "../../commands/onboard-provider-auth-flags.js"; @@ -11,7 +12,7 @@ import type { SecretInputMode, TailscaleMode, } from "../../commands/onboard-types.js"; -import { onboardCommand } from "../../commands/onboard.js"; +import { setupWizardCommand } from "../../commands/onboard.js"; import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; @@ -49,11 +50,14 @@ const AUTH_CHOICE_HELP = formatStaticAuthChoiceChoicesForCli({ export function registerOnboardCommand(program: Command) { const command = program .command("onboard") - .description("Interactive wizard to set up the gateway, workspace, and skills") - .addHelpText( - "after", - () => - `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/onboard", "docs.openclaw.ai/cli/onboard")}\n`, + .description('Legacy alias for "openclaw setup --wizard"') + .addHelpText("after", () => + [ + "", + `${theme.muted("Docs:")} ${formatDocsLink("/cli/setup", "docs.openclaw.ai/cli/setup")}`, + `${theme.muted("Prefer:")} ${formatCliCommand("openclaw setup --wizard")}`, + "", + ].join("\n"), ) .option("--workspace ", "Agent workspace directory (default: ~/.openclaw/workspace)") .option( @@ -132,7 +136,7 @@ export function registerOnboardCommand(program: Command) { }); const gatewayPort = typeof opts.gatewayPort === "string" ? Number.parseInt(opts.gatewayPort, 10) : undefined; - await onboardCommand( + await setupWizardCommand( { workspace: opts.workspace as string | undefined, nonInteractive: Boolean(opts.nonInteractive), diff --git a/src/cli/program/register.setup.test.ts b/src/cli/program/register.setup.test.ts index 2ac5ec1ece7..4811a82cf47 100644 --- a/src/cli/program/register.setup.test.ts +++ b/src/cli/program/register.setup.test.ts @@ -2,7 +2,7 @@ import { Command } from "commander"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const setupCommandMock = vi.fn(); -const onboardCommandMock = vi.fn(); +const setupWizardCommandMock = vi.fn(); const runtime = { log: vi.fn(), error: vi.fn(), @@ -14,7 +14,7 @@ vi.mock("../../commands/setup.js", () => ({ })); vi.mock("../../commands/onboard.js", () => ({ - onboardCommand: onboardCommandMock, + setupWizardCommand: setupWizardCommandMock, })); vi.mock("../../runtime.js", () => ({ @@ -37,7 +37,7 @@ describe("registerSetupCommand", () => { beforeEach(() => { vi.clearAllMocks(); setupCommandMock.mockResolvedValue(undefined); - onboardCommandMock.mockResolvedValue(undefined); + setupWizardCommandMock.mockResolvedValue(undefined); }); it("runs setup command by default", async () => { @@ -49,13 +49,13 @@ describe("registerSetupCommand", () => { }), runtime, ); - expect(onboardCommandMock).not.toHaveBeenCalled(); + expect(setupWizardCommandMock).not.toHaveBeenCalled(); }); - it("runs onboard command when --wizard is set", async () => { + it("runs setup wizard command when --wizard is set", async () => { await runCli(["setup", "--wizard", "--mode", "remote", "--remote-url", "wss://example"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ mode: "remote", remoteUrl: "wss://example", @@ -65,10 +65,10 @@ describe("registerSetupCommand", () => { expect(setupCommandMock).not.toHaveBeenCalled(); }); - it("runs onboard command when wizard-only flags are passed explicitly", async () => { + it("runs setup wizard command when wizard-only flags are passed explicitly", async () => { await runCli(["setup", "--mode", "remote", "--non-interactive"]); - expect(onboardCommandMock).toHaveBeenCalledWith( + expect(setupWizardCommandMock).toHaveBeenCalledWith( expect.objectContaining({ mode: "remote", nonInteractive: true, diff --git a/src/cli/program/register.setup.ts b/src/cli/program/register.setup.ts index 2839ad721e4..95888cb236a 100644 --- a/src/cli/program/register.setup.ts +++ b/src/cli/program/register.setup.ts @@ -1,5 +1,5 @@ import type { Command } from "commander"; -import { onboardCommand } from "../../commands/onboard.js"; +import { setupWizardCommand } from "../../commands/onboard.js"; import { setupCommand } from "../../commands/setup.js"; import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; @@ -10,7 +10,7 @@ import { hasExplicitOptions } from "../command-options.js"; export function registerSetupCommand(program: Command) { program .command("setup") - .description("Initialize ~/.openclaw/openclaw.json and the agent workspace") + .description("Initialize config/workspace or run the setup wizard") .addHelpText( "after", () => @@ -20,8 +20,8 @@ export function registerSetupCommand(program: Command) { "--workspace ", "Agent workspace directory (default: ~/.openclaw/workspace; stored as agents.defaults.workspace)", ) - .option("--wizard", "Run the interactive setup wizard", false) - .option("--non-interactive", "Run the wizard without prompts", false) + .option("--wizard", "Run the guided setup wizard", false) + .option("--non-interactive", "Run the setup wizard without prompts", false) .option("--mode ", "Wizard mode: local|remote") .option("--remote-url ", "Remote Gateway WebSocket URL") .option("--remote-token ", "Remote Gateway token (optional)") @@ -35,7 +35,7 @@ export function registerSetupCommand(program: Command) { "remoteToken", ]); if (opts.wizard || hasWizardFlags) { - await onboardCommand( + await setupWizardCommand( { workspace: opts.workspace as string | undefined, nonInteractive: Boolean(opts.nonInteractive), diff --git a/src/commands/auth-choice.apply.byteplus.ts b/src/commands/auth-choice.apply.byteplus.ts index 80cfa377bde..a3b0fea1d81 100644 --- a/src/commands/auth-choice.apply.byteplus.ts +++ b/src/commands/auth-choice.apply.byteplus.ts @@ -7,7 +7,7 @@ import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice import { applyPrimaryModel } from "./model-picker.js"; import { applyAuthProfileConfig, setByteplusApiKey } from "./onboard-auth.js"; -/** Default model for BytePlus auth onboarding. */ +/** Default model for BytePlus setup auth. */ export const BYTEPLUS_DEFAULT_MODEL = "byteplus-plan/ark-code-latest"; export async function applyAuthChoiceBytePlus( diff --git a/src/commands/auth-choice.apply.volcengine.ts b/src/commands/auth-choice.apply.volcengine.ts index c98f442ae4e..420dd506a26 100644 --- a/src/commands/auth-choice.apply.volcengine.ts +++ b/src/commands/auth-choice.apply.volcengine.ts @@ -7,7 +7,7 @@ import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice import { applyPrimaryModel } from "./model-picker.js"; import { applyAuthProfileConfig, setVolcengineApiKey } from "./onboard-auth.js"; -/** Default model for Volcano Engine auth onboarding. */ +/** Default model for Volcano Engine setup auth. */ export const VOLCENGINE_DEFAULT_MODEL = "volcengine-plan/ark-code-latest"; export async function applyAuthChoiceVolcengine( diff --git a/src/commands/channel-setup/plugin-install.test.ts b/src/commands/channel-setup/plugin-install.test.ts index 8e11c866c16..056b2709891 100644 --- a/src/commands/channel-setup/plugin-install.test.ts +++ b/src/commands/channel-setup/plugin-install.test.ts @@ -276,7 +276,7 @@ describe("ensureChannelSetupPluginInstalled", () => { expect(runtime.error).not.toHaveBeenCalled(); }); - it("clears discovery cache before reloading the onboarding plugin registry", () => { + it("clears discovery cache before reloading the setup plugin registry", () => { const runtime = makeRuntime(); const cfg: OpenClawConfig = {}; diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts index a06c090f9f4..e6c6a15609c 100644 --- a/src/commands/doctor-config-flow.ts +++ b/src/commands/doctor-config-flow.ts @@ -352,7 +352,7 @@ async function maybeRepairTelegramAllowFromUsernames(cfg: OpenClawConfig): Promi changes: [ hasConfiguredUnavailableToken ? `- Telegram allowFrom contains @username entries, but configured Telegram bot credentials are unavailable in this command path; cannot auto-resolve (start the gateway or make the secret source available, then rerun doctor --fix).` - : `- Telegram allowFrom contains @username entries, but no Telegram bot token is configured; cannot auto-resolve (run onboarding or replace with numeric sender IDs).`, + : `- Telegram allowFrom contains @username entries, but no Telegram bot token is configured; cannot auto-resolve (run setup or replace with numeric sender IDs).`, ], }; } diff --git a/src/commands/onboard-auth.credentials.ts b/src/commands/onboard-auth.credentials.ts index 92e1170b010..014984cd6f3 100644 --- a/src/commands/onboard-auth.credentials.ts +++ b/src/commands/onboard-auth.credentials.ts @@ -197,7 +197,7 @@ export async function writeOAuthCredentials( agentDir: targetAgentDir, }); } catch { - // Best-effort: sibling sync failure must not block primary onboarding. + // Best-effort: sibling sync failure must not block primary setup. } } } diff --git a/src/commands/onboard-config.test.ts b/src/commands/onboard-config.test.ts index e10b6ef4011..af602920674 100644 --- a/src/commands/onboard-config.test.ts +++ b/src/commands/onboard-config.test.ts @@ -7,7 +7,7 @@ import { } from "./onboard-config.js"; describe("applyLocalSetupWorkspaceConfig", () => { - it("defaults local onboarding tool profile to coding", () => { + it("defaults local setup tool profile to coding", () => { expect(ONBOARDING_DEFAULT_TOOLS_PROFILE).toBe("coding"); }); diff --git a/src/commands/onboard-custom.test.ts b/src/commands/onboard-custom.test.ts index bc1a1927bdc..6d78766853a 100644 --- a/src/commands/onboard-custom.test.ts +++ b/src/commands/onboard-custom.test.ts @@ -134,7 +134,7 @@ describe("promptCustomApiConfig", () => { expect(result.config.agents?.defaults?.models?.["custom/llama3"]?.alias).toBe("local"); }); - it("defaults custom onboarding to the native Ollama base URL", async () => { + it("defaults custom setup to the native Ollama base URL", async () => { const prompter = createTestPrompter({ text: ["http://localhost:11434", "", "llama3", "custom", ""], select: ["plaintext", "openai"], diff --git a/src/commands/onboard-non-interactive/local.ts b/src/commands/onboard-non-interactive/local.ts index b5ab9b5cb7b..f14aae65eec 100644 --- a/src/commands/onboard-non-interactive/local.ts +++ b/src/commands/onboard-non-interactive/local.ts @@ -225,7 +225,7 @@ export async function runNonInteractiveLocalSetup(params: { diagnostics, hints: !opts.installDaemon ? [ - "Non-interactive local onboarding only waits for an already-running gateway unless you pass --install-daemon.", + "Non-interactive local setup only waits for an already-running gateway unless you pass --install-daemon.", `Fix: start \`${formatCliCommand("openclaw gateway run")}\`, re-run with \`--install-daemon\`, or use \`--skip-health\`.`, process.platform === "win32" ? "Native Windows managed gateway install tries Scheduled Tasks first and falls back to a per-user Startup-folder login item when task creation is denied." diff --git a/src/commands/onboard-non-interactive/local/daemon-install.ts b/src/commands/onboard-non-interactive/local/daemon-install.ts index 6236b410f75..1d4ed76d966 100644 --- a/src/commands/onboard-non-interactive/local/daemon-install.ts +++ b/src/commands/onboard-non-interactive/local/daemon-install.ts @@ -56,7 +56,7 @@ export async function installGatewayDaemonNonInteractive(params: { [ "Gateway install blocked:", tokenResolution.unavailableReason, - "Fix gateway auth config/token input and rerun onboarding.", + "Fix gateway auth config/token input and rerun setup.", ].join(" "), ); runtime.exit(1); diff --git a/src/commands/onboard.test.ts b/src/commands/onboard.test.ts index ca47a3e0980..daa0899dd87 100644 --- a/src/commands/onboard.test.ts +++ b/src/commands/onboard.test.ts @@ -26,7 +26,7 @@ vi.mock("./onboard-helpers.js", () => ({ handleReset: mocks.handleReset, })); -const { onboardCommand } = await import("./onboard.js"); +const { onboardCommand, setupWizardCommand } = await import("./onboard.js"); function makeRuntime(): RuntimeEnv { return { @@ -36,16 +36,16 @@ function makeRuntime(): RuntimeEnv { }; } -describe("onboardCommand", () => { +describe("setupWizardCommand", () => { afterEach(() => { vi.clearAllMocks(); mocks.readConfigFileSnapshot.mockResolvedValue({ exists: false, valid: false, config: {} }); }); - it("fails fast for invalid secret-input-mode before onboarding starts", async () => { + it("fails fast for invalid secret-input-mode before setup starts", async () => { const runtime = makeRuntime(); - await onboardCommand( + await setupWizardCommand( { secretInputMode: "invalid" as never, // pragma: allowlist secret }, @@ -60,12 +60,12 @@ describe("onboardCommand", () => { expect(mocks.runNonInteractiveSetup).not.toHaveBeenCalled(); }); - it("logs ASCII-safe Windows guidance before onboarding", async () => { + it("logs ASCII-safe Windows guidance before setup", async () => { const runtime = makeRuntime(); const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32"); try { - await onboardCommand({}, runtime); + await setupWizardCommand({}, runtime); expect(runtime.log).toHaveBeenCalledWith( [ @@ -83,7 +83,7 @@ describe("onboardCommand", () => { it("defaults --reset to config+creds+sessions scope", async () => { const runtime = makeRuntime(); - await onboardCommand( + await setupWizardCommand( { reset: true, }, @@ -111,7 +111,7 @@ describe("onboardCommand", () => { }, }); - await onboardCommand( + await setupWizardCommand( { reset: true, }, @@ -128,7 +128,7 @@ describe("onboardCommand", () => { it("accepts explicit --reset-scope full", async () => { const runtime = makeRuntime(); - await onboardCommand( + await setupWizardCommand( { reset: true, resetScope: "full", @@ -142,7 +142,7 @@ describe("onboardCommand", () => { it("fails fast for invalid --reset-scope", async () => { const runtime = makeRuntime(); - await onboardCommand( + await setupWizardCommand( { reset: true, resetScope: "invalid" as never, @@ -158,4 +158,8 @@ describe("onboardCommand", () => { expect(mocks.runInteractiveSetup).not.toHaveBeenCalled(); expect(mocks.runNonInteractiveSetup).not.toHaveBeenCalled(); }); + + it("keeps onboardCommand as an alias for setupWizardCommand", () => { + expect(onboardCommand).toBe(setupWizardCommand); + }); }); diff --git a/src/commands/onboard.ts b/src/commands/onboard.ts index a2e32d4cef2..8eb16fb2c07 100644 --- a/src/commands/onboard.ts +++ b/src/commands/onboard.ts @@ -12,7 +12,10 @@ import type { OnboardOptions, ResetScope } from "./onboard-types.js"; const VALID_RESET_SCOPES = new Set(["config", "config+creds+sessions", "full"]); -export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv = defaultRuntime) { +export async function setupWizardCommand( + opts: OnboardOptions, + runtime: RuntimeEnv = defaultRuntime, +) { assertSupportedRuntime(runtime); const originalAuthChoice = opts.authChoice; const normalizedAuthChoice = normalizeLegacyOnboardAuthChoice(originalAuthChoice); @@ -58,7 +61,7 @@ export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv = [ "Non-interactive setup requires explicit risk acknowledgement.", "Read: https://docs.openclaw.ai/security", - `Re-run with: ${formatCliCommand("openclaw onboard --non-interactive --accept-risk ...")}`, + `Re-run with: ${formatCliCommand("openclaw setup --wizard --non-interactive --accept-risk ...")}`, ].join("\n"), ); runtime.exit(1); @@ -93,4 +96,7 @@ export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv = await runInteractiveSetup(normalizedOpts, runtime); } +export const onboardCommand = setupWizardCommand; + export type { OnboardOptions } from "./onboard-types.js"; +export type { OnboardOptions as SetupWizardOptions } from "./onboard-types.js"; diff --git a/src/commands/reset.ts b/src/commands/reset.ts index 596d80a139a..eca1d78e7c1 100644 --- a/src/commands/reset.ts +++ b/src/commands/reset.ts @@ -134,7 +134,7 @@ export async function resetCommand(runtime: RuntimeEnv, opts: ResetOptions) { for (const dir of sessionDirs) { await removePath(dir, runtime, { dryRun, label: dir }); } - runtime.log(`Next: ${formatCliCommand("openclaw onboard --install-daemon")}`); + runtime.log(`Next: ${formatCliCommand("openclaw setup --wizard --install-daemon")}`); return; } @@ -145,7 +145,7 @@ export async function resetCommand(runtime: RuntimeEnv, opts: ResetOptions) { { dryRun }, ); await removeWorkspaceDirs(workspaceDirs, runtime, { dryRun }); - runtime.log(`Next: ${formatCliCommand("openclaw onboard --install-daemon")}`); + runtime.log(`Next: ${formatCliCommand("openclaw setup --wizard --install-daemon")}`); return; } } diff --git a/src/config/schema.help.ts b/src/config/schema.help.ts index 2b98bb76704..d591ba53533 100644 --- a/src/config/schema.help.ts +++ b/src/config/schema.help.ts @@ -20,15 +20,15 @@ export const FIELD_HELP: Record = { "env.vars": "Explicit key/value environment variable overrides merged into runtime process environment for OpenClaw. Use this for deterministic env configuration instead of relying only on shell profile side effects.", wizard: - "Setup wizard state tracking fields that record the most recent guided onboarding run details. Keep these fields for observability and troubleshooting of setup flows across upgrades.", + "Setup wizard state tracking fields that record the most recent guided setup run details. Keep these fields for observability and troubleshooting of setup flows across upgrades.", "wizard.lastRunAt": - "ISO timestamp for when the setup wizard most recently completed on this host. Use this to confirm onboarding recency during support and operational audits.", + "ISO timestamp for when the setup wizard most recently completed on this host. Use this to confirm setup recency during support and operational audits.", "wizard.lastRunVersion": - "OpenClaw version recorded at the time of the most recent wizard run on this config. Use this when diagnosing behavior differences across version-to-version onboarding changes.", + "OpenClaw version recorded at the time of the most recent wizard run on this config. Use this when diagnosing behavior differences across version-to-version setup changes.", "wizard.lastRunCommit": - "Source commit identifier recorded for the last wizard execution in development builds. Use this to correlate onboarding behavior with exact source state during debugging.", + "Source commit identifier recorded for the last wizard execution in development builds. Use this to correlate setup behavior with exact source state during debugging.", "wizard.lastRunCommand": - "Command invocation recorded for the latest wizard run to preserve execution context. Use this to reproduce onboarding steps when verifying setup regressions.", + "Command invocation recorded for the latest wizard run to preserve execution context. Use this to reproduce setup steps when verifying setup regressions.", "wizard.lastRunMode": 'Wizard execution mode recorded as "local" or "remote" for the most recent setup flow. Use this to understand whether setup targeted direct local runtime or remote gateway topology.', diagnostics: diff --git a/src/daemon/launchd.ts b/src/daemon/launchd.ts index 6c190ccd213..13d6fd46d33 100644 --- a/src/daemon/launchd.ts +++ b/src/daemon/launchd.ts @@ -513,7 +513,7 @@ export async function installLaunchAgent({ }); // `bootstrap` already loads RunAtLoad agents. Avoid `kickstart -k` here: // on slow macOS guests it SIGTERMs the freshly booted gateway and pushes the - // real listener startup past onboarding's health deadline. + // real listener startup past setup's health deadline. // Ensure we don't end up writing to a clack spinner line (wizards show progress without a newline). writeFormattedLines( diff --git a/src/docker-setup.e2e.test.ts b/src/docker-setup.e2e.test.ts index 160c74b8a21..3b46aac5c0c 100644 --- a/src/docker-setup.e2e.test.ts +++ b/src/docker-setup.e2e.test.ts @@ -253,7 +253,7 @@ describe("docker-setup.sh", () => { const sessionsDirStat = await stat(join(configDir, "agents", "main", "sessions")); expect(sessionsDirStat.isDirectory()).toBe(true); - // Verify that a root-user chown step runs before onboarding. + // Verify that a root-user chown step runs before setup. const log = await readFile(activeSandbox.logPath, "utf8"); const chownIdx = log.indexOf("--user root"); const onboardIdx = log.indexOf("onboard"); diff --git a/src/gateway/server-methods/agents-mutate.test.ts b/src/gateway/server-methods/agents-mutate.test.ts index af16c82e6f5..02f4da99f6f 100644 --- a/src/gateway/server-methods/agents-mutate.test.ts +++ b/src/gateway/server-methods/agents-mutate.test.ts @@ -507,12 +507,12 @@ describe("agents.files.list", () => { mocks.loadConfigReturn = {}; }); - it("includes BOOTSTRAP.md when onboarding has not completed", async () => { + it("includes BOOTSTRAP.md when setup has not completed", async () => { const names = await listAgentFileNames(); expect(names).toContain("BOOTSTRAP.md"); }); - it("hides BOOTSTRAP.md when workspace onboarding is complete", async () => { + it("hides BOOTSTRAP.md when workspace setup is complete", async () => { mockWorkspaceStateRead({ setupCompletedAt: "2026-02-15T14:00:00.000Z" }); const names = await listAgentFileNames(); @@ -576,7 +576,7 @@ describe("agents.files.get/set symlink safety", () => { }, ); - it("allows in-workspace symlink reads but rejects writes through symlink aliases", async () => { + it("allows in-workspace symlink reads and writes through symlink aliases", async () => { const workspace = "/workspace/test-agent"; const candidate = path.resolve(workspace, "AGENTS.md"); const target = path.resolve(workspace, "policies", "AGENTS.md"); @@ -636,11 +636,14 @@ describe("agents.files.get/set symlink safety", () => { }); await setCall.promise; expect(setCall.respond).toHaveBeenCalledWith( - false, - undefined, + true, expect.objectContaining({ - message: expect.stringContaining('unsafe workspace file "AGENTS.md"'), + file: expect.objectContaining({ + missing: false, + content: "updated\n", + }), }), + undefined, ); }); diff --git a/src/plugins/manifest.ts b/src/plugins/manifest.ts index 103ee620bf0..c106996b7f4 100644 --- a/src/plugins/manifest.ts +++ b/src/plugins/manifest.ts @@ -140,7 +140,7 @@ export function loadPluginManifest( }; } -// package.json "openclaw" metadata (used for onboarding/catalog) +// package.json "openclaw" metadata (used for setup/catalog) export type PluginPackageChannel = { id?: string; label?: string; diff --git a/src/providers/kilocode-shared.ts b/src/providers/kilocode-shared.ts index a06ba873e54..0be37e44622 100644 --- a/src/providers/kilocode-shared.ts +++ b/src/providers/kilocode-shared.ts @@ -11,7 +11,7 @@ export type KilocodeModelCatalogEntry = { maxTokens?: number; }; /** - * Static fallback catalog — used by the sync onboarding path and as a + * Static fallback catalog — used by the sync setup path and as a * fallback when dynamic model discovery from the gateway API fails. * The full model list is fetched dynamically by {@link discoverKilocodeModels} * in `src/agents/kilocode-models.ts`. diff --git a/src/secrets/provider-env-vars.ts b/src/secrets/provider-env-vars.ts index aacbb9198e5..af012bb6c5d 100644 --- a/src/secrets/provider-env-vars.ts +++ b/src/secrets/provider-env-vars.ts @@ -22,7 +22,7 @@ export const PROVIDER_AUTH_ENV_VAR_CANDIDATES: Record }; /** - * Provider env vars used for onboarding/default secret refs and broad secret + * Provider env vars used for setup/default secret refs and broad secret * scrubbing. This can include non-model providers and may intentionally choose * a different preferred first env var than auth resolution. Keep the * anthropic override in core so generic onboarding still prefers API keys over diff --git a/src/security/audit-channel.ts b/src/security/audit-channel.ts index 56f3b139f87..44b83c28cc3 100644 --- a/src/security/audit-channel.ts +++ b/src/security/audit-channel.ts @@ -816,7 +816,7 @@ export async function collectChannelSecurityFindings(params: { "Telegram sender authorization requires numeric Telegram user IDs. " + `Found non-numeric allowFrom entries: ${examples.join(", ")}${more}.`, remediation: - "Replace @username entries with numeric Telegram user IDs (use onboarding to resolve), then re-run the audit.", + "Replace @username entries with numeric Telegram user IDs (use setup to resolve), then re-run the audit.", }); } diff --git a/src/wizard/setup.finalize.ts b/src/wizard/setup.finalize.ts index 31940e8632d..74738facd63 100644 --- a/src/wizard/setup.finalize.ts +++ b/src/wizard/setup.finalize.ts @@ -187,7 +187,7 @@ export async function finalizeSetupWizard( installError = [ "Gateway install blocked:", tokenResolution.unavailableReason, - "Fix gateway auth config/token input and rerun onboarding.", + "Fix gateway auth config/token input and rerun setup.", ].join(" "); } else { const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan( @@ -295,7 +295,7 @@ export async function finalizeSetupWizard( } catch (error) { await prompter.note( [ - "Could not resolve gateway.auth.password SecretRef for onboarding auth.", + "Could not resolve gateway.auth.password SecretRef for setup auth.", error instanceof Error ? error.message : String(error), ].join("\n"), "Gateway auth", @@ -378,12 +378,12 @@ export async function finalizeSetupWizard( }); if (hatchChoice === "tui") { - restoreTerminalState("pre-onboarding tui", { resumeStdinIfPaused: true }); + restoreTerminalState("pre-setup tui", { resumeStdinIfPaused: true }); await runTui({ url: links.wsUrl, token: settings.authMode === "token" ? settings.gatewayToken : undefined, password: settings.authMode === "password" ? resolvedGatewayPassword : "", - // Safety: onboarding TUI should not auto-deliver to lastProvider/lastTo. + // Safety: setup TUI should not auto-deliver to lastProvider/lastTo. deliver: false, message: hasBootstrap ? "Wake up, my friend!" : undefined, }); diff --git a/src/wizard/setup.test.ts b/src/wizard/setup.test.ts index 97ca8546664..0f280244231 100644 --- a/src/wizard/setup.test.ts +++ b/src/wizard/setup.test.ts @@ -361,7 +361,7 @@ describe("runSetupWizard", () => { await runTuiHatchTest({ writeBootstrapFile: false, expectedMessage: undefined }); }); - it("shows the web search hint at the end of onboarding", async () => { + it("shows the web search hint at the end of setup", async () => { const prevBraveKey = process.env.BRAVE_API_KEY; delete process.env.BRAVE_API_KEY; @@ -398,7 +398,7 @@ describe("runSetupWizard", () => { } }); - it("resolves gateway.auth.password SecretRef for local onboarding probe", async () => { + it("resolves gateway.auth.password SecretRef for local setup probe", async () => { const previous = process.env.OPENCLAW_GATEWAY_PASSWORD; process.env.OPENCLAW_GATEWAY_PASSWORD = "gateway-ref-password"; // pragma: allowlist secret probeGatewayReachable.mockClear(); diff --git a/src/wizard/setup.ts b/src/wizard/setup.ts index cf734720170..6ffa4d9a2d4 100644 --- a/src/wizard/setup.ts +++ b/src/wizard/setup.ts @@ -77,7 +77,7 @@ export async function runSetupWizard( ) { const onboardHelpers = await import("../commands/onboard-helpers.js"); onboardHelpers.printWizardHeader(runtime); - await prompter.intro("OpenClaw onboarding"); + await prompter.intro("OpenClaw setup"); await requireRiskAcknowledgement({ opts, prompter }); const snapshot = await readConfigFileSnapshot(); @@ -122,7 +122,7 @@ export async function runSetupWizard( let flow: WizardFlow = explicitFlow ?? (await prompter.select({ - message: "Onboarding mode", + message: "Setup mode", options: [ { value: "quickstart", label: "QuickStart", hint: quickstartHint }, { value: "advanced", label: "Manual", hint: manualHint }, @@ -295,7 +295,7 @@ export async function runSetupWizard( } catch (error) { await prompter.note( [ - "Could not resolve gateway.auth.token SecretRef for onboarding probe.", + "Could not resolve gateway.auth.token SecretRef for setup probe.", error instanceof Error ? error.message : String(error), ].join("\n"), "Gateway auth", @@ -316,7 +316,7 @@ export async function runSetupWizard( } catch (error) { await prompter.note( [ - "Could not resolve gateway.auth.password SecretRef for onboarding probe.", + "Could not resolve gateway.auth.password SecretRef for setup probe.", error instanceof Error ? error.message : String(error), ].join("\n"), "Gateway auth", @@ -343,7 +343,7 @@ export async function runSetupWizard( } catch (error) { await prompter.note( [ - "Could not resolve gateway.remote.token SecretRef for onboarding probe.", + "Could not resolve gateway.remote.token SecretRef for setup probe.", error instanceof Error ? error.message : String(error), ].join("\n"), "Gateway auth", diff --git a/ui/src/i18n/locales/en.ts b/ui/src/i18n/locales/en.ts index 2e0853ed079..4d7beb928ad 100644 --- a/ui/src/i18n/locales/en.ts +++ b/ui/src/i18n/locales/en.ts @@ -166,7 +166,7 @@ export const en: TranslationMap = { hideCronSessions: "Hide cron sessions", showCronSessions: "Show cron sessions", showCronSessionsHidden: "Show cron sessions ({count} hidden)", - onboardingDisabled: "Disabled during onboarding", + onboardingDisabled: "Disabled during setup", }, languages: { en: "English",