Roo-Code/apps/cli
Hannes Rudolph bcb8c81916
Reapply Batch 2: 9 minor-conflict non-AI-SDK cherry-picks (#11474)
* fix: correct Bedrock model ID for Claude Opus 4.6 (#11232)

Remove the :0 suffix from the Claude Opus 4.6 model ID to match
the correct AWS Bedrock model identifier.

The model ID was "anthropic.claude-opus-4-6-v1:0" but should be
"anthropic.claude-opus-4-6-v1" per AWS Bedrock documentation.

Fixes #11231

Co-authored-by: Roo Code <roomote@roocode.com>

* fix: guard against empty-string baseURL in provider constructors (#11233)

When the 'custom base URL' checkbox is unchecked in the UI, the setting
is set to '' (empty string). Providers that passed this directly to their
SDK constructors caused 'Failed to parse URL' errors because the SDK
treated '' as a valid but broken base URL override.

- gemini.ts: use || undefined (was passing raw option)
- openai-native.ts: use || undefined (was passing raw option)
- openai.ts: change ?? to || for fallback default
- deepseek.ts: change ?? to || for fallback default
- moonshot.ts: change ?? to || for fallback default

Adds test coverage for Gemini and OpenAI Native constructors verifying
empty-string baseURL is coerced to undefined.

* fix: make defaultTemperature required in getModelParams to prevent silent temperature overrides (#11218)

* fix: DeepSeek temperature defaulting to 0 instead of 0.3

Pass defaultTemperature: DEEP_SEEK_DEFAULT_TEMPERATURE to getModelParams() in
DeepSeekHandler.getModel() to ensure the correct default temperature (0.3)
is used when no user configuration is provided.

Closes #11194

* refactor: make defaultTemperature required in getModelParams

Make the defaultTemperature parameter required in getModelParams() instead
of defaulting to 0. This prevents providers with their own non-zero default
temperature (like DeepSeek's 0.3) from being silently overridden by the
implicit 0 default.

Every provider now explicitly declares its temperature default, making the
temperature resolution chain clear:
  user setting → model default → provider default

---------

Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>

* feat: batch consecutive tool calls in chat UI with shared utility (#11245)

* feat: group consecutive list_files tool calls into single UI block

Consolidate consecutive listFilesTopLevel/listFilesRecursive ask messages
into a single 'Roo wants to view multiple directories' block, matching the
existing read_file batching pattern.

* chore: add missing translation keys for all locales

* refactor: consolidate duplicate listFiles batch-handling blocks in ChatRow

Merge the separate listFilesTopLevel and listFilesRecursive case blocks
into a single combined case with shared batch-detection logic, selecting
the icon and translation key based on the tool type. This removes the
duplicated isBatchDirRequest check and BatchListFilesPermission render.

* feat: batch consecutive file-edit tool calls into single UI block

Add edit-file batching in ChatView groupedMessages that consolidates
consecutive editedExistingFile, appliedDiff, newFileCreated,
insertContent, and searchAndReplace asks into a single BatchDiffApproval
block. Move batchDiffs detection in ChatRow above the switch statement
so it applies to any file-edit tool type.

* refactor: extract batchConsecutive utility, fix batch UI issues

- Extract generic batchConsecutive() utility from 3 identical while-loops
- Fix React key collisions in BatchListFilesPermission, BatchFilePermission, BatchDiffApproval
- Normalize language prop to "shellsession" (was "shell-session" for top-level)
- Remove unused _batchedMessages property from synthetic messages
- Remove dead didViewMultipleDirectories i18n key from all 18 locale files
- Add batch button text for listFilesTopLevel/listFilesRecursive
- Add batchConsecutive utility tests (6 cases)

* fix: audit improvements for batch tool-call UI

- Make batchConsecutive() generic instead of ClineMessage-specific
- Add batch-aware button text for edit-file batches ("Save All"/"Deny All")
- Add dedicated list-batch/edit-batch i18n keys (stop reusing read-batch)
- Add JSON.parse defense-in-depth in all three synthesizers
- Fix mixed list_files batch icon to default to FolderTree
- Add 6 missing test cases (all-match, immutability, spy, single-dir)

* chore: minor type cleanup (out-of-scope housekeeping)

- Trim unused recursive/isOutsideWorkspace from DirPermissionItem interface
- Remove 4 pre-existing `as any` casts in ChatView.tsx:
  - window cast → precise inline type
  - checkpoint bracket access → removed unnecessary casts
  - condensing message → `as ClineMessage`
  - debounce cancel → `.clear()` (correct API)
- Update BatchListFilesPermission test data to match trimmed interface

* i18n: add list-batch and edit-batch translations for all locales

* feat: add IPC query handlers for commands, modes, and models (#11279)

Add GetCommands, GetModes, and GetModels to the IPC protocol so external
clients can fetch slash commands, available modes, and Roo provider models
without going through the internal webview message channel.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add lock toggle to pin API config across all modes in workspace (#11295)

* feat: add lock toggle to pin API config across all modes in workspace

Add a lock/unlock toggle inside the API config selector popover (next to
the settings gear) that, when enabled, applies the selected API
configuration to all modes in the current workspace.

- Add lockApiConfigAcrossModes to ExtensionState and WebviewMessage types
- Store setting in workspaceState (per-workspace, not global)
- When locked, activateProviderProfile sets config for all modes
- Lock icon in ApiConfigSelector popover bottom bar next to gear
- Full i18n: English + 17 locale translations (all mention workspace scope)
- 9 new tests: 2 ClineProvider, 2 handler, 5 UI (77 total pass)

* refactor: replace write-fan-out with read-time override for lock API config

The original lock implementation used setModeConfig() fan-out to write the
locked config to ALL modes globally. Since the lock flag lives in workspace-
scoped workspaceState but modeApiConfigs are in global secrets, this caused
cross-workspace data destruction.

Replaced with read-time guards:
- handleModeSwitch: early return when lock is on (skip per-mode config load)
- createTaskWithHistoryItem: skip mode-based config restoration under lock
- activateProviderProfile: removed fan-out block
- lockApiConfigAcrossModes handler: simplified to flag + state post only
- Fixed pre-existing workspaceState mock gap in ClineProvider.spec.ts and
  ClineProvider.sticky-profile.spec.ts

* fix: validate Gemini thinkingLevel against model capabilities and handle empty streams (#11303)

* fix: validate Gemini thinkingLevel against model capabilities and handle empty streams

getGeminiReasoning() now validates the selected effort against the model's
supportsReasoningEffort array before sending it as thinkingLevel. When a
stale settings value (e.g. 'medium' from a different model) is not in the
supported set, it falls back to the model's default reasoningEffort.

GeminiHandler.createMessage() now tracks whether any text content was
yielded during streaming and handles NoOutputGeneratedError gracefully
instead of surfacing the cryptic 'No output generated' error.

* fix: guard thinkingLevel fallback against 'none' effort and add i18n TODO

The array validation fallback in getGeminiReasoning() now only triggers
when the selected effort IS a valid Gemini thinking level but not in
the model's supported set. Values like 'none' (explicit no-reasoning
signal) are no longer overridden by the model default.

Also adds a TODO for moving the empty-stream message to i18n.

* fix: track tool_call_start in hasContent to avoid false empty-stream warning

Tool-only responses (no text) are valid content. Without this,
agentic tool-call responses would incorrectly trigger the empty
response warning message.

* chore(cli): prepare release v0.0.53 (#11425)

* feat: add GLM-5 model support to Z.ai provider (#11440)

* chore: regenerate pnpm-lock.yaml

* fix: resolve type errors and remove AI SDK test contamination

* docs: update progress.txt with rebuilt Batch 2 status

---------

Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com>
Co-authored-by: Roo Code <roomote@roocode.com>
Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com>
Co-authored-by: Chris Estreich <cestreich@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:40:07 -07:00
..
docs Add back post-revert bug fixes and features (Step 2) (#11463) 2026-02-13 18:40:28 -05:00
scripts Add back post-revert bug fixes and features (Step 2) (#11463) 2026-02-13 18:40:28 -05:00
src Reapply Batch 1: 22 clean non-AI-SDK cherry-picks (#11473) 2026-02-14 13:47:12 -07:00
CHANGELOG.md Reapply Batch 2: 9 minor-conflict non-AI-SDK cherry-picks (#11474) 2026-02-14 16:40:07 -07:00
eslint.config.mjs VSCode shim + basic cli (#10452) 2026-01-05 10:24:05 -08:00
install.sh Add back post-revert bug fixes and features (Step 2) (#11463) 2026-02-13 18:40:28 -05:00
package.json Reapply Batch 2: 9 minor-conflict non-AI-SDK cherry-picks (#11474) 2026-02-14 16:40:07 -07:00
README.md Add back post-revert bug fixes and features (Step 2) (#11463) 2026-02-13 18:40:28 -05:00
tsconfig.json More file organization for the cli (#10599) 2026-01-09 23:22:51 -08:00
tsup.config.ts Revert to pre-AI-SDK state (January 29, 2026) (#11462) 2026-02-13 16:45:18 -05:00
vitest.config.ts More file organization for the cli (#10599) 2026-01-09 23:22:51 -08:00

@roo-code/cli

Command Line Interface for Roo Code - Run the Roo Code agent from the terminal without VSCode.

Overview

This CLI uses the @roo-code/vscode-shim package to provide a VSCode API compatibility layer, allowing the main Roo Code extension to run in a Node.js environment.

Installation

Install the Roo Code CLI with a single command:

curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh

Requirements:

  • Node.js 20 or higher
  • macOS Apple Silicon (M1/M2/M3/M4) or Linux x64

Custom installation directory:

ROO_INSTALL_DIR=/opt/roo-code ROO_BIN_DIR=/usr/local/bin curl -fsSL ... | sh

Install a specific version:

ROO_VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh

Updating

Re-run the install script to update to the latest version:

curl -fsSL https://raw.githubusercontent.com/RooCodeInc/Roo-Code/main/apps/cli/install.sh | sh

Uninstalling

rm -rf ~/.roo/cli ~/.local/bin/roo

Development Installation

For contributing or development:

# From the monorepo root.
pnpm install

# Build the main extension first.
pnpm --filter roo-cline bundle

# Build the cli.
pnpm --filter @roo-code/cli build

Usage

Interactive Mode (Default)

By default, the CLI auto-approves actions and runs in interactive TUI mode:

export OPENROUTER_API_KEY=sk-or-v1-...

roo "What is this project?" -w ~/Documents/my-project

You can also run without a prompt and enter it interactively in TUI mode:

roo -w ~/Documents/my-project

In interactive mode:

  • 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

Approval-Required Mode (--require-approval)

If you want manual approval prompts, enable approval-required mode:

roo "Refactor the utils.ts file" --require-approval -w ~/Documents/my-project

In approval-required mode:

  • Tool, command, browser, and MCP actions prompt for yes/no approval
  • Followup questions wait for manual input (no auto-timeout)

Roo Code Cloud Authentication

To use Roo Code Cloud features (like the provider proxy), you need to authenticate:

# Log in to Roo Code Cloud (opens browser)
roo auth login

# Check authentication status
roo auth status

# Log out
roo auth logout

The auth login command:

  1. Opens your browser to authenticate with Roo Code Cloud
  2. Receives a secure token via localhost callback
  3. Stores the token in ~/.config/roo/credentials.json

Tokens are valid for 90 days. The CLI will prompt you to re-authenticate when your token expires.

Authentication Flow:

┌──────┐         ┌─────────┐         ┌───────────────┐
│  CLI │         │ Browser │         │ Roo Code Cloud│
└──┬───┘         └────┬────┘         └───────┬───────┘
   │                  │                      │
   │ Open auth URL    │                      │
   │─────────────────>│                      │
   │                  │                      │
   │                  │ Authenticate         │
   │                  │─────────────────────>│
   │                  │                      │
   │                  │<─────────────────────│
   │                  │ Token via callback   │
   │<─────────────────│                      │
   │                  │                      │
   │ Store token      │                      │
   │                  │                      │

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
-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

Command Description
roo auth login Authenticate with Roo Code Cloud
roo auth logout Clear stored authentication token
roo auth status Show current authentication status

Environment Variables

The CLI will look for API keys in environment variables if not provided via --api-key:

Provider Environment Variable
roo ROO_API_KEY
anthropic ANTHROPIC_API_KEY
openai-native OPENAI_API_KEY
openrouter OPENROUTER_API_KEY
gemini GOOGLE_API_KEY
vercel-ai-gateway VERCEL_AI_GATEWAY_API_KEY

Authentication Environment Variables:

Variable Description
ROO_WEB_APP_URL Override the Roo Code Cloud URL (default: https://app.roocode.com)

Architecture

┌─────────────────┐
│   CLI Entry     │
│   (index.ts)    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  ExtensionHost  │
│  (extension-    │
│   host.ts)      │
└────────┬────────┘
         │
    ┌────┴────┐
    │         │
    ▼         ▼
┌───────┐  ┌──────────┐
│vscode │  │Extension │
│-shim  │  │ Bundle   │
└───────┘  └──────────┘

How It Works

  1. CLI Entry Point (index.ts): Parses command line arguments and initializes the ExtensionHost

  2. ExtensionHost (extension-host.ts):

    • Creates a VSCode API mock using @roo-code/vscode-shim
    • Intercepts require('vscode') to return the mock
    • Loads and activates the extension bundle
    • Manages bidirectional message flow
  3. Message Flow:

    • CLI → Extension: emit("webviewMessage", {...})
    • Extension → CLI: emit("extensionWebviewMessage", {...})

Development

# Run directly from source (no build required)
pnpm dev --provider roo --api-key $ROO_API_KEY --print "Hello"

# Run tests
pnpm test

# Type checking
pnpm check-types

# Linting
pnpm lint

By default the start script points ROO_CODE_PROVIDER_URL at http://localhost:8080/proxy for local development. To point at the production API instead, override the environment variable:

ROO_CODE_PROVIDER_URL=https://api.roocode.com/proxy pnpm dev --provider roo --api-key $ROO_API_KEY --print "Hello"

Releasing

Official releases are created via the GitHub Actions workflow at .github/workflows/cli-release.yml.

To trigger a release:

  1. Go to ActionsCLI Release
  2. Click Run workflow
  3. Optionally specify a version (defaults to package.json version)
  4. Click Run workflow

The workflow will:

  1. Build the CLI on all platforms (macOS Apple Silicon, Linux x64)
  2. Create platform-specific tarballs with bundled ripgrep
  3. Verify each tarball
  4. Create a GitHub release with all tarballs attached

Local Builds

For local development and testing, use the build script:

# Build tarball for your current platform
./apps/cli/scripts/build.sh

# Build and install locally
./apps/cli/scripts/build.sh --install

# Fast build (skip verification)
./apps/cli/scripts/build.sh --skip-verify