diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md index 98231e84808..2ae88332dd3 100644 --- a/apps/cli/CHANGELOG.md +++ b/apps/cli/CHANGELOG.md @@ -67,7 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Skip onboarding flow when a provider is explicitly specified via `--provider` flag or saved in settings -- Unified permission flags: Combined `-y`, `--yes`, and `--dangerously-skip-permissions` into a single option for Claude Code-like CLI compatibility +- Unified permission flags: Combined approval-skipping flags into a single option for Claude Code-like CLI compatibility - Improved Roo Code Router authentication flow and error messaging ### Fixed diff --git a/apps/cli/README.md b/apps/cli/README.md index 7060be6e8f6..0e49140b91d 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -66,7 +66,7 @@ pnpm --filter @roo-code/cli build ### Interactive Mode (Default) -By default, the CLI prompts for approval before executing actions: +By default, the CLI auto-approves actions and runs in interactive TUI mode: ```bash export OPENROUTER_API_KEY=sk-or-v1-... @@ -82,24 +82,23 @@ roo -w ~/Documents/my-project In interactive mode: -- Tool executions prompt for yes/no approval -- Commands prompt for yes/no approval -- Followup questions show suggestions and wait for user input -- Browser and MCP actions prompt for approval +- Tool executions are auto-approved +- Commands are auto-approved +- Followup questions show suggestions with a 60-second timeout, then auto-select the first suggestion +- Browser and MCP actions are auto-approved -### Non-Interactive Mode (`-y`) +### Approval-Required Mode (`--require-approval`) -For automation and scripts, use `-y` to auto-approve all actions: +If you want manual approval prompts, enable approval-required mode: ```bash -roo "Refactor the utils.ts file" -y -w ~/Documents/my-project +roo "Refactor the utils.ts file" --require-approval -w ~/Documents/my-project ``` -In non-interactive mode: +In approval-required mode: -- Tool, command, browser, and MCP actions are auto-approved -- Followup questions show a 60-second timeout, then auto-select the first suggestion -- Typing any key cancels the timeout and allows manual input +- Tool, command, browser, and MCP actions prompt for yes/no approval +- Followup questions wait for manual input (no auto-timeout) ### Roo Code Cloud Authentication @@ -147,23 +146,23 @@ Tokens are valid for 90 days. The CLI will prompt you to re-authenticate when yo ## Options -| Option | Description | Default | -| ------------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- | -| `[prompt]` | Your prompt (positional argument, optional) | None | -| `--prompt-file ` | Read prompt from a file instead of command line argument | None | -| `-w, --workspace ` | Workspace path to operate in | Current directory | -| `-p, --print` | Print response and exit (non-interactive mode) | `false` | -| `-e, --extension ` | Path to the extension bundle directory | Auto-detected | -| `-d, --debug` | Enable debug output (includes detailed debug information, prompts, paths, etc) | `false` | -| `-y, --yes, --dangerously-skip-permissions` | Auto-approve all actions (use with caution) | `false` | -| `-k, --api-key ` | API key for the LLM provider | From env var | -| `--provider ` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) | -| `-m, --model ` | Model to use | `anthropic/claude-opus-4.6` | -| `--mode ` | Mode to start in (code, architect, ask, debug, etc.) | `code` | -| `-r, --reasoning-effort ` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` | -| `--ephemeral` | Run without persisting state (uses temporary storage) | `false` | -| `--oneshot` | Exit upon task completion | `false` | -| `--output-format ` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` | +| Option | Description | Default | +| --------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- | +| `[prompt]` | Your prompt (positional argument, optional) | None | +| `--prompt-file ` | Read prompt from a file instead of command line argument | None | +| `-w, --workspace ` | Workspace path to operate in | Current directory | +| `-p, --print` | Print response and exit (non-interactive mode) | `false` | +| `-e, --extension ` | Path to the extension bundle directory | Auto-detected | +| `-d, --debug` | Enable debug output (includes detailed debug information, prompts, paths, etc) | `false` | +| `-a, --require-approval` | Require manual approval before actions execute | `false` | +| `-k, --api-key ` | API key for the LLM provider | From env var | +| `--provider ` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) | +| `-m, --model ` | Model to use | `anthropic/claude-opus-4.6` | +| `--mode ` | Mode to start in (code, architect, ask, debug, etc.) | `code` | +| `-r, --reasoning-effort ` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` | +| `--ephemeral` | Run without persisting state (uses temporary storage) | `false` | +| `--oneshot` | Exit upon task completion | `false` | +| `--output-format ` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` | ## Auth Commands diff --git a/apps/cli/docs/AGENT_LOOP.md b/apps/cli/docs/AGENT_LOOP.md index a7b1d9eed40..a512d47a500 100644 --- a/apps/cli/docs/AGENT_LOOP.md +++ b/apps/cli/docs/AGENT_LOOP.md @@ -242,7 +242,8 @@ Routes asks to appropriate handlers: - Uses type guards: `isIdleAsk()`, `isInteractiveAsk()`, etc. - Coordinates between `OutputManager` and `PromptManager` -- In non-interactive mode (`-y` flag), auto-approves everything +- By default, the CLI auto-approves tool/command/browser/MCP actions +- In `--require-approval` mode, those actions prompt for manual approval ### OutputManager @@ -320,7 +321,7 @@ if (isInteractiveAsk(ask)) { Enable with `-d` flag. Logs go to `~/.roo/cli-debug.log`: ```bash -roo -d -y -P "Build something" --no-tui +roo -d -P "Build something" --no-tui ``` View logs: diff --git a/apps/cli/package.json b/apps/cli/package.json index 029e6772011..dcab6b45cf2 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -15,7 +15,7 @@ "test": "vitest run", "build": "tsup", "build:extension": "pnpm --filter roo-cline bundle", - "dev": "ROO_AUTH_BASE_URL=https://app.roocode.com ROO_SDK_BASE_URL=https://cloud-api.roocode.com ROO_CODE_PROVIDER_URL=https://api.roocode.com/proxy tsx src/index.ts -y", + "dev": "ROO_AUTH_BASE_URL=https://app.roocode.com ROO_SDK_BASE_URL=https://cloud-api.roocode.com ROO_CODE_PROVIDER_URL=https://api.roocode.com/proxy tsx src/index.ts", "dev:local": "ROO_AUTH_BASE_URL=http://localhost:3000 ROO_SDK_BASE_URL=http://localhost:3001 ROO_CODE_PROVIDER_URL=http://localhost:8080/proxy tsx src/index.ts", "clean": "rimraf dist .turbo" }, diff --git a/apps/cli/src/commands/cli/run.ts b/apps/cli/src/commands/cli/run.ts index 881107fb820..1ce2f4a1f11 100644 --- a/apps/cli/src/commands/cli/run.ts +++ b/apps/cli/src/commands/cli/run.ts @@ -65,8 +65,10 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption flagOptions.reasoningEffort || settings.reasoningEffort || DEFAULT_FLAGS.reasoningEffort const effectiveProvider = flagOptions.provider ?? settings.provider ?? (rooToken ? "roo" : "openrouter") const effectiveWorkspacePath = flagOptions.workspace ? path.resolve(flagOptions.workspace) : process.cwd() - const effectiveDangerouslySkipPermissions = - flagOptions.yes || flagOptions.dangerouslySkipPermissions || settings.dangerouslySkipPermissions || false + const legacyRequireApprovalFromSettings = + settings.requireApproval ?? + (settings.dangerouslySkipPermissions === undefined ? undefined : !settings.dangerouslySkipPermissions) + const effectiveRequireApproval = flagOptions.requireApproval || legacyRequireApprovalFromSettings || false const effectiveExitOnComplete = flagOptions.print || flagOptions.oneshot || settings.oneshot || false const extensionHostOptions: ExtensionHostOptions = { @@ -77,7 +79,7 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption model: effectiveModel, workspacePath: effectiveWorkspacePath, extensionPath: path.resolve(flagOptions.extension || getDefaultExtensionPath(__dirname)), - nonInteractive: effectiveDangerouslySkipPermissions, + nonInteractive: !effectiveRequireApproval, exitOnError: flagOptions.exitOnError, ephemeral: flagOptions.ephemeral, debug: flagOptions.debug, diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index 51218aa8604..a1fd1be89e1 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -18,8 +18,7 @@ program .option("-p, --print", "Print response and exit (non-interactive mode)", false) .option("-e, --extension ", "Path to the extension bundle directory") .option("-d, --debug", "Enable debug output (includes detailed debug information)", false) - .option("-y, --yes", "Auto-approve all prompts (use with caution)", false) - .option("--dangerously-skip-permissions", "Alias for --yes", false) + .option("-a, --require-approval", "Require manual approval for actions", false) .option("-k, --api-key ", "API key for the LLM provider") .option("--provider ", "API provider (roo, anthropic, openai, openrouter, etc.)") .option("-m, --model ", "Model to use", DEFAULT_FLAGS.model) diff --git a/apps/cli/src/lib/storage/__tests__/settings.test.ts b/apps/cli/src/lib/storage/__tests__/settings.test.ts index d5d520a5975..30f1dbe8ecb 100644 --- a/apps/cli/src/lib/storage/__tests__/settings.test.ts +++ b/apps/cli/src/lib/storage/__tests__/settings.test.ts @@ -179,20 +179,20 @@ describe("Settings Storage", () => { expect(loaded.reasoningEffort).toBe("low") }) - it("should support dangerouslySkipPermissions setting", async () => { - await saveSettings({ dangerouslySkipPermissions: true }) + it("should support requireApproval setting", async () => { + await saveSettings({ requireApproval: true }) const loaded = await loadSettings() - expect(loaded.dangerouslySkipPermissions).toBe(true) + expect(loaded.requireApproval).toBe(true) }) - it("should support all settings together including dangerouslySkipPermissions", async () => { + it("should support all settings together including requireApproval", async () => { const allSettings = { mode: "architect", provider: "anthropic" as const, model: "claude-sonnet-4-20250514", reasoningEffort: "high" as const, - dangerouslySkipPermissions: true, + requireApproval: true, } await saveSettings(allSettings) @@ -202,7 +202,7 @@ describe("Settings Storage", () => { 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.requireApproval).toBe(true) }) it("should support oneshot setting", async () => { @@ -218,7 +218,7 @@ describe("Settings Storage", () => { provider: "anthropic" as const, model: "claude-sonnet-4-20250514", reasoningEffort: "high" as const, - dangerouslySkipPermissions: true, + requireApproval: true, oneshot: true, } @@ -229,8 +229,15 @@ describe("Settings Storage", () => { 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.requireApproval).toBe(true) expect(loaded.oneshot).toBe(true) }) + + it("should still load legacy dangerouslySkipPermissions setting", async () => { + await saveSettings({ dangerouslySkipPermissions: true }) + const loaded = await loadSettings() + + expect(loaded.dangerouslySkipPermissions).toBe(true) + }) }) }) diff --git a/apps/cli/src/types/types.ts b/apps/cli/src/types/types.ts index 827afad513a..162f7bac7b7 100644 --- a/apps/cli/src/types/types.ts +++ b/apps/cli/src/types/types.ts @@ -24,8 +24,7 @@ export type FlagOptions = { print: boolean extension?: string debug: boolean - yes: boolean - dangerouslySkipPermissions: boolean + requireApproval: boolean exitOnError: boolean apiKey?: string provider?: SupportedProvider @@ -58,7 +57,9 @@ export interface CliSettings { model?: string /** Default reasoning effort level */ reasoningEffort?: ReasoningEffortFlagOptions - /** Auto-approve all prompts (use with caution) */ + /** Require manual approval for tools/commands/browser/MCP actions */ + requireApproval?: boolean + /** @deprecated Legacy inverse setting kept for backward compatibility */ dangerouslySkipPermissions?: boolean /** Exit upon task completion */ oneshot?: boolean diff --git a/packages/evals/src/cli/runTaskInCli.ts b/packages/evals/src/cli/runTaskInCli.ts index 03b3ad4f701..ea22202305c 100644 --- a/packages/evals/src/cli/runTaskInCli.ts +++ b/packages/evals/src/cli/runTaskInCli.ts @@ -43,7 +43,6 @@ export const runTaskWithCli = async ({ run, task, publish, logger, jobToken }: R promptSourcePath, "--workspace", workspacePath, - "--yes", "--reasoning-effort", "disabled", "--oneshot",