| import type { Command } from "commander"; |
| import { formatAuthChoiceChoicesForCli } from "../../commands/auth-choice-options.js"; |
| import type { GatewayDaemonRuntime } from "../../commands/daemon-runtime.js"; |
| import { ONBOARD_PROVIDER_AUTH_FLAGS } from "../../commands/onboard-provider-auth-flags.js"; |
| import type { |
| AuthChoice, |
| GatewayAuthChoice, |
| GatewayBind, |
| NodeManagerChoice, |
| ResetScope, |
| SecretInputMode, |
| TailscaleMode, |
| } from "../../commands/onboard-types.js"; |
| import { onboardCommand } from "../../commands/onboard.js"; |
| import { defaultRuntime } from "../../runtime.js"; |
| import { formatDocsLink } from "../../terminal/links.js"; |
| import { theme } from "../../terminal/theme.js"; |
| import { runCommandWithRuntime } from "../cli-utils.js"; |
|
|
| function resolveInstallDaemonFlag( |
| command: unknown, |
| opts: { installDaemon?: boolean }, |
| ): boolean | undefined { |
| if (!command || typeof command !== "object") { |
| return undefined; |
| } |
| const getOptionValueSource = |
| "getOptionValueSource" in command ? command.getOptionValueSource : undefined; |
| if (typeof getOptionValueSource !== "function") { |
| return undefined; |
| } |
|
|
| |
| |
| if (getOptionValueSource.call(command, "skipDaemon") === "cli") { |
| return false; |
| } |
| if (getOptionValueSource.call(command, "installDaemon") === "cli") { |
| return Boolean(opts.installDaemon); |
| } |
| return undefined; |
| } |
|
|
| const AUTH_CHOICE_HELP = formatAuthChoiceChoicesForCli({ |
| includeLegacyAliases: true, |
| includeSkip: true, |
| }); |
|
|
| 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`, |
| ) |
| .option("--workspace <dir>", "Agent workspace directory (default: ~/.openclaw/workspace)") |
| .option( |
| "--reset", |
| "Reset config + credentials + sessions before running wizard (workspace only with --reset-scope full)", |
| ) |
| .option("--reset-scope <scope>", "Reset scope: config|config+creds+sessions|full") |
| .option("--non-interactive", "Run without prompts", false) |
| .option( |
| "--accept-risk", |
| "Acknowledge that agents are powerful and full system access is risky (required for --non-interactive)", |
| false, |
| ) |
| .option("--flow <flow>", "Wizard flow: quickstart|advanced|manual") |
| .option("--mode <mode>", "Wizard mode: local|remote") |
| .option("--auth-choice <choice>", `Auth: ${AUTH_CHOICE_HELP}`) |
| .option( |
| "--token-provider <id>", |
| "Token provider id (non-interactive; used with --auth-choice token)", |
| ) |
| .option("--token <token>", "Token value (non-interactive; used with --auth-choice token)") |
| .option( |
| "--token-profile-id <id>", |
| "Auth profile id (non-interactive; default: <provider>:manual)", |
| ) |
| .option("--token-expires-in <duration>", "Optional token expiry duration (e.g. 365d, 12h)") |
| .option( |
| "--secret-input-mode <mode>", |
| "API key persistence mode: plaintext|ref (default: plaintext)", |
| ) |
| .option("--cloudflare-ai-gateway-account-id <id>", "Cloudflare Account ID") |
| .option("--cloudflare-ai-gateway-gateway-id <id>", "Cloudflare AI Gateway ID"); |
|
|
| for (const providerFlag of ONBOARD_PROVIDER_AUTH_FLAGS) { |
| command.option(providerFlag.cliOption, providerFlag.description); |
| } |
|
|
| command |
| .option("--custom-base-url <url>", "Custom provider base URL") |
| .option("--custom-api-key <key>", "Custom provider API key (optional)") |
| .option("--custom-model-id <id>", "Custom provider model ID") |
| .option("--custom-provider-id <id>", "Custom provider ID (optional; auto-derived by default)") |
| .option( |
| "--custom-compatibility <mode>", |
| "Custom provider API compatibility: openai|anthropic (default: openai)", |
| ) |
| .option("--gateway-port <port>", "Gateway port") |
| .option("--gateway-bind <mode>", "Gateway bind: loopback|tailnet|lan|auto|custom") |
| .option("--gateway-auth <mode>", "Gateway auth: token|password") |
| .option("--gateway-token <token>", "Gateway token (token auth)") |
| .option( |
| "--gateway-token-ref-env <name>", |
| "Gateway token SecretRef env var name (token auth; e.g. OPENCLAW_GATEWAY_TOKEN)", |
| ) |
| .option("--gateway-password <password>", "Gateway password (password auth)") |
| .option("--remote-url <url>", "Remote Gateway WebSocket URL") |
| .option("--remote-token <token>", "Remote Gateway token (optional)") |
| .option("--tailscale <mode>", "Tailscale: off|serve|funnel") |
| .option("--tailscale-reset-on-exit", "Reset tailscale serve/funnel on exit") |
| .option("--install-daemon", "Install gateway service") |
| .option("--no-install-daemon", "Skip gateway service install") |
| .option("--skip-daemon", "Skip gateway service install") |
| .option("--daemon-runtime <runtime>", "Daemon runtime: node|bun") |
| .option("--skip-channels", "Skip channel setup") |
| .option("--skip-skills", "Skip skills setup") |
| .option("--skip-search", "Skip search provider setup") |
| .option("--skip-health", "Skip health check") |
| .option("--skip-ui", "Skip Control UI/TUI prompts") |
| .option("--node-manager <name>", "Node manager for skills: npm|pnpm|bun") |
| .option("--json", "Output JSON summary", false); |
|
|
| command.action(async (opts, commandRuntime) => { |
| await runCommandWithRuntime(defaultRuntime, async () => { |
| const installDaemon = resolveInstallDaemonFlag(commandRuntime, { |
| installDaemon: Boolean(opts.installDaemon), |
| }); |
| const gatewayPort = |
| typeof opts.gatewayPort === "string" ? Number.parseInt(opts.gatewayPort, 10) : undefined; |
| await onboardCommand( |
| { |
| workspace: opts.workspace as string | undefined, |
| nonInteractive: Boolean(opts.nonInteractive), |
| acceptRisk: Boolean(opts.acceptRisk), |
| flow: opts.flow as "quickstart" | "advanced" | "manual" | undefined, |
| mode: opts.mode as "local" | "remote" | undefined, |
| authChoice: opts.authChoice as AuthChoice | undefined, |
| tokenProvider: opts.tokenProvider as string | undefined, |
| token: opts.token as string | undefined, |
| tokenProfileId: opts.tokenProfileId as string | undefined, |
| tokenExpiresIn: opts.tokenExpiresIn as string | undefined, |
| secretInputMode: opts.secretInputMode as SecretInputMode | undefined, |
| anthropicApiKey: opts.anthropicApiKey as string | undefined, |
| openaiApiKey: opts.openaiApiKey as string | undefined, |
| mistralApiKey: opts.mistralApiKey as string | undefined, |
| openrouterApiKey: opts.openrouterApiKey as string | undefined, |
| kilocodeApiKey: opts.kilocodeApiKey as string | undefined, |
| aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined, |
| cloudflareAiGatewayAccountId: opts.cloudflareAiGatewayAccountId as string | undefined, |
| cloudflareAiGatewayGatewayId: opts.cloudflareAiGatewayGatewayId as string | undefined, |
| cloudflareAiGatewayApiKey: opts.cloudflareAiGatewayApiKey as string | undefined, |
| moonshotApiKey: opts.moonshotApiKey as string | undefined, |
| kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined, |
| geminiApiKey: opts.geminiApiKey as string | undefined, |
| zaiApiKey: opts.zaiApiKey as string | undefined, |
| xiaomiApiKey: opts.xiaomiApiKey as string | undefined, |
| qianfanApiKey: opts.qianfanApiKey as string | undefined, |
| modelstudioApiKeyCn: opts.modelstudioApiKeyCn as string | undefined, |
| modelstudioApiKey: opts.modelstudioApiKey as string | undefined, |
| minimaxApiKey: opts.minimaxApiKey as string | undefined, |
| syntheticApiKey: opts.syntheticApiKey as string | undefined, |
| veniceApiKey: opts.veniceApiKey as string | undefined, |
| togetherApiKey: opts.togetherApiKey as string | undefined, |
| huggingfaceApiKey: opts.huggingfaceApiKey as string | undefined, |
| opencodeZenApiKey: opts.opencodeZenApiKey as string | undefined, |
| opencodeGoApiKey: opts.opencodeGoApiKey as string | undefined, |
| xaiApiKey: opts.xaiApiKey as string | undefined, |
| litellmApiKey: opts.litellmApiKey as string | undefined, |
| volcengineApiKey: opts.volcengineApiKey as string | undefined, |
| byteplusApiKey: opts.byteplusApiKey as string | undefined, |
| customBaseUrl: opts.customBaseUrl as string | undefined, |
| customApiKey: opts.customApiKey as string | undefined, |
| customModelId: opts.customModelId as string | undefined, |
| customProviderId: opts.customProviderId as string | undefined, |
| customCompatibility: opts.customCompatibility as "openai" | "anthropic" | undefined, |
| gatewayPort: |
| typeof gatewayPort === "number" && Number.isFinite(gatewayPort) |
| ? gatewayPort |
| : undefined, |
| gatewayBind: opts.gatewayBind as GatewayBind | undefined, |
| gatewayAuth: opts.gatewayAuth as GatewayAuthChoice | undefined, |
| gatewayToken: opts.gatewayToken as string | undefined, |
| gatewayTokenRefEnv: opts.gatewayTokenRefEnv as string | undefined, |
| gatewayPassword: opts.gatewayPassword as string | undefined, |
| remoteUrl: opts.remoteUrl as string | undefined, |
| remoteToken: opts.remoteToken as string | undefined, |
| tailscale: opts.tailscale as TailscaleMode | undefined, |
| tailscaleResetOnExit: Boolean(opts.tailscaleResetOnExit), |
| reset: Boolean(opts.reset), |
| resetScope: opts.resetScope as ResetScope | undefined, |
| installDaemon, |
| daemonRuntime: opts.daemonRuntime as GatewayDaemonRuntime | undefined, |
| skipChannels: Boolean(opts.skipChannels), |
| skipSkills: Boolean(opts.skipSkills), |
| skipSearch: Boolean(opts.skipSearch), |
| skipHealth: Boolean(opts.skipHealth), |
| skipUi: Boolean(opts.skipUi), |
| nodeManager: opts.nodeManager as NodeManagerChoice | undefined, |
| json: Boolean(opts.json), |
| }, |
| defaultRuntime, |
| ); |
| }); |
| }); |
| } |
|
|