mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Make CLI auto-approve by default with require-approval opt-in (#11424)
Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
parent
bd4cd07e88
commit
6c8b9dfa26
9 changed files with 58 additions and 50 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <path>` | Read prompt from a file instead of command line argument | None |
|
||||
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
|
||||
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
|
||||
| `-e, --extension <path>` | 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 <key>` | API key for the LLM provider | From env var |
|
||||
| `--provider <provider>` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) |
|
||||
| `-m, --model <model>` | Model to use | `anthropic/claude-opus-4.6` |
|
||||
| `--mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
|
||||
| `-r, --reasoning-effort <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 <format>` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` |
|
||||
| Option | Description | Default |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------- |
|
||||
| `[prompt]` | Your prompt (positional argument, optional) | None |
|
||||
| `--prompt-file <path>` | Read prompt from a file instead of command line argument | None |
|
||||
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
|
||||
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
|
||||
| `-e, --extension <path>` | 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 <key>` | API key for the LLM provider | From env var |
|
||||
| `--provider <provider>` | API provider (roo, anthropic, openai, openrouter, etc.) | `openrouter` (or `roo` if authenticated) |
|
||||
| `-m, --model <model>` | Model to use | `anthropic/claude-opus-4.6` |
|
||||
| `--mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
|
||||
| `-r, --reasoning-effort <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 <format>` | Output format with `--print`: `text`, `json`, or `stream-json` | `text` |
|
||||
|
||||
## Auth Commands
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@ program
|
|||
.option("-p, --print", "Print response and exit (non-interactive mode)", false)
|
||||
.option("-e, --extension <path>", "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 <key>", "API key for the LLM provider")
|
||||
.option("--provider <provider>", "API provider (roo, anthropic, openai, openrouter, etc.)")
|
||||
.option("-m, --model <model>", "Model to use", DEFAULT_FLAGS.model)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ export const runTaskWithCli = async ({ run, task, publish, logger, jobToken }: R
|
|||
promptSourcePath,
|
||||
"--workspace",
|
||||
workspacePath,
|
||||
"--yes",
|
||||
"--reasoning-effort",
|
||||
"disabled",
|
||||
"--oneshot",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue