diff --git a/src/cli/browser-cli-actions-observe.ts b/src/cli/browser-cli-actions-observe.ts index cb265a884..c463bde37 100644 --- a/src/cli/browser-cli-actions-observe.ts +++ b/src/cli/browser-cli-actions-observe.ts @@ -8,6 +8,14 @@ import { import { danger } from "../globals.js"; import { defaultRuntime } from "../runtime.js"; import type { BrowserParentOpts } from "./browser-cli-shared.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; + +function runBrowserObserve(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + defaultRuntime.error(danger(String(err))); + defaultRuntime.exit(1); + }); +} export function registerBrowserActionObserveCommands( browser: Command, @@ -22,7 +30,7 @@ export function registerBrowserActionObserveCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserObserve(async () => { const result = await browserConsoleMessages(baseUrl, { level: opts.level?.trim() || undefined, targetId: opts.targetId?.trim() || undefined, @@ -33,10 +41,7 @@ export function registerBrowserActionObserveCommands( return; } defaultRuntime.log(JSON.stringify(result.messages, null, 2)); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -47,7 +52,7 @@ export function registerBrowserActionObserveCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserObserve(async () => { const result = await browserPdfSave(baseUrl, { targetId: opts.targetId?.trim() || undefined, profile, @@ -57,10 +62,7 @@ export function registerBrowserActionObserveCommands( return; } defaultRuntime.log(`PDF: ${result.path}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -80,7 +82,7 @@ export function registerBrowserActionObserveCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserObserve(async () => { const result = await browserResponseBody(baseUrl, { url, targetId: opts.targetId?.trim() || undefined, @@ -93,9 +95,6 @@ export function registerBrowserActionObserveCommands( return; } defaultRuntime.log(result.response.body); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/browser-cli-debug.ts b/src/cli/browser-cli-debug.ts index c25d96b62..68bdb53b1 100644 --- a/src/cli/browser-cli-debug.ts +++ b/src/cli/browser-cli-debug.ts @@ -11,6 +11,14 @@ import { import { danger } from "../globals.js"; import { defaultRuntime } from "../runtime.js"; import type { BrowserParentOpts } from "./browser-cli-shared.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; + +function runBrowserDebug(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + defaultRuntime.error(danger(String(err))); + defaultRuntime.exit(1); + }); +} export function registerBrowserDebugCommands( browser: Command, @@ -25,7 +33,7 @@ export function registerBrowserDebugCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserDebug(async () => { const result = await browserHighlight(baseUrl, { ref: ref.trim(), targetId: opts.targetId?.trim() || undefined, @@ -36,10 +44,7 @@ export function registerBrowserDebugCommands( return; } defaultRuntime.log(`highlighted ${ref.trim()}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -51,7 +56,7 @@ export function registerBrowserDebugCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserDebug(async () => { const result = await browserPageErrors(baseUrl, { targetId: opts.targetId?.trim() || undefined, clear: Boolean(opts.clear), @@ -70,10 +75,7 @@ export function registerBrowserDebugCommands( .map((e) => `${e.timestamp} ${e.name ? `${e.name}: ` : ""}${e.message}`) .join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -86,7 +88,7 @@ export function registerBrowserDebugCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserDebug(async () => { const result = await browserRequests(baseUrl, { targetId: opts.targetId?.trim() || undefined, filter: opts.filter?.trim() || undefined, @@ -111,10 +113,7 @@ export function registerBrowserDebugCommands( }) .join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); const trace = browser.command("trace").description("Record a Playwright trace"); @@ -130,7 +129,7 @@ export function registerBrowserDebugCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserDebug(async () => { const result = await browserTraceStart(baseUrl, { targetId: opts.targetId?.trim() || undefined, screenshots: Boolean(opts.screenshots), @@ -143,10 +142,7 @@ export function registerBrowserDebugCommands( return; } defaultRuntime.log("trace started"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); trace @@ -158,7 +154,7 @@ export function registerBrowserDebugCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserDebug(async () => { const result = await browserTraceStop(baseUrl, { targetId: opts.targetId?.trim() || undefined, path: opts.out?.trim() || undefined, @@ -169,9 +165,6 @@ export function registerBrowserDebugCommands( return; } defaultRuntime.log(`TRACE:${result.path}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/browser-cli-manage.ts b/src/cli/browser-cli-manage.ts index 5b17cef03..9caa47cdf 100644 --- a/src/cli/browser-cli-manage.ts +++ b/src/cli/browser-cli-manage.ts @@ -19,6 +19,14 @@ import { browserAct } from "../browser/client-actions-core.js"; import { danger, info } from "../globals.js"; import { defaultRuntime } from "../runtime.js"; import type { BrowserParentOpts } from "./browser-cli-shared.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; + +function runBrowserCommand(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + defaultRuntime.error(danger(String(err))); + defaultRuntime.exit(1); + }); +} export function registerBrowserManageCommands( browser: Command, @@ -30,7 +38,7 @@ export function registerBrowserManageCommands( .action(async (_opts, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); - try { + await runBrowserCommand(async () => { const status = await browserStatus(baseUrl, { profile: parent?.browserProfile, }); @@ -53,10 +61,7 @@ export function registerBrowserManageCommands( ...(status.detectError ? [`detectError: ${status.detectError}`] : []), ].join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -66,7 +71,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { await browserStart(baseUrl, { profile }); const status = await browserStatus(baseUrl, { profile }); if (parent?.json) { @@ -75,10 +80,7 @@ export function registerBrowserManageCommands( } const name = status.profile ?? "clawd"; defaultRuntime.log(info(`🦞 browser [${name}] running: ${status.running}`)); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -88,7 +90,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { await browserStop(baseUrl, { profile }); const status = await browserStatus(baseUrl, { profile }); if (parent?.json) { @@ -97,10 +99,7 @@ export function registerBrowserManageCommands( } const name = status.profile ?? "clawd"; defaultRuntime.log(info(`🦞 browser [${name}] running: ${status.running}`)); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -110,7 +109,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserResetProfile(baseUrl, { profile }); if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); @@ -122,10 +121,7 @@ export function registerBrowserManageCommands( } const dest = result.to ?? result.from; defaultRuntime.log(info(`🦞 browser profile moved to Trash (${dest})`)); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -135,7 +131,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const tabs = await browserTabs(baseUrl, { profile }); if (parent?.json) { defaultRuntime.log(JSON.stringify({ tabs }, null, 2)); @@ -152,10 +148,7 @@ export function registerBrowserManageCommands( ) .join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); const tab = browser @@ -165,7 +158,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = (await browserTabAction(baseUrl, { action: "list", profile, @@ -186,10 +179,7 @@ export function registerBrowserManageCommands( ) .join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); tab @@ -199,7 +189,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserTabAction(baseUrl, { action: "new", profile, @@ -209,10 +199,7 @@ export function registerBrowserManageCommands( return; } defaultRuntime.log("opened new tab"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); tab @@ -228,7 +215,7 @@ export function registerBrowserManageCommands( defaultRuntime.exit(1); return; } - try { + await runBrowserCommand(async () => { const result = await browserTabAction(baseUrl, { action: "select", index: Math.floor(index) - 1, @@ -239,10 +226,7 @@ export function registerBrowserManageCommands( return; } defaultRuntime.log(`selected tab ${Math.floor(index)}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); tab @@ -260,7 +244,7 @@ export function registerBrowserManageCommands( defaultRuntime.exit(1); return; } - try { + await runBrowserCommand(async () => { const result = await browserTabAction(baseUrl, { action: "close", index: idx, @@ -271,10 +255,7 @@ export function registerBrowserManageCommands( return; } defaultRuntime.log("closed tab"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -285,17 +266,14 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const tab = await browserOpenTab(baseUrl, url, { profile }); if (parent?.json) { defaultRuntime.log(JSON.stringify(tab, null, 2)); return; } defaultRuntime.log(`opened: ${tab.url}\nid: ${tab.targetId}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -306,17 +284,14 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { await browserFocusTab(baseUrl, targetId, { profile }); if (parent?.json) { defaultRuntime.log(JSON.stringify({ ok: true }, null, 2)); return; } defaultRuntime.log(`focused tab ${targetId}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -327,7 +302,7 @@ export function registerBrowserManageCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { if (targetId?.trim()) { await browserCloseTab(baseUrl, targetId.trim(), { profile }); } else { @@ -338,10 +313,7 @@ export function registerBrowserManageCommands( return; } defaultRuntime.log("closed tab"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); // Profile management commands @@ -351,7 +323,7 @@ export function registerBrowserManageCommands( .action(async (_opts, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); - try { + await runBrowserCommand(async () => { const profiles = await browserProfiles(baseUrl); if (parent?.json) { defaultRuntime.log(JSON.stringify({ profiles }, null, 2)); @@ -373,10 +345,7 @@ export function registerBrowserManageCommands( }) .join("\n"), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); browser @@ -390,7 +359,7 @@ export function registerBrowserManageCommands( async (opts: { name: string; color?: string; cdpUrl?: string; driver?: string }, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); - try { + await runBrowserCommand(async () => { const result = await browserCreateProfile(baseUrl, { name: opts.name, color: opts.color, @@ -409,10 +378,7 @@ export function registerBrowserManageCommands( }`, ), ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }, ); @@ -423,7 +389,7 @@ export function registerBrowserManageCommands( .action(async (opts: { name: string }, cmd) => { const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); - try { + await runBrowserCommand(async () => { const result = await browserDeleteProfile(baseUrl, opts.name); if (parent?.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); @@ -433,9 +399,6 @@ export function registerBrowserManageCommands( ? `🦞 Deleted profile "${result.profile}" (user data removed)` : `🦞 Deleted profile "${result.profile}" (no user data found)`; defaultRuntime.log(info(msg)); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/browser-cli-state.ts b/src/cli/browser-cli-state.ts index 905500286..ea98901e1 100644 --- a/src/cli/browser-cli-state.ts +++ b/src/cli/browser-cli-state.ts @@ -17,12 +17,20 @@ import { defaultRuntime } from "../runtime.js"; import { parseBooleanValue } from "../utils/boolean.js"; import type { BrowserParentOpts } from "./browser-cli-shared.js"; import { registerBrowserCookiesAndStorageCommands } from "./browser-cli-state.cookies-storage.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; function parseOnOff(raw: string): boolean | null { const parsed = parseBooleanValue(raw); return parsed === undefined ? null : parsed; } +function runBrowserCommand(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + defaultRuntime.error(danger(String(err))); + defaultRuntime.exit(1); + }); +} + export function registerBrowserStateCommands( browser: Command, parentOpts: (cmd: Command) => BrowserParentOpts, @@ -46,7 +54,7 @@ export function registerBrowserStateCommands( defaultRuntime.exit(1); return; } - try { + await runBrowserCommand(async () => { const result = await browserAct( baseUrl, { @@ -62,10 +70,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`viewport set: ${width}x${height}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -83,7 +88,7 @@ export function registerBrowserStateCommands( defaultRuntime.exit(1); return; } - try { + await runBrowserCommand(async () => { const result = await browserSetOffline(baseUrl, { offline, targetId: opts.targetId?.trim() || undefined, @@ -94,10 +99,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`offline: ${offline}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -109,7 +111,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const parsed = JSON.parse(String(opts.json)) as unknown; if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { throw new Error("headers json must be an object"); @@ -128,10 +130,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log("headers set"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -145,7 +144,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserSetHttpCredentials(baseUrl, { username: username?.trim() || undefined, password, @@ -158,10 +157,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(opts.clear ? "credentials cleared" : "credentials set"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -177,7 +173,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserSetGeolocation(baseUrl, { latitude: Number.isFinite(latitude) ? latitude : undefined, longitude: Number.isFinite(longitude) ? longitude : undefined, @@ -192,10 +188,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(opts.clear ? "geolocation cleared" : "geolocation set"); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -215,7 +208,7 @@ export function registerBrowserStateCommands( defaultRuntime.exit(1); return; } - try { + await runBrowserCommand(async () => { const result = await browserSetMedia(baseUrl, { colorScheme, targetId: opts.targetId?.trim() || undefined, @@ -226,10 +219,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`media colorScheme: ${colorScheme}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -241,7 +231,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserSetTimezone(baseUrl, { timezoneId, targetId: opts.targetId?.trim() || undefined, @@ -252,10 +242,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`timezone: ${timezoneId}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -267,7 +254,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserSetLocale(baseUrl, { locale, targetId: opts.targetId?.trim() || undefined, @@ -278,10 +265,7 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`locale: ${locale}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); set @@ -293,7 +277,7 @@ export function registerBrowserStateCommands( const parent = parentOpts(cmd); const baseUrl = resolveBrowserControlUrl(parent?.url); const profile = parent?.browserProfile; - try { + await runBrowserCommand(async () => { const result = await browserSetDevice(baseUrl, { name, targetId: opts.targetId?.trim() || undefined, @@ -304,9 +288,6 @@ export function registerBrowserStateCommands( return; } defaultRuntime.log(`device: ${name}`); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/channels-cli.ts b/src/cli/channels-cli.ts index 14f85b52a..ee56a4a0a 100644 --- a/src/cli/channels-cli.ts +++ b/src/cli/channels-cli.ts @@ -14,6 +14,7 @@ import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; import { runChannelLogin, runChannelLogout } from "./channel-auth.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; import { hasExplicitOptions } from "./command-options.js"; const optionNamesAdd = [ @@ -44,6 +45,17 @@ const optionNamesAdd = [ const optionNamesRemove = ["channel", "account", "delete"] as const; +function runChannelsCommand(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action); +} + +function runChannelsCommandWithDanger(action: () => Promise, label: string) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + defaultRuntime.error(danger(`${label}: ${String(err)}`)); + defaultRuntime.exit(1); + }); +} + export function registerChannelsCli(program: Command) { const channelNames = listChannelPlugins() .map((plugin) => plugin.id) @@ -66,12 +78,9 @@ export function registerChannelsCli(program: Command) { .option("--no-usage", "Skip model provider usage/quota snapshots") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runChannelsCommand(async () => { await channelsListCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -81,12 +90,9 @@ export function registerChannelsCli(program: Command) { .option("--timeout ", "Timeout in ms", "10000") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runChannelsCommand(async () => { await channelsStatusCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -98,12 +104,9 @@ export function registerChannelsCli(program: Command) { .option("--timeout ", "Timeout in ms", "10000") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runChannelsCommand(async () => { await channelsCapabilitiesCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -115,7 +118,7 @@ export function registerChannelsCli(program: Command) { .option("--kind ", "Target kind (auto|user|group)", "auto") .option("--json", "Output JSON", false) .action(async (entries, opts) => { - try { + await runChannelsCommand(async () => { await channelsResolveCommand( { channel: opts.channel as string | undefined, @@ -126,10 +129,7 @@ export function registerChannelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -139,12 +139,9 @@ export function registerChannelsCli(program: Command) { .option("--lines ", "Number of lines (default: 200)", "200") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runChannelsCommand(async () => { await channelsLogsCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -174,13 +171,10 @@ export function registerChannelsCli(program: Command) { .option("--initial-sync-limit ", "Matrix initial sync limit") .option("--use-env", "Use env token (default account only)", false) .action(async (opts, command) => { - try { + await runChannelsCommand(async () => { const hasFlags = hasExplicitOptions(command, optionNamesAdd); await channelsAddCommand(opts, defaultRuntime, { hasFlags }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -190,13 +184,10 @@ export function registerChannelsCli(program: Command) { .option("--account ", "Account id (default when omitted)") .option("--delete", "Delete config entries (no prompt)", false) .action(async (opts, command) => { - try { + await runChannelsCommand(async () => { const hasFlags = hasExplicitOptions(command, optionNamesRemove); await channelsRemoveCommand(opts, defaultRuntime, { hasFlags }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); channels @@ -206,7 +197,8 @@ export function registerChannelsCli(program: Command) { .option("--account ", "Account id (accountId)") .option("--verbose", "Verbose connection logs", false) .action(async (opts) => { - try { + await runChannelsCommandWithDanger( + async () => { await runChannelLogin( { channel: opts.channel as string | undefined, @@ -215,10 +207,9 @@ export function registerChannelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(danger(`Channel login failed: ${String(err)}`)); - defaultRuntime.exit(1); - } + }, + "Channel login failed", + ); }); channels @@ -227,7 +218,8 @@ export function registerChannelsCli(program: Command) { .option("--channel ", "Channel alias (default: whatsapp)") .option("--account ", "Account id (accountId)") .action(async (opts) => { - try { + await runChannelsCommandWithDanger( + async () => { await runChannelLogout( { channel: opts.channel as string | undefined, @@ -235,9 +227,8 @@ export function registerChannelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(danger(`Channel logout failed: ${String(err)}`)); - defaultRuntime.exit(1); - } + }, + "Channel logout failed", + ); }); } diff --git a/src/cli/cli-utils.ts b/src/cli/cli-utils.ts index 1b9e28a48..2aae659f8 100644 --- a/src/cli/cli-utils.ts +++ b/src/cli/cli-utils.ts @@ -29,3 +29,20 @@ export async function withManager(params: { } } } + +export async function runCommandWithRuntime( + runtime: { error: (message: string) => void; exit: (code: number) => void }, + action: () => Promise, + onError?: (error: unknown) => void, +): Promise { + try { + await action(); + } catch (err) { + if (onError) { + onError(err); + return; + } + runtime.error(String(err)); + runtime.exit(1); + } +} diff --git a/src/cli/docs-cli.ts b/src/cli/docs-cli.ts index b69204137..8078b8afe 100644 --- a/src/cli/docs-cli.ts +++ b/src/cli/docs-cli.ts @@ -4,6 +4,7 @@ import { docsSearchCommand } from "../commands/docs.js"; import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; export function registerDocsCli(program: Command) { program @@ -15,11 +16,8 @@ export function registerDocsCli(program: Command) { () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/docs", "docs.clawd.bot/cli/docs")}\n`, ) .action(async (queryParts: string[]) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { await docsSearchCommand(queryParts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/gateway-cli/register.ts b/src/cli/gateway-cli/register.ts index 0a4361140..5cfe71cd8 100644 --- a/src/cli/gateway-cli/register.ts +++ b/src/cli/gateway-cli/register.ts @@ -7,6 +7,7 @@ import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { colorize, isRich, theme } from "../../terminal/theme.js"; import { withProgress } from "../progress.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; import { callGatewayCli, gatewayCallOpts } from "./call.js"; import type { GatewayDiscoverOpts } from "./discover.js"; import { @@ -41,6 +42,14 @@ function styleHealthChannelLine(line: string, rich: boolean): string { return line; } +function runGatewayCommand(action: () => Promise, label?: string) { + return runCommandWithRuntime(defaultRuntime, action, (err) => { + const message = String(err); + defaultRuntime.error(label ? `${label}: ${message}` : message); + defaultRuntime.exit(1); + }); +} + export function registerGatewayCli(program: Command) { const gateway = addGatewayRunCommand( program @@ -67,7 +76,7 @@ export function registerGatewayCli(program: Command) { .argument("", "Method name (health/status/system-presence/cron.*)") .option("--params ", "JSON object string for params", "{}") .action(async (method, opts) => { - try { + await runGatewayCommand(async () => { const params = JSON.parse(String(opts.params ?? "{}")); const result = await callGatewayCli(method, opts, params); if (opts.json) { @@ -79,10 +88,7 @@ export function registerGatewayCli(program: Command) { `${colorize(rich, theme.heading, "Gateway call")}: ${colorize(rich, theme.muted, String(method))}`, ); defaultRuntime.log(JSON.stringify(result, null, 2)); - } catch (err) { - defaultRuntime.error(`Gateway call failed: ${String(err)}`); - defaultRuntime.exit(1); - } + }, "Gateway call failed"); }), ); @@ -91,7 +97,7 @@ export function registerGatewayCli(program: Command) { .command("health") .description("Fetch Gateway health") .action(async (opts) => { - try { + await runGatewayCommand(async () => { const result = await callGatewayCli("health", opts); if (opts.json) { defaultRuntime.log(JSON.stringify(result, null, 2)); @@ -110,10 +116,7 @@ export function registerGatewayCli(program: Command) { defaultRuntime.log(styleHealthChannelLine(line, rich)); } } - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }), ); @@ -129,12 +132,9 @@ export function registerGatewayCli(program: Command) { .option("--timeout ", "Overall probe budget in ms", "3000") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runGatewayCommand(async () => { await gatewayStatusCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); gateway @@ -145,7 +145,7 @@ export function registerGatewayCli(program: Command) { .option("--timeout ", "Per-command timeout in ms", "2000") .option("--json", "Output JSON", false) .action(async (opts: GatewayDiscoverOpts) => { - try { + await runGatewayCommand(async () => { const timeoutMs = parseDiscoverTimeoutMs(opts.timeout, 2000); const beacons = await withProgress( { @@ -200,9 +200,6 @@ export function registerGatewayCli(program: Command) { defaultRuntime.log(line); } } - } catch (err) { - defaultRuntime.error(`gateway discover failed: ${String(err)}`); - defaultRuntime.exit(1); - } + }, "gateway discover failed"); }); } diff --git a/src/cli/models-cli.ts b/src/cli/models-cli.ts index 3268e9aba..a2674d94a 100644 --- a/src/cli/models-cli.ts +++ b/src/cli/models-cli.ts @@ -29,6 +29,11 @@ import { import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; +import { runCommandWithRuntime } from "./cli-utils.js"; + +function runModelsCommand(action: () => Promise) { + return runCommandWithRuntime(defaultRuntime, action); +} export function registerModelsCli(program: Command) { const models = program @@ -51,12 +56,9 @@ export function registerModelsCli(program: Command) { .option("--json", "Output JSON", false) .option("--plain", "Plain line output", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsListCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); models @@ -70,12 +72,9 @@ export function registerModelsCli(program: Command) { false, ) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsStatusCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); models @@ -83,12 +82,9 @@ export function registerModelsCli(program: Command) { .description("Set the default model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsSetCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); models @@ -96,12 +92,9 @@ export function registerModelsCli(program: Command) { .description("Set the image model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsSetImageCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const aliases = models.command("aliases").description("Manage model aliases"); @@ -112,12 +105,9 @@ export function registerModelsCli(program: Command) { .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAliasesListCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); aliases @@ -126,12 +116,9 @@ export function registerModelsCli(program: Command) { .argument("", "Alias name") .argument("", "Model id or alias") .action(async (alias: string, model: string) => { - try { + await runModelsCommand(async () => { await modelsAliasesAddCommand(alias, model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); aliases @@ -139,12 +126,9 @@ export function registerModelsCli(program: Command) { .description("Remove a model alias") .argument("", "Alias name") .action(async (alias: string) => { - try { + await runModelsCommand(async () => { await modelsAliasesRemoveCommand(alias, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const fallbacks = models.command("fallbacks").description("Manage model fallback list"); @@ -155,12 +139,9 @@ export function registerModelsCli(program: Command) { .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsFallbacksListCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); fallbacks @@ -168,12 +149,9 @@ export function registerModelsCli(program: Command) { .description("Add a fallback model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsFallbacksAddCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); fallbacks @@ -181,24 +159,18 @@ export function registerModelsCli(program: Command) { .description("Remove a fallback model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsFallbacksRemoveCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); fallbacks .command("clear") .description("Clear all fallback models") .action(async () => { - try { + await runModelsCommand(async () => { await modelsFallbacksClearCommand(defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const imageFallbacks = models @@ -211,12 +183,9 @@ export function registerModelsCli(program: Command) { .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsImageFallbacksListCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); imageFallbacks @@ -224,12 +193,9 @@ export function registerModelsCli(program: Command) { .description("Add an image fallback model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsImageFallbacksAddCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); imageFallbacks @@ -237,24 +203,18 @@ export function registerModelsCli(program: Command) { .description("Remove an image fallback model") .argument("", "Model id or alias") .action(async (model: string) => { - try { + await runModelsCommand(async () => { await modelsImageFallbacksRemoveCommand(model, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); imageFallbacks .command("clear") .description("Clear all image fallback models") .action(async () => { - try { + await runModelsCommand(async () => { await modelsImageFallbacksClearCommand(defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); models @@ -273,16 +233,13 @@ export function registerModelsCli(program: Command) { .option("--set-image", "Set agents.defaults.imageModel to the first image selection", false) .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsScanCommand(opts, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); models.action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsStatusCommand( { json: Boolean(opts?.statusJson), @@ -290,10 +247,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const auth = models.command("auth").description("Manage model auth profiles"); @@ -302,12 +256,9 @@ export function registerModelsCli(program: Command) { .command("add") .description("Interactive auth helper (setup-token or paste token)") .action(async () => { - try { + await runModelsCommand(async () => { await modelsAuthAddCommand({}, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); auth @@ -317,7 +268,7 @@ export function registerModelsCli(program: Command) { .option("--method ", "Provider auth method id") .option("--set-default", "Apply the provider's default model recommendation", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAuthLoginCommand( { provider: opts.provider as string | undefined, @@ -326,10 +277,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); auth @@ -338,7 +286,7 @@ export function registerModelsCli(program: Command) { .option("--provider ", "Provider id (default: anthropic)") .option("--yes", "Skip confirmation", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAuthSetupTokenCommand( { provider: opts.provider as string | undefined, @@ -346,10 +294,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); auth @@ -362,7 +307,7 @@ export function registerModelsCli(program: Command) { "Optional expiry duration (e.g. 365d, 12h). Stored as absolute expiresAt.", ) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAuthPasteTokenCommand( { provider: opts.provider as string | undefined, @@ -371,10 +316,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); auth @@ -383,7 +325,7 @@ export function registerModelsCli(program: Command) { .option("--profile-id ", "Auth profile id (default: github-copilot:github)") .option("--yes", "Overwrite existing profile without prompting", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await githubCopilotLoginCommand( { profileId: opts.profileId as string | undefined, @@ -391,10 +333,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const order = auth.command("order").description("Manage per-agent auth profile order overrides"); @@ -406,7 +345,7 @@ export function registerModelsCli(program: Command) { .option("--agent ", "Agent id (default: configured default agent)") .option("--json", "Output JSON", false) .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAuthOrderGetCommand( { provider: opts.provider as string, @@ -415,10 +354,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); order @@ -428,7 +364,7 @@ export function registerModelsCli(program: Command) { .option("--agent ", "Agent id (default: configured default agent)") .argument("", "Auth profile ids (e.g. anthropic:claude-cli)") .action(async (profileIds: string[], opts) => { - try { + await runModelsCommand(async () => { await modelsAuthOrderSetCommand( { provider: opts.provider as string, @@ -437,10 +373,7 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); order @@ -449,7 +382,7 @@ export function registerModelsCli(program: Command) { .requiredOption("--provider ", "Provider id (e.g. anthropic)") .option("--agent ", "Agent id (default: configured default agent)") .action(async (opts) => { - try { + await runModelsCommand(async () => { await modelsAuthOrderClearCommand( { provider: opts.provider as string, @@ -457,9 +390,6 @@ export function registerModelsCli(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/message/helpers.ts b/src/cli/program/message/helpers.ts index da1f46561..0f03a0b90 100644 --- a/src/cli/program/message/helpers.ts +++ b/src/cli/program/message/helpers.ts @@ -4,7 +4,7 @@ import { danger, setVerbose } from "../../../globals.js"; import { CHANNEL_TARGET_DESCRIPTION } from "../../../infra/outbound/channel-target.js"; import { defaultRuntime } from "../../../runtime.js"; import { createDefaultDeps } from "../../deps.js"; -import { ensureConfigReady } from "../config-guard.js"; +import { runCommandWithRuntime } from "../../cli-utils.js"; export type MessageCliHelpers = { withMessageBase: (command: Command) => Command; @@ -31,10 +31,11 @@ export function createMessageCliHelpers( command.requiredOption("-t, --target ", CHANNEL_TARGET_DESCRIPTION); const runMessageAction = async (action: string, opts: Record) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: true }); setVerbose(Boolean(opts.verbose)); const deps = createDefaultDeps(); - try { + await runCommandWithRuntime( + defaultRuntime, + async () => { await messageCommand( { ...(() => { @@ -49,10 +50,12 @@ export function createMessageCliHelpers( deps, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(danger(String(err))); - defaultRuntime.exit(1); - } + }, + (err) => { + defaultRuntime.error(danger(String(err))); + defaultRuntime.exit(1); + }, + ); }; // `message` is only used for `message.help({ error: true })`, keep the diff --git a/src/cli/program/register.agent.ts b/src/cli/program/register.agent.ts index cfde6709c..e87b71452 100644 --- a/src/cli/program/register.agent.ts +++ b/src/cli/program/register.agent.ts @@ -8,8 +8,8 @@ import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; import { hasExplicitOptions } from "../command-options.js"; import { createDefaultDeps } from "../deps.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; import { collectOption } from "./helpers.js"; -import { ensureConfigReady } from "./config-guard.js"; export function registerAgentCommands(program: Command, args: { agentChannelOptions: string }) { program @@ -54,17 +54,13 @@ Examples: ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent")}`, ) .action(async (opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: false }); const verboseLevel = typeof opts.verbose === "string" ? opts.verbose.toLowerCase() : ""; setVerbose(verboseLevel === "on"); // Build default deps (keeps parity with other commands; future-proofing). const deps = createDefaultDeps(); - try { + await runCommandWithRuntime(defaultRuntime, async () => { await agentCliCommand(opts, defaultRuntime, deps); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); const agents = program @@ -82,16 +78,12 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent .option("--json", "Output JSON instead of text", false) .option("--bindings", "Include routing bindings", false) .action(async (opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: true }); - try { + await runCommandWithRuntime(defaultRuntime, async () => { await agentsListCommand( { json: Boolean(opts.json), bindings: Boolean(opts.bindings) }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); agents @@ -104,8 +96,7 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent .option("--non-interactive", "Disable prompts; requires --workspace", false) .option("--json", "Output JSON summary", false) .action(async (name, opts, command) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: true }); - try { + await runCommandWithRuntime(defaultRuntime, async () => { const hasFlags = hasExplicitOptions(command, [ "workspace", "model", @@ -126,10 +117,7 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent defaultRuntime, { hasFlags }, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); agents @@ -138,8 +126,7 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent .option("--force", "Skip confirmation", false) .option("--json", "Output JSON summary", false) .action(async (id, opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: true }); - try { + await runCommandWithRuntime(defaultRuntime, async () => { await agentsDeleteCommand( { id: String(id), @@ -148,19 +135,12 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.clawd.bot/cli/agent }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); agents.action(async () => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: true }); - try { + await runCommandWithRuntime(defaultRuntime, async () => { await agentsListCommand({}, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/register.configure.ts b/src/cli/program/register.configure.ts index 0a6d6fd4b..a10805e88 100644 --- a/src/cli/program/register.configure.ts +++ b/src/cli/program/register.configure.ts @@ -7,6 +7,7 @@ import { import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; export function registerConfigureCommand(program: Command) { program @@ -24,7 +25,7 @@ export function registerConfigureCommand(program: Command) { [] as string[], ) .action(async (opts) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { const sections: string[] = Array.isArray(opts.section) ? opts.section .map((value: unknown) => (typeof value === "string" ? value.trim() : "")) @@ -45,9 +46,6 @@ export function registerConfigureCommand(program: Command) { } await configureCommandWithSections(sections as never, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/register.maintenance.ts b/src/cli/program/register.maintenance.ts index ffa5ac46d..8d045de64 100644 --- a/src/cli/program/register.maintenance.ts +++ b/src/cli/program/register.maintenance.ts @@ -6,6 +6,7 @@ import { uninstallCommand } from "../../commands/uninstall.js"; import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; export function registerMaintenanceCommands(program: Command) { program @@ -24,7 +25,7 @@ export function registerMaintenanceCommands(program: Command) { .option("--generate-gateway-token", "Generate and configure a gateway token", false) .option("--deep", "Scan system services for extra gateway installs", false) .action(async (opts) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { await doctorCommand(defaultRuntime, { workspaceSuggestions: opts.workspaceSuggestions, yes: Boolean(opts.yes), @@ -34,10 +35,7 @@ export function registerMaintenanceCommands(program: Command) { generateGatewayToken: Boolean(opts.generateGatewayToken), deep: Boolean(opts.deep), }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); program @@ -50,14 +48,11 @@ export function registerMaintenanceCommands(program: Command) { ) .option("--no-open", "Print URL but do not launch a browser", false) .action(async (opts) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { await dashboardCommand(defaultRuntime, { noOpen: Boolean(opts.noOpen), }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); program @@ -73,17 +68,14 @@ export function registerMaintenanceCommands(program: Command) { .option("--non-interactive", "Disable prompts (requires --scope + --yes)", false) .option("--dry-run", "Print actions without removing files", false) .action(async (opts) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { await resetCommand(defaultRuntime, { scope: opts.scope, yes: Boolean(opts.yes), nonInteractive: Boolean(opts.nonInteractive), dryRun: Boolean(opts.dryRun), }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); program @@ -103,7 +95,7 @@ export function registerMaintenanceCommands(program: Command) { .option("--non-interactive", "Disable prompts (requires --yes)", false) .option("--dry-run", "Print actions without removing files", false) .action(async (opts) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { await uninstallCommand(defaultRuntime, { service: Boolean(opts.service), state: Boolean(opts.state), @@ -114,9 +106,6 @@ export function registerMaintenanceCommands(program: Command) { nonInteractive: Boolean(opts.nonInteractive), dryRun: Boolean(opts.dryRun), }); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 08d610182..4f1005304 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -11,6 +11,7 @@ import type { 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, @@ -94,7 +95,7 @@ export function registerOnboardCommand(program: Command) { .option("--node-manager ", "Node manager for skills: npm|pnpm|bun") .option("--json", "Output JSON summary", false) .action(async (opts, command) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { const installDaemon = resolveInstallDaemonFlag(command, { installDaemon: Boolean(opts.installDaemon), }); @@ -147,9 +148,6 @@ export function registerOnboardCommand(program: Command) { }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/register.setup.ts b/src/cli/program/register.setup.ts index 189773d72..aa79a5dda 100644 --- a/src/cli/program/register.setup.ts +++ b/src/cli/program/register.setup.ts @@ -5,6 +5,7 @@ import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; import { hasExplicitOptions } from "../command-options.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; export function registerSetupCommand(program: Command) { program @@ -25,7 +26,7 @@ export function registerSetupCommand(program: Command) { .option("--remote-url ", "Remote Gateway WebSocket URL") .option("--remote-token ", "Remote Gateway token (optional)") .action(async (opts, command) => { - try { + await runCommandWithRuntime(defaultRuntime, async () => { const hasWizardFlags = hasExplicitOptions(command, [ "wizard", "nonInteractive", @@ -47,9 +48,6 @@ export function registerSetupCommand(program: Command) { return; } await setupCommand({ workspace: opts.workspace as string | undefined }, defaultRuntime); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); } diff --git a/src/cli/program/register.status-health-sessions.ts b/src/cli/program/register.status-health-sessions.ts index 6e39ec484..cb34e7cea 100644 --- a/src/cli/program/register.status-health-sessions.ts +++ b/src/cli/program/register.status-health-sessions.ts @@ -6,8 +6,22 @@ import { setVerbose } from "../../globals.js"; import { defaultRuntime } from "../../runtime.js"; import { formatDocsLink } from "../../terminal/links.js"; import { theme } from "../../terminal/theme.js"; +import { runCommandWithRuntime } from "../cli-utils.js"; import { parsePositiveIntOrUndefined } from "./helpers.js"; -import { ensureConfigReady } from "./config-guard.js"; + +function resolveVerbose(opts: { verbose?: boolean; debug?: boolean }): boolean { + return Boolean(opts.verbose || opts.debug); +} + +function parseTimeoutMs(timeout: unknown): number | null | undefined { + const parsed = parsePositiveIntOrUndefined(timeout); + if (timeout !== undefined && parsed === undefined) { + defaultRuntime.error("--timeout must be a positive integer (milliseconds)"); + defaultRuntime.exit(1); + return null; + } + return parsed; +} export function registerStatusHealthSessionsCommands(program: Command) { program @@ -38,16 +52,13 @@ Examples: `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/status", "docs.clawd.bot/cli/status")}\n`, ) .action(async (opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: false }); - const verbose = Boolean(opts.verbose || opts.debug); + const verbose = resolveVerbose(opts); setVerbose(verbose); - const timeout = parsePositiveIntOrUndefined(opts.timeout); - if (opts.timeout !== undefined && timeout === undefined) { - defaultRuntime.error("--timeout must be a positive integer (milliseconds)"); - defaultRuntime.exit(1); + const timeout = parseTimeoutMs(opts.timeout); + if (timeout === null) { return; } - try { + await runCommandWithRuntime(defaultRuntime, async () => { await statusCommand( { json: Boolean(opts.json), @@ -59,10 +70,7 @@ Examples: }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); program @@ -78,16 +86,13 @@ Examples: `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/health", "docs.clawd.bot/cli/health")}\n`, ) .action(async (opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: false }); - const verbose = Boolean(opts.verbose || opts.debug); + const verbose = resolveVerbose(opts); setVerbose(verbose); - const timeout = parsePositiveIntOrUndefined(opts.timeout); - if (opts.timeout !== undefined && timeout === undefined) { - defaultRuntime.error("--timeout must be a positive integer (milliseconds)"); - defaultRuntime.exit(1); + const timeout = parseTimeoutMs(opts.timeout); + if (timeout === null) { return; } - try { + await runCommandWithRuntime(defaultRuntime, async () => { await healthCommand( { json: Boolean(opts.json), @@ -96,10 +101,7 @@ Examples: }, defaultRuntime, ); - } catch (err) { - defaultRuntime.error(String(err)); - defaultRuntime.exit(1); - } + }); }); program @@ -126,7 +128,6 @@ Shows token usage per session when the agent reports it; set agents.defaults.con `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sessions", "docs.clawd.bot/cli/sessions")}\n`, ) .action(async (opts) => { - await ensureConfigReady({ runtime: defaultRuntime, migrateState: false }); setVerbose(Boolean(opts.verbose)); await sessionsCommand( {