From d14e7e200ca4f16bce77fc0db45a2259c1f2ecd1 Mon Sep 17 00:00:00 2001 From: cte Date: Fri, 16 Jan 2026 22:20:00 -0800 Subject: [PATCH] Add a --oneshot option --- apps/cli/src/commands/cli/run.ts | 3 +- apps/cli/src/index.ts | 1 + .../lib/storage/__tests__/settings.test.ts | 28 +++++++++++++ apps/cli/src/types/types.ts | 3 ++ apps/cli/src/ui/App.tsx | 42 +++++++++---------- apps/cli/src/ui/components/Header.tsx | 21 +++++----- 6 files changed, 63 insertions(+), 35 deletions(-) diff --git a/apps/cli/src/commands/cli/run.ts b/apps/cli/src/commands/cli/run.ts index 783333b146..86ede4c813 100644 --- a/apps/cli/src/commands/cli/run.ts +++ b/apps/cli/src/commands/cli/run.ts @@ -65,6 +65,7 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption const effectiveWorkspacePath = flagOptions.workspace ? path.resolve(flagOptions.workspace) : process.cwd() const effectiveDangerouslySkipPermissions = flagOptions.yes || flagOptions.dangerouslySkipPermissions || settings.dangerouslySkipPermissions || false + const effectiveExitOnComplete = flagOptions.print || flagOptions.oneshot || settings.oneshot || false const extensionHostOptions: ExtensionHostOptions = { mode: effectiveMode, @@ -77,7 +78,7 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption nonInteractive: effectiveDangerouslySkipPermissions, ephemeral: flagOptions.ephemeral, debug: flagOptions.debug, - exitOnComplete: flagOptions.print, + exitOnComplete: effectiveExitOnComplete, } // Roo Code Cloud Authentication diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index f4bad8c483..e664422562 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -29,6 +29,7 @@ program DEFAULT_FLAGS.reasoningEffort, ) .option("--ephemeral", "Run without persisting state (uses temporary storage)", false) + .option("--oneshot", "Exit upon task completion", false) .action(run) const authCommand = program.command("auth").description("Manage authentication for Roo Code Cloud") diff --git a/apps/cli/src/lib/storage/__tests__/settings.test.ts b/apps/cli/src/lib/storage/__tests__/settings.test.ts index 989118f2f3..c133f733b9 100644 --- a/apps/cli/src/lib/storage/__tests__/settings.test.ts +++ b/apps/cli/src/lib/storage/__tests__/settings.test.ts @@ -204,5 +204,33 @@ describe("Settings Storage", () => { expect(loaded.reasoningEffort).toBe("high") expect(loaded.dangerouslySkipPermissions).toBe(true) }) + + it("should support oneshot setting", async () => { + await saveSettings({ oneshot: true }) + const loaded = await loadSettings() + + expect(loaded.oneshot).toBe(true) + }) + + it("should support all settings together including oneshot", async () => { + const allSettings = { + mode: "architect", + provider: "anthropic" as const, + model: "claude-sonnet-4-20250514", + reasoningEffort: "high" as const, + dangerouslySkipPermissions: true, + oneshot: true, + } + + await saveSettings(allSettings) + const loaded = await loadSettings() + + expect(loaded.mode).toBe("architect") + expect(loaded.provider).toBe("anthropic") + expect(loaded.model).toBe("claude-sonnet-4-20250514") + expect(loaded.reasoningEffort).toBe("high") + expect(loaded.dangerouslySkipPermissions).toBe(true) + expect(loaded.oneshot).toBe(true) + }) }) }) diff --git a/apps/cli/src/types/types.ts b/apps/cli/src/types/types.ts index f7a93a683e..d5c71a330f 100644 --- a/apps/cli/src/types/types.ts +++ b/apps/cli/src/types/types.ts @@ -31,6 +31,7 @@ export type FlagOptions = { mode?: string reasoningEffort?: ReasoningEffortFlagOptions ephemeral: boolean + oneshot: boolean } export enum OnboardingProviderChoice { @@ -56,4 +57,6 @@ export interface CliSettings { reasoningEffort?: ReasoningEffortFlagOptions /** Auto-approve all prompts (use with caution) */ dangerouslySkipPermissions?: boolean + /** Exit upon task completion */ + oneshot?: boolean } diff --git a/apps/cli/src/ui/App.tsx b/apps/cli/src/ui/App.tsx index fc2fc51add..208a9bb0f9 100644 --- a/apps/cli/src/ui/App.tsx +++ b/apps/cli/src/ui/App.tsx @@ -68,23 +68,24 @@ export interface TUIAppProps extends ExtensionHostOptions { /** * Inner App component that uses the terminal size context */ -function AppInner({ - initialPrompt, - workspacePath, - extensionPath, - user, - provider, - apiKey, - model, - mode, - nonInteractive = false, - debug, - exitOnComplete, - reasoningEffort, - ephemeral, - version, - createExtensionHost, -}: TUIAppProps) { +function AppInner({ createExtensionHost, ...extensionHostOptions }: TUIAppProps) { + const { + initialPrompt, + workspacePath, + extensionPath, + user, + provider, + apiKey, + model, + mode, + nonInteractive = false, + debug, + exitOnComplete, + reasoningEffort, + ephemeral, + version, + } = extensionHostOptions + const { exit } = useApp() const { @@ -454,12 +455,7 @@ function AppInner({ {/* Header - fixed size */}
{user && Welcome back, {user.name}} - cwd: {cwd.startsWith(homeDir) ? cwd.replace(homeDir, "~") : cwd} + cwd:{" "} + {workspacePath.startsWith(homeDir) ? workspacePath.replace(homeDir, "~") : workspacePath} {provider}: {model} [{reasoningEffort}] - mode: {mode} + + mode: {mode} + {nonInteractive && " (YOLO)"} +