Skip to content

Commit 6c8b9df

Browse files
cteroomote
andauthored
Make CLI auto-approve by default with require-approval opt-in (#11424)
Co-authored-by: Roo Code <roomote@roocode.com>
1 parent bd4cd07 commit 6c8b9df

9 files changed

Lines changed: 58 additions & 50 deletions

File tree

apps/cli/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6767
### Changed
6868

6969
- Skip onboarding flow when a provider is explicitly specified via `--provider` flag or saved in settings
70-
- Unified permission flags: Combined `-y`, `--yes`, and `--dangerously-skip-permissions` into a single option for Claude Code-like CLI compatibility
70+
- Unified permission flags: Combined approval-skipping flags into a single option for Claude Code-like CLI compatibility
7171
- Improved Roo Code Router authentication flow and error messaging
7272

7373
### Fixed

apps/cli/README.md

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pnpm --filter @roo-code/cli build
6666

6767
### Interactive Mode (Default)
6868

69-
By default, the CLI prompts for approval before executing actions:
69+
By default, the CLI auto-approves actions and runs in interactive TUI mode:
7070

7171
```bash
7272
export OPENROUTER_API_KEY=sk-or-v1-...
@@ -82,24 +82,23 @@ roo -w ~/Documents/my-project
8282

8383
In interactive mode:
8484

85-
- Tool executions prompt for yes/no approval
86-
- Commands prompt for yes/no approval
87-
- Followup questions show suggestions and wait for user input
88-
- Browser and MCP actions prompt for approval
85+
- Tool executions are auto-approved
86+
- Commands are auto-approved
87+
- Followup questions show suggestions with a 60-second timeout, then auto-select the first suggestion
88+
- Browser and MCP actions are auto-approved
8989

90-
### Non-Interactive Mode (`-y`)
90+
### Approval-Required Mode (`--require-approval`)
9191

92-
For automation and scripts, use `-y` to auto-approve all actions:
92+
If you want manual approval prompts, enable approval-required mode:
9393

9494
```bash
95-
roo "Refactor the utils.ts file" -y -w ~/Documents/my-project
95+
roo "Refactor the utils.ts file" --require-approval -w ~/Documents/my-project
9696
```
9797

98-
In non-interactive mode:
98+
In approval-required mode:
9999

100-
- Tool, command, browser, and MCP actions are auto-approved
101-
- Followup questions show a 60-second timeout, then auto-select the first suggestion
102-
- Typing any key cancels the timeout and allows manual input
100+
- Tool, command, browser, and MCP actions prompt for yes/no approval
101+
- Followup questions wait for manual input (no auto-timeout)
103102

104103
### Roo Code Cloud Authentication
105104

@@ -147,23 +146,23 @@ Tokens are valid for 90 days. The CLI will prompt you to re-authenticate when yo
147146

148147
## Options
149148

150-
| Option | Description | Default |
151-
| ------------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- |
152-
| `[prompt]` | Your prompt (positional argument, optional) | None |
153-
| `--prompt-file <path>` | Read prompt from a file instead of command line argument | None |
154-
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
155-
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
156-
| `-e, --extension <path>` | Path to the extension bundle directory | Auto-detected |
157-
| `-d, --debug` | Enable debug output (includes detailed debug information, prompts, paths, etc) | `false` |
158-
| `-y, --yes, --dangerously-skip-permissions` | Auto-approve all actions (use with caution) | `false` |
159-
| `-k, --api-key <key>` | API key for the LLM provider | From env var |
160-
| `--provider <provider>` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) |
161-
| `-m, --model <model>` | Model to use | `anthropic/claude-opus-4.6` |
162-
| `--mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
163-
| `-r, --reasoning-effort <effort>` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` |
164-
| `--ephemeral` | Run without persisting state (uses temporary storage) | `false` |
165-
| `--oneshot` | Exit upon task completion | `false` |
166-
| `--output-format <format>` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` |
149+
| Option | Description | Default |
150+
| --------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- |
151+
| `[prompt]` | Your prompt (positional argument, optional) | None |
152+
| `--prompt-file <path>` | Read prompt from a file instead of command line argument | None |
153+
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
154+
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
155+
| `-e, --extension <path>` | Path to the extension bundle directory | Auto-detected |
156+
| `-d, --debug` | Enable debug output (includes detailed debug information, prompts, paths, etc) | `false` |
157+
| `-a, --require-approval` | Require manual approval before actions execute | `false` |
158+
| `-k, --api-key <key>` | API key for the LLM provider | From env var |
159+
| `--provider <provider>` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) |
160+
| `-m, --model <model>` | Model to use | `anthropic/claude-opus-4.6` |
161+
| `--mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
162+
| `-r, --reasoning-effort <effort>` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` |
163+
| `--ephemeral` | Run without persisting state (uses temporary storage) | `false` |
164+
| `--oneshot` | Exit upon task completion | `false` |
165+
| `--output-format <format>` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` |
167166

168167
## Auth Commands
169168

apps/cli/docs/AGENT_LOOP.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ Routes asks to appropriate handlers:
242242

243243
- Uses type guards: `isIdleAsk()`, `isInteractiveAsk()`, etc.
244244
- Coordinates between `OutputManager` and `PromptManager`
245-
- In non-interactive mode (`-y` flag), auto-approves everything
245+
- By default, the CLI auto-approves tool/command/browser/MCP actions
246+
- In `--require-approval` mode, those actions prompt for manual approval
246247

247248
### OutputManager
248249

@@ -320,7 +321,7 @@ if (isInteractiveAsk(ask)) {
320321
Enable with `-d` flag. Logs go to `~/.roo/cli-debug.log`:
321322

322323
```bash
323-
roo -d -y -P "Build something" --no-tui
324+
roo -d -P "Build something" --no-tui
324325
```
325326

326327
View logs:

apps/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"test": "vitest run",
1616
"build": "tsup",
1717
"build:extension": "pnpm --filter roo-cline bundle",
18-
"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",
18+
"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",
1919
"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",
2020
"clean": "rimraf dist .turbo"
2121
},

apps/cli/src/commands/cli/run.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
6565
flagOptions.reasoningEffort || settings.reasoningEffort || DEFAULT_FLAGS.reasoningEffort
6666
const effectiveProvider = flagOptions.provider ?? settings.provider ?? (rooToken ? "roo" : "openrouter")
6767
const effectiveWorkspacePath = flagOptions.workspace ? path.resolve(flagOptions.workspace) : process.cwd()
68-
const effectiveDangerouslySkipPermissions =
69-
flagOptions.yes || flagOptions.dangerouslySkipPermissions || settings.dangerouslySkipPermissions || false
68+
const legacyRequireApprovalFromSettings =
69+
settings.requireApproval ??
70+
(settings.dangerouslySkipPermissions === undefined ? undefined : !settings.dangerouslySkipPermissions)
71+
const effectiveRequireApproval = flagOptions.requireApproval || legacyRequireApprovalFromSettings || false
7072
const effectiveExitOnComplete = flagOptions.print || flagOptions.oneshot || settings.oneshot || false
7173

7274
const extensionHostOptions: ExtensionHostOptions = {
@@ -77,7 +79,7 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
7779
model: effectiveModel,
7880
workspacePath: effectiveWorkspacePath,
7981
extensionPath: path.resolve(flagOptions.extension || getDefaultExtensionPath(__dirname)),
80-
nonInteractive: effectiveDangerouslySkipPermissions,
82+
nonInteractive: !effectiveRequireApproval,
8183
exitOnError: flagOptions.exitOnError,
8284
ephemeral: flagOptions.ephemeral,
8385
debug: flagOptions.debug,

apps/cli/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ program
1818
.option("-p, --print", "Print response and exit (non-interactive mode)", false)
1919
.option("-e, --extension <path>", "Path to the extension bundle directory")
2020
.option("-d, --debug", "Enable debug output (includes detailed debug information)", false)
21-
.option("-y, --yes", "Auto-approve all prompts (use with caution)", false)
22-
.option("--dangerously-skip-permissions", "Alias for --yes", false)
21+
.option("-a, --require-approval", "Require manual approval for actions", false)
2322
.option("-k, --api-key <key>", "API key for the LLM provider")
2423
.option("--provider <provider>", "API provider (roo, anthropic, openai, openrouter, etc.)")
2524
.option("-m, --model <model>", "Model to use", DEFAULT_FLAGS.model)

apps/cli/src/lib/storage/__tests__/settings.test.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,20 @@ describe("Settings Storage", () => {
179179
expect(loaded.reasoningEffort).toBe("low")
180180
})
181181

182-
it("should support dangerouslySkipPermissions setting", async () => {
183-
await saveSettings({ dangerouslySkipPermissions: true })
182+
it("should support requireApproval setting", async () => {
183+
await saveSettings({ requireApproval: true })
184184
const loaded = await loadSettings()
185185

186-
expect(loaded.dangerouslySkipPermissions).toBe(true)
186+
expect(loaded.requireApproval).toBe(true)
187187
})
188188

189-
it("should support all settings together including dangerouslySkipPermissions", async () => {
189+
it("should support all settings together including requireApproval", async () => {
190190
const allSettings = {
191191
mode: "architect",
192192
provider: "anthropic" as const,
193193
model: "claude-sonnet-4-20250514",
194194
reasoningEffort: "high" as const,
195-
dangerouslySkipPermissions: true,
195+
requireApproval: true,
196196
}
197197

198198
await saveSettings(allSettings)
@@ -202,7 +202,7 @@ describe("Settings Storage", () => {
202202
expect(loaded.provider).toBe("anthropic")
203203
expect(loaded.model).toBe("claude-sonnet-4-20250514")
204204
expect(loaded.reasoningEffort).toBe("high")
205-
expect(loaded.dangerouslySkipPermissions).toBe(true)
205+
expect(loaded.requireApproval).toBe(true)
206206
})
207207

208208
it("should support oneshot setting", async () => {
@@ -218,7 +218,7 @@ describe("Settings Storage", () => {
218218
provider: "anthropic" as const,
219219
model: "claude-sonnet-4-20250514",
220220
reasoningEffort: "high" as const,
221-
dangerouslySkipPermissions: true,
221+
requireApproval: true,
222222
oneshot: true,
223223
}
224224

@@ -229,8 +229,15 @@ describe("Settings Storage", () => {
229229
expect(loaded.provider).toBe("anthropic")
230230
expect(loaded.model).toBe("claude-sonnet-4-20250514")
231231
expect(loaded.reasoningEffort).toBe("high")
232-
expect(loaded.dangerouslySkipPermissions).toBe(true)
232+
expect(loaded.requireApproval).toBe(true)
233233
expect(loaded.oneshot).toBe(true)
234234
})
235+
236+
it("should still load legacy dangerouslySkipPermissions setting", async () => {
237+
await saveSettings({ dangerouslySkipPermissions: true })
238+
const loaded = await loadSettings()
239+
240+
expect(loaded.dangerouslySkipPermissions).toBe(true)
241+
})
235242
})
236243
})

apps/cli/src/types/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ export type FlagOptions = {
2424
print: boolean
2525
extension?: string
2626
debug: boolean
27-
yes: boolean
28-
dangerouslySkipPermissions: boolean
27+
requireApproval: boolean
2928
exitOnError: boolean
3029
apiKey?: string
3130
provider?: SupportedProvider
@@ -58,7 +57,9 @@ export interface CliSettings {
5857
model?: string
5958
/** Default reasoning effort level */
6059
reasoningEffort?: ReasoningEffortFlagOptions
61-
/** Auto-approve all prompts (use with caution) */
60+
/** Require manual approval for tools/commands/browser/MCP actions */
61+
requireApproval?: boolean
62+
/** @deprecated Legacy inverse setting kept for backward compatibility */
6263
dangerouslySkipPermissions?: boolean
6364
/** Exit upon task completion */
6465
oneshot?: boolean

packages/evals/src/cli/runTaskInCli.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export const runTaskWithCli = async ({ run, task, publish, logger, jobToken }: R
4343
promptSourcePath,
4444
"--workspace",
4545
workspacePath,
46-
"--yes",
4746
"--reasoning-effort",
4847
"disabled",
4948
"--oneshot",

0 commit comments

Comments
 (0)