fix: streamline configure section flow

This commit is contained in:
Peter Steinberger
2026-01-12 07:43:01 +00:00
parent 414ad72d17
commit 018f7aa4df

View File

@@ -151,40 +151,27 @@ const CONFIGURE_SECTION_OPTIONS: {
}, },
]; ];
async function promptConfigureSections( type ConfigureSectionChoice = WizardSection | "__continue";
async function promptConfigureSection(
runtime: RuntimeEnv, runtime: RuntimeEnv,
): Promise<WizardSection[]> { hasSelection: boolean,
const selected: WizardSection[] = []; ): Promise<ConfigureSectionChoice> {
const continueValue = "__continue"; return guardCancel(
await select<ConfigureSectionChoice>({
while (true) { message: "Select sections to configure",
const choice = guardCancel( options: [
await select<string>({ ...CONFIGURE_SECTION_OPTIONS,
message: "Select sections to configure", {
options: [ value: "__continue",
...CONFIGURE_SECTION_OPTIONS, label: "Continue",
{ hint: hasSelection ? "Done" : "Skip for now",
value: continueValue, },
label: "Continue", ],
hint: selected.length === 0 ? "Skip for now" : "Run selected", initialValue: CONFIGURE_SECTION_OPTIONS[0]?.value,
}, }),
], runtime,
initialValue: CONFIGURE_SECTION_OPTIONS[0]?.value, );
}),
runtime,
);
if (choice === continueValue) {
break;
}
const section = choice as WizardSection;
if (!selected.includes(section)) {
selected.push(section);
}
}
return selected;
} }
async function promptGatewayConfig( async function promptGatewayConfig(
@@ -658,136 +645,271 @@ export async function runConfigureWizard(
return; return;
} }
const selected = opts.sections
? opts.sections
: await promptConfigureSections(runtime);
if (!selected || selected.length === 0) {
outro("No changes selected.");
return;
}
let nextConfig = { ...baseConfig }; let nextConfig = { ...baseConfig };
let workspaceDir = let workspaceDir =
nextConfig.agents?.defaults?.workspace ?? nextConfig.agents?.defaults?.workspace ??
baseConfig.agents?.defaults?.workspace ?? baseConfig.agents?.defaults?.workspace ??
DEFAULT_WORKSPACE; DEFAULT_WORKSPACE;
let gatewayPort = resolveGatewayPort(baseConfig); let gatewayPort = resolveGatewayPort(baseConfig);
let gatewayToken: string | undefined; let gatewayToken: string | undefined =
nextConfig.gateway?.auth?.token ??
baseConfig.gateway?.auth?.token ??
process.env.CLAWDBOT_GATEWAY_TOKEN;
if (selected.includes("workspace")) { const persistConfig = async () => {
const workspaceInput = guardCancel( nextConfig = applyWizardMetadata(nextConfig, {
await text({ command: opts.command,
message: "Workspace directory", mode,
initialValue: workspaceDir, });
}), await writeConfigFile(nextConfig);
runtime, runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
); };
workspaceDir = resolveUserPath(
String(workspaceInput ?? "").trim() || DEFAULT_WORKSPACE,
);
nextConfig = {
...nextConfig,
agents: {
...nextConfig.agents,
defaults: {
...nextConfig.agents?.defaults,
workspace: workspaceDir,
},
},
};
await ensureWorkspaceAndSessions(workspaceDir, runtime);
}
if (selected.includes("model")) { if (opts.sections) {
nextConfig = await promptAuthConfig(nextConfig, runtime, prompter); const selected = opts.sections;
} if (!selected || selected.length === 0) {
outro("No changes selected.");
if (selected.includes("gateway")) { return;
const gateway = await promptGatewayConfig(nextConfig, runtime);
nextConfig = gateway.config;
gatewayPort = gateway.port;
gatewayToken = gateway.token;
}
if (selected.includes("providers")) {
const providerMode = guardCancel(
await select({
message: "Providers",
options: [
{
value: "configure",
label: "Configure/link",
hint: "Add/update providers; disable unselected accounts",
},
{
value: "remove",
label: "Remove provider config",
hint: "Delete provider tokens/settings from clawdbot.json",
},
],
initialValue: "configure",
}),
runtime,
) as ProvidersWizardMode;
if (providerMode === "configure") {
nextConfig = await setupProviders(nextConfig, runtime, prompter, {
allowDisable: true,
allowSignalInstall: true,
});
} else {
nextConfig = await removeProviderConfigWizard(nextConfig, runtime);
} }
}
if (selected.includes("skills")) { if (selected.includes("workspace")) {
const wsDir = resolveUserPath(workspaceDir); const workspaceInput = guardCancel(
nextConfig = await setupSkills(nextConfig, wsDir, runtime, prompter);
}
nextConfig = applyWizardMetadata(nextConfig, {
command: opts.command,
mode,
});
await writeConfigFile(nextConfig);
runtime.log(`Updated ${CONFIG_PATH_CLAWDBOT}`);
if (selected.includes("daemon")) {
if (!selected.includes("gateway")) {
const portInput = guardCancel(
await text({ await text({
message: "Gateway port for daemon install", message: "Workspace directory",
initialValue: String(gatewayPort), initialValue: workspaceDir,
validate: (value) =>
Number.isFinite(Number(value)) ? undefined : "Invalid port",
}), }),
runtime, runtime,
); );
gatewayPort = Number.parseInt(String(portInput), 10); workspaceDir = resolveUserPath(
String(workspaceInput ?? "").trim() || DEFAULT_WORKSPACE,
);
nextConfig = {
...nextConfig,
agents: {
...nextConfig.agents,
defaults: {
...nextConfig.agents?.defaults,
workspace: workspaceDir,
},
},
};
await ensureWorkspaceAndSessions(workspaceDir, runtime);
} }
await maybeInstallDaemon({ if (selected.includes("model")) {
runtime, nextConfig = await promptAuthConfig(nextConfig, runtime, prompter);
port: gatewayPort, }
gatewayToken,
});
}
if (selected.includes("health")) { if (selected.includes("gateway")) {
await sleep(1000); const gateway = await promptGatewayConfig(nextConfig, runtime);
try { nextConfig = gateway.config;
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime); gatewayPort = gateway.port;
} catch (err) { gatewayToken = gateway.token;
runtime.error(formatHealthCheckFailure(err)); }
note(
[ if (selected.includes("providers")) {
"Docs:", const providerMode = guardCancel(
"https://docs.clawd.bot/gateway/health", await select({
"https://docs.clawd.bot/gateway/troubleshooting", message: "Providers",
].join("\n"), options: [
"Health check help", {
); value: "configure",
label: "Configure/link",
hint: "Add/update providers; disable unselected accounts",
},
{
value: "remove",
label: "Remove provider config",
hint: "Delete provider tokens/settings from clawdbot.json",
},
],
initialValue: "configure",
}),
runtime,
) as ProvidersWizardMode;
if (providerMode === "configure") {
nextConfig = await setupProviders(nextConfig, runtime, prompter, {
allowDisable: true,
allowSignalInstall: true,
});
} else {
nextConfig = await removeProviderConfigWizard(nextConfig, runtime);
}
}
if (selected.includes("skills")) {
const wsDir = resolveUserPath(workspaceDir);
nextConfig = await setupSkills(nextConfig, wsDir, runtime, prompter);
}
await persistConfig();
if (selected.includes("daemon")) {
if (!selected.includes("gateway")) {
const portInput = guardCancel(
await text({
message: "Gateway port for daemon install",
initialValue: String(gatewayPort),
validate: (value) =>
Number.isFinite(Number(value)) ? undefined : "Invalid port",
}),
runtime,
);
gatewayPort = Number.parseInt(String(portInput), 10);
}
await maybeInstallDaemon({
runtime,
port: gatewayPort,
gatewayToken,
});
}
if (selected.includes("health")) {
await sleep(1000);
try {
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
} catch (err) {
runtime.error(formatHealthCheckFailure(err));
note(
[
"Docs:",
"https://docs.clawd.bot/gateway/health",
"https://docs.clawd.bot/gateway/troubleshooting",
].join("\n"),
"Health check help",
);
}
}
} else {
let ranSection = false;
let didConfigureGateway = false;
while (true) {
const choice = await promptConfigureSection(runtime, ranSection);
if (choice === "__continue") break;
ranSection = true;
if (choice === "workspace") {
const workspaceInput = guardCancel(
await text({
message: "Workspace directory",
initialValue: workspaceDir,
}),
runtime,
);
workspaceDir = resolveUserPath(
String(workspaceInput ?? "").trim() || DEFAULT_WORKSPACE,
);
nextConfig = {
...nextConfig,
agents: {
...nextConfig.agents,
defaults: {
...nextConfig.agents?.defaults,
workspace: workspaceDir,
},
},
};
await ensureWorkspaceAndSessions(workspaceDir, runtime);
await persistConfig();
}
if (choice === "model") {
nextConfig = await promptAuthConfig(nextConfig, runtime, prompter);
await persistConfig();
}
if (choice === "gateway") {
const gateway = await promptGatewayConfig(nextConfig, runtime);
nextConfig = gateway.config;
gatewayPort = gateway.port;
gatewayToken = gateway.token;
didConfigureGateway = true;
await persistConfig();
}
if (choice === "providers") {
const providerMode = guardCancel(
await select({
message: "Providers",
options: [
{
value: "configure",
label: "Configure/link",
hint: "Add/update providers; disable unselected accounts",
},
{
value: "remove",
label: "Remove provider config",
hint: "Delete provider tokens/settings from clawdbot.json",
},
],
initialValue: "configure",
}),
runtime,
) as ProvidersWizardMode;
if (providerMode === "configure") {
nextConfig = await setupProviders(nextConfig, runtime, prompter, {
allowDisable: true,
allowSignalInstall: true,
});
} else {
nextConfig = await removeProviderConfigWizard(nextConfig, runtime);
}
await persistConfig();
}
if (choice === "skills") {
const wsDir = resolveUserPath(workspaceDir);
nextConfig = await setupSkills(nextConfig, wsDir, runtime, prompter);
await persistConfig();
}
if (choice === "daemon") {
if (!didConfigureGateway) {
const portInput = guardCancel(
await text({
message: "Gateway port for daemon install",
initialValue: String(gatewayPort),
validate: (value) =>
Number.isFinite(Number(value)) ? undefined : "Invalid port",
}),
runtime,
);
gatewayPort = Number.parseInt(String(portInput), 10);
}
await maybeInstallDaemon({
runtime,
port: gatewayPort,
gatewayToken,
});
}
if (choice === "health") {
await sleep(1000);
try {
await healthCommand({ json: false, timeoutMs: 10_000 }, runtime);
} catch (err) {
runtime.error(formatHealthCheckFailure(err));
note(
[
"Docs:",
"https://docs.clawd.bot/gateway/health",
"https://docs.clawd.bot/gateway/troubleshooting",
].join("\n"),
"Health check help",
);
}
}
}
if (!ranSection) {
outro("No changes selected.");
return;
} }
} }