From 814e9a500e81b40ce504c4477a025f74d055ddba Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 22 Jan 2026 23:07:40 +0000 Subject: [PATCH] feat: add manual onboarding flow alias --- docs/cli/onboard.md | 4 ++ src/cli/program/register.onboard.ts | 4 +- src/commands/onboard-types.ts | 3 +- src/commands/onboard.ts | 4 +- src/wizard/onboarding.gateway-config.ts | 2 +- src/wizard/onboarding.ts | 89 +++++++++++++------------ 6 files changed, 59 insertions(+), 47 deletions(-) diff --git a/docs/cli/onboard.md b/docs/cli/onboard.md index 02593a19c..bd100c460 100644 --- a/docs/cli/onboard.md +++ b/docs/cli/onboard.md @@ -16,6 +16,10 @@ Related: ```bash clawdbot onboard clawdbot onboard --flow quickstart +clawdbot onboard --flow manual clawdbot onboard --mode remote --remote-url ws://gateway-host:18789 ``` +Flow notes: +- `quickstart`: minimal prompts, auto-generates a gateway token. +- `manual`: full prompts for port/bind/auth (alias of `advanced`). diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index f2f75d3cc..281464b6f 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -48,7 +48,7 @@ export function registerOnboardCommand(program: Command) { "Acknowledge that agents are powerful and full system access is risky (required for --non-interactive)", false, ) - .option("--flow ", "Wizard flow: quickstart|advanced") + .option("--flow ", "Wizard flow: quickstart|advanced|manual") .option("--mode ", "Wizard mode: local|remote") .option( "--auth-choice ", @@ -106,7 +106,7 @@ export function registerOnboardCommand(program: Command) { workspace: opts.workspace as string | undefined, nonInteractive: Boolean(opts.nonInteractive), acceptRisk: Boolean(opts.acceptRisk), - flow: opts.flow as "quickstart" | "advanced" | undefined, + 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, diff --git a/src/commands/onboard-types.ts b/src/commands/onboard-types.ts index 2a445053d..fad8fe483 100644 --- a/src/commands/onboard-types.ts +++ b/src/commands/onboard-types.ts @@ -42,7 +42,8 @@ export type ProviderChoice = ChannelChoice; export type OnboardOptions = { mode?: OnboardMode; - flow?: "quickstart" | "advanced"; + /** "manual" is an alias for "advanced". */ + flow?: "quickstart" | "advanced" | "manual"; workspace?: string; nonInteractive?: boolean; /** Required for non-interactive onboarding; skips the interactive risk prompt when true. */ diff --git a/src/commands/onboard.ts b/src/commands/onboard.ts index 97e7bc3c7..d8618a871 100644 --- a/src/commands/onboard.ts +++ b/src/commands/onboard.ts @@ -12,7 +12,9 @@ import type { OnboardOptions } from "./onboard-types.js"; export async function onboardCommand(opts: OnboardOptions, runtime: RuntimeEnv = defaultRuntime) { assertSupportedRuntime(runtime); const authChoice = opts.authChoice === "oauth" ? ("setup-token" as const) : opts.authChoice; - const normalizedOpts = authChoice === opts.authChoice ? opts : { ...opts, authChoice }; + const flow = opts.flow === "manual" ? ("advanced" as const) : opts.flow; + const normalizedOpts = + authChoice === opts.authChoice && flow === opts.flow ? opts : { ...opts, authChoice, flow }; if (normalizedOpts.nonInteractive && normalizedOpts.acceptRisk !== true) { runtime.error( diff --git a/src/wizard/onboarding.gateway-config.ts b/src/wizard/onboarding.gateway-config.ts index 4974615eb..e8163cbad 100644 --- a/src/wizard/onboarding.gateway-config.ts +++ b/src/wizard/onboarding.gateway-config.ts @@ -191,7 +191,7 @@ export async function configureGatewayForOnboarding( const tokenInput = await prompter.text({ message: "Gateway token (blank to generate)", placeholder: "Needed for multi-machine or non-loopback access", - initialValue: quickstartGateway.token ?? randomToken(), + initialValue: quickstartGateway.token ?? "", }); gatewayToken = String(tokenInput).trim() || randomToken(); } diff --git a/src/wizard/onboarding.ts b/src/wizard/onboarding.ts index 0ec2a7fc0..d6be230a2 100644 --- a/src/wizard/onboarding.ts +++ b/src/wizard/onboarding.ts @@ -82,10 +82,9 @@ export async function runOnboardingWizard( const snapshot = await readConfigFileSnapshot(); let baseConfig: ClawdbotConfig = snapshot.valid ? snapshot.config : {}; - if (snapshot.exists) { - const title = snapshot.valid ? "Existing config detected" : "Invalid config"; - await prompter.note(summarizeExistingConfig(baseConfig), title); - if (!snapshot.valid && snapshot.issues.length > 0) { + if (snapshot.exists && !snapshot.valid) { + await prompter.note(summarizeExistingConfig(baseConfig), "Invalid config"); + if (snapshot.issues.length > 0) { await prompter.note( [ ...snapshot.issues.map((iss) => `- ${iss.path}: ${iss.message}`), @@ -95,14 +94,51 @@ export async function runOnboardingWizard( "Config issues", ); } + await prompter.outro( + `Config invalid. Run \`${formatCliCommand("clawdbot doctor")}\` to repair it, then re-run onboarding.`, + ); + runtime.exit(1); + return; + } - if (!snapshot.valid) { - await prompter.outro( - `Config invalid. Run \`${formatCliCommand("clawdbot doctor")}\` to repair it, then re-run onboarding.`, - ); - runtime.exit(1); - return; - } + const quickstartHint = `Configure details later via ${formatCliCommand("clawdbot configure")}.`; + const manualHint = "Configure port, network, Tailscale, and auth options."; + const explicitFlowRaw = opts.flow?.trim(); + const normalizedExplicitFlow = explicitFlowRaw === "manual" ? "advanced" : explicitFlowRaw; + if ( + normalizedExplicitFlow && + normalizedExplicitFlow !== "quickstart" && + normalizedExplicitFlow !== "advanced" + ) { + runtime.error("Invalid --flow (use quickstart, manual, or advanced)."); + runtime.exit(1); + return; + } + const explicitFlow: WizardFlow | undefined = + normalizedExplicitFlow === "quickstart" || normalizedExplicitFlow === "advanced" + ? normalizedExplicitFlow + : undefined; + let flow: WizardFlow = + explicitFlow ?? + ((await prompter.select({ + message: "Onboarding mode", + options: [ + { value: "quickstart", label: "QuickStart", hint: quickstartHint }, + { value: "advanced", label: "Manual", hint: manualHint }, + ], + initialValue: "quickstart", + })) as "quickstart" | "advanced"); + + if (opts.mode === "remote" && flow === "quickstart") { + await prompter.note( + "QuickStart only supports local gateways. Switching to Manual mode.", + "QuickStart", + ); + flow = "advanced"; + } + + if (snapshot.exists) { + await prompter.note(summarizeExistingConfig(baseConfig), "Existing config detected"); const action = (await prompter.select({ message: "Config handling", @@ -134,37 +170,6 @@ export async function runOnboardingWizard( } } - const quickstartHint = `Configure details later via ${formatCliCommand("clawdbot configure")}.`; - const advancedHint = "Configure port, network, Tailscale, and auth options."; - const explicitFlowRaw = opts.flow?.trim(); - if (explicitFlowRaw && explicitFlowRaw !== "quickstart" && explicitFlowRaw !== "advanced") { - runtime.error("Invalid --flow (use quickstart or advanced)."); - runtime.exit(1); - return; - } - const explicitFlow: WizardFlow | undefined = - explicitFlowRaw === "quickstart" || explicitFlowRaw === "advanced" - ? explicitFlowRaw - : undefined; - let flow: WizardFlow = - explicitFlow ?? - ((await prompter.select({ - message: "Onboarding mode", - options: [ - { value: "quickstart", label: "QuickStart", hint: quickstartHint }, - { value: "advanced", label: "Advanced", hint: advancedHint }, - ], - initialValue: "quickstart", - })) as "quickstart" | "advanced"); - - if (opts.mode === "remote" && flow === "quickstart") { - await prompter.note( - "QuickStart only supports local gateways. Switching to Advanced mode.", - "QuickStart", - ); - flow = "advanced"; - } - const quickstartGateway: QuickstartGatewayDefaults = (() => { const hasExisting = typeof baseConfig.gateway?.port === "number" ||