Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
37d0bde
feat(SecretStorageService): service for mcp hub to store access and r…
edelauna Mar 6, 2026
5128372
feat(callbackServer): used for OAuth 2.1 callbacks
edelauna Mar 6, 2026
288f147
fix(@modelcontextprotocol): overwrites
edelauna Mar 6, 2026
1aa1184
feat(McpOAuthClientProvider): implementing provider to allow OAuth fo…
edelauna Mar 6, 2026
0afa23c
fix(callbackServer): removing reflected xss and updating template
edelauna Mar 7, 2026
3121d36
fix(McpHub): not blocking on authprovider flow
edelauna Mar 7, 2026
8f314c4
refactor(McpOAuthClientProvider): do not default to openid scope
edelauna Mar 11, 2026
240cc81
feat(McpHub): handle OAuth refresh mid tool call
edelauna Mar 11, 2026
c9f981e
fix(McpOAuthClientProvider): refresh token race condition between cli…
edelauna Mar 12, 2026
441deac
feat(McpHub): update OAuth Flow to be opt in and handle concurrent fl…
edelauna Mar 14, 2026
faffb4b
refactor(McpHub): prompt for authentication even mid tool call
edelauna Mar 25, 2026
ab8d12d
refactor(callbackServer): added in i18n translations
edelauna Mar 25, 2026
7c0d0e3
feat(McpHub): cache whether server required OAuth or not
edelauna Mar 27, 2026
b1d44ce
refactor(McpOAuthClientProvider): add TOKEN_EXPIRY_BUFFER
edelauna Mar 27, 2026
f2a3cfb
refactor(SecretStorageService): caching full DCR repose
edelauna Mar 27, 2026
8eb8be9
refactor(McpHub): making prompt long running or dismissable
edelauna Apr 3, 2026
f10d254
feat(McpHub): handling concurrent window auth
edelauna Apr 24, 2026
fda3e98
feat(McpHub): making oauth less disruptive to flow
edelauna Apr 24, 2026
ba5345c
fix(esbuild): sequence rebuild calls to prevent Windows EBUSY race on…
edelauna Apr 24, 2026
a127704
refactor(McpHub): cleanup crosswindow auths
edelauna Apr 24, 2026
b9d2852
refactor(SecretStorageService): base64 encode server endpoints to avo…
edelauna Apr 24, 2026
cde464e
refactor(callbackServer): make cancellable
edelauna Apr 24, 2026
4f62b40
fix(i18n): catalan strings
edelauna Apr 24, 2026
dab4e2c
test(oauth): restoring mocked global
edelauna Apr 24, 2026
f0e1121
feat(McpOAuthClientProvider): adding callback to cancel callback server
edelauna Apr 24, 2026
05b399b
test: feedback
edelauna Apr 24, 2026
7840d03
empty commit for ci
edelauna Apr 26, 2026
04c7580
Remove Roo Code Cloud from extension and CLI
taltas Apr 28, 2026
d8570e4
Remove Roo Code Router remnants and migrations
taltas Apr 28, 2026
caabce3
Fix CloudService compatibility test singleton usage
taltas Apr 28, 2026
f681e03
Update Roo provider tests for compatibility mode
taltas Apr 28, 2026
6fbf91b
Localize router removal messaging
taltas Apr 29, 2026
5c75bf6
Resolve router removal message at runtime
taltas Apr 29, 2026
ac78824
Add issue templates
taltas Apr 30, 2026
ff931da
Merge pull request #5 from Zoo-Code-Org/remove-roo-cloud
taltas Apr 30, 2026
bb46e6c
Rename Roo Code mentions to Zoo Code in English chat locale
taltas Apr 24, 2026
82ef6fb
Update localized chat locales for Zoo Code rebrand
taltas Apr 24, 2026
1cf8019
Update Roo and Roo code to Zoo and Zoo code
taltas Apr 24, 2026
821fd67
chore: update webview locale translations for Zoo rename
taltas Apr 24, 2026
3449809
chore: rename Roo to Zoo in locale files
taltas Apr 25, 2026
2303d00
chore: rename Roo to Zoo in package strings
taltas Apr 25, 2026
94c62e0
Resolve PR #2 locale merge conflicts after rebase
hannesrudolph Apr 30, 2026
04d5082
fix: restore valid locale JSON for translation check
hannesrudolph Apr 30, 2026
539cd95
Merge pull request #2 from Zoo-Code-Org/roo-to-zoo-upgrade
taltas Apr 30, 2026
9260779
Merge pull request #7 from Zoo-Code-Org/issue-templates
taltas Apr 30, 2026
2e3ec13
Merge pull request #1 from Zoo-Code-Org/feat/mcp-oauth-streamable-http
edelauna May 1, 2026
2644752
feat: subscription-gated LLM tool result compression
May 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .github/ISSUE_TEMPLATE/add-provider-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: Add provider model
about: Add a provider model that isn't htere
title: ''
labels: model
assignees: ''
type: Task

---

Name of model: (GPT 5.4)
Model creator: (i.e. Open AI)
Link to model:
34 changes: 34 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] "
labels: bug
assignees: ''
type: Bug

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Video**
Add a video of the incident happening, it will help us debug

**What version of zoo are you running**
i.e. 3.55

**Additional context**
Add any other context about the problem here.
21 changes: 21 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: Feature request
about: What do you want to add to zoo?
title: ''
labels: enhancement
assignees: ''
type: Feature

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
106 changes: 35 additions & 71 deletions apps/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,101 +130,65 @@ printf '{"command":"start","requestId":"1","prompt":"1+1=?"}\n' | roo --print --
printf '{"command":"start","requestId":"1","taskId":"018f7fc8-7c96-7f7c-98aa-2ec4ff7f6d87","prompt":"1+1=?"}\n' | roo --print --stdin-prompt-stream --output-format stream-json
```

### Roo Code Cloud Authentication
### Legacy Roo Auth Token Cleanup

To use Roo Code Cloud features (like the provider proxy), you need to authenticate:
Normal CLI usage is login-free. Use `--provider` with your own API key, or set the provider environment variable directly.

```bash
# Log in to Roo Code Cloud (opens browser)
roo auth login
Roo Code Router has been removed from the CLI. The remaining `auth` commands only help inspect or delete any legacy Roo auth token still stored from older releases:

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

# Log out
# Remove an old stored Roo auth token
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 │ │
│ │ │
```
If you never used Roo Code Router, you can ignore this section entirely.

## 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 |
| `--create-with-session-id <session-id>` | Create a new task using the provided session ID (UUID) | None |
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
| `--stdin-prompt-stream` | Read NDJSON control commands from stdin (requires `--print`) | `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` |
| `--terminal-shell <path>` | Absolute shell path for inline terminal command execution | Auto-detected shell |
| `-r, --reasoning-effort <effort>` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` |
| `--consecutive-mistake-limit <n>` | Consecutive error/repetition limit before guidance prompt (`0` disables the limit) | `10` |
| `--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 |
| `--create-with-session-id <session-id>` | Create a new task using the provided session ID (UUID) | None |
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
| `-p, --print` | Print response and exit (non-interactive mode) | `false` |
| `--stdin-prompt-stream` | Read NDJSON control commands from stdin (requires `--print`) | `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 (anthropic, openai-native, gemini, openrouter, vercel-ai-gateway) | `openrouter` |
| `-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 |
| `-r, --reasoning-effort <effort>` | Reasoning effort level (unspecified, disabled, none, minimal, low, medium, high, xhigh) | `medium` |
| `--consecutive-mistake-limit <n>` | Consecutive error/repetition limit before guidance prompt (`0` disables the limit) | `10` |
| `--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 |
| Command | Description |
| ----------------- | ------------------------------------ |
| `roo auth logout` | Clear a stored legacy Roo auth token |
| `roo auth status` | Show legacy Roo token 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

```
Expand Down Expand Up @@ -268,7 +232,7 @@ The CLI will look for API keys in environment variables if not provided via `--a

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

# Run tests
pnpm test
Expand All @@ -280,10 +244,10 @@ pnpm check-types
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:
By default the dev script still points `ROO_CODE_PROVIDER_URL` at `http://localhost:8080/proxy` for local extension-host development. The CLI provider selection itself should use a non-Router provider such as OpenRouter. To point the backend URL at production instead, override the environment variable:

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

## Releasing
Expand Down
76 changes: 76 additions & 0 deletions apps/cli/src/commands/auth/__tests__/auth-commands.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
vi.mock("@/lib/storage/index.js", () => ({
loadToken: vi.fn(),
loadCredentials: vi.fn(),
getCredentialsPath: vi.fn(() => "/tmp/roo/cli-credentials.json"),
hasToken: vi.fn(),
clearToken: vi.fn(),
}))

vi.mock("@/lib/auth/index.js", () => ({
isTokenExpired: vi.fn(),
isTokenValid: vi.fn(),
getTokenExpirationDate: vi.fn(),
}))

import { status } from "../status.js"
import { logout } from "../logout.js"
import { loadToken, loadCredentials, getCredentialsPath, hasToken, clearToken } from "@/lib/storage/index.js"
import { isTokenExpired, isTokenValid, getTokenExpirationDate } from "@/lib/auth/index.js"

describe("auth commands", () => {
beforeEach(() => {
vi.clearAllMocks()
})

it("reports missing Roo auth tokens as normal for standard CLI usage", async () => {
vi.mocked(loadToken).mockResolvedValue(null)
const consoleLog = vi.spyOn(console, "log").mockImplementation(() => {})

const result = await status()

expect(result).toEqual({ authenticated: false })
expect(consoleLog.mock.calls.flat().join("\n")).toContain("Normal CLI usage does not require login.")
expect(consoleLog.mock.calls.flat().join("\n")).toContain("Roo Code Router has been removed")
})

it("reports optional Roo auth token details when available", async () => {
const token = "header.payload.signature"
const expiresAt = new Date("2026-05-01T00:00:00.000Z")

vi.mocked(loadToken).mockResolvedValue(token)
vi.mocked(loadCredentials).mockResolvedValue({ token, createdAt: "2026-04-01T00:00:00.000Z" })
vi.mocked(isTokenValid).mockReturnValue(true)
vi.mocked(isTokenExpired).mockReturnValue(false)
vi.mocked(getTokenExpirationDate).mockReturnValue(expiresAt)
vi.mocked(getCredentialsPath).mockReturnValue("/tmp/roo/cli-credentials.json")
const consoleLog = vi.spyOn(console, "log").mockImplementation(() => {})

const result = await status({ verbose: true })

expect(result.authenticated).toBe(true)
expect(consoleLog.mock.calls.flat().join("\n")).toContain("Legacy Roo auth token still stored")
expect(consoleLog.mock.calls.flat().join("\n")).toContain("/tmp/roo/cli-credentials.json")
})

it("removes stored Roo auth tokens", async () => {
vi.mocked(hasToken).mockResolvedValue(true)
const consoleLog = vi.spyOn(console, "log").mockImplementation(() => {})

const result = await logout()

expect(result).toEqual({ success: true, wasLoggedIn: true })
expect(clearToken).toHaveBeenCalledTimes(1)
expect(consoleLog.mock.calls.flat().join("\n")).toContain("Removed stored legacy Roo auth token")
})

it("treats missing Roo auth tokens as already logged out", async () => {
vi.mocked(hasToken).mockResolvedValue(false)
const consoleLog = vi.spyOn(console, "log").mockImplementation(() => {})

const result = await logout()

expect(result).toEqual({ success: true, wasLoggedIn: false })
expect(clearToken).not.toHaveBeenCalled()
expect(consoleLog.mock.calls.flat().join("\n")).toContain("No legacy Roo auth token stored.")
})
})
1 change: 0 additions & 1 deletion apps/cli/src/commands/auth/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from "./login.js"
export * from "./logout.js"
export * from "./status.js"
Loading
Loading