mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 14:52:09 +03:00
Merge PR #2280: feat(cli): CLI v4 — Commander.js, 50+ commands, TUI, i18n, plugins (Phases 0-9)
Complete rewrite of the OmniRoute CLI: - Commander.js-based modular architecture (50+ command files) - Full i18n support (en + pt-BR, 1222 keys each) - TUI interactive interface (OAuthFlow, EvalWatch, ProvidersTestAll) - Plugin system (omniroute-cmd-*) - OpenAPI codegen (omniroute api <tag> <op>) - Commands: serve, combo, compression, keys, tunnel, backup, test-provider, health, memory, MCP, A2A, oauth, skills, webhooks, usage, cost, eval, context-eng, dashboard, doctor, env, files, logs, models, nodes, oneproxy, open, openapi, plugin, policy, pricing, providers, quota, registry, repl, reset-encrypted-columns, resilience, restart, runtime, sessions, setup, simulate, status, stop, stream, sync, tags, telemetry, translator, tray, update - Code review fixes: C1-C3, I1-I5, M1-M4 applied # Conflicts: # bin/cli/commands/config.mjs # bin/omniroute.mjs # package-lock.json # package.json
This commit is contained in:
@@ -1,492 +0,0 @@
|
||||
# CLI Tools Setup Guide — OmniRoute
|
||||
|
||||
This guide explains how to install and configure all supported AI coding CLI tools
|
||||
to use **OmniRoute** as the unified backend, giving you centralized key management,
|
||||
cost tracking, model switching, and request logging across every tool.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
Claude / Codex / OpenCode / Cline / KiloCode / Continue / Kiro / Cursor / Copilot
|
||||
│
|
||||
▼ (all point to OmniRoute)
|
||||
http://YOUR_SERVER:20128/v1
|
||||
│
|
||||
▼ (OmniRoute routes to the right provider)
|
||||
Anthropic / OpenAI / Gemini / DeepSeek / Groq / Mistral / ...
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- One API key to manage all tools
|
||||
- Cost tracking across all CLIs in the dashboard
|
||||
- Model switching without reconfiguring every tool
|
||||
- Works locally and on remote servers (VPS)
|
||||
|
||||
---
|
||||
|
||||
## Supported Tools (Dashboard Source of Truth)
|
||||
|
||||
The dashboard cards in `/dashboard/cli-tools` are generated from `src/shared/constants/cliTools.ts`.
|
||||
Current list (v3.0.0-rc.16):
|
||||
|
||||
| Tool | ID | Command | Setup Mode | Install Method |
|
||||
| ------------------ | ------------- | ---------- | ---------- | -------------- |
|
||||
| **Claude Code** | `claude` | `claude` | env | npm |
|
||||
| **OpenAI Codex** | `codex` | `codex` | custom | npm |
|
||||
| **Factory Droid** | `droid` | `droid` | custom | bundled/CLI |
|
||||
| **OpenClaw** | `openclaw` | `openclaw` | custom | bundled/CLI |
|
||||
| **Cursor** | `cursor` | app | guide | desktop app |
|
||||
| **Cline** | `cline` | `cline` | custom | npm |
|
||||
| **Kilo Code** | `kilo` | `kilocode` | custom | npm |
|
||||
| **Continue** | `continue` | extension | guide | VS Code |
|
||||
| **Antigravity** | `antigravity` | internal | mitm | OmniRoute |
|
||||
| **GitHub Copilot** | `copilot` | extension | custom | VS Code |
|
||||
| **OpenCode** | `opencode` | `opencode` | guide | npm |
|
||||
| **Kiro AI** | `kiro` | app/cli | mitm | desktop/CLI |
|
||||
| **Qwen Code** | `qwen` | `qwen` | custom | npm |
|
||||
|
||||
### CLI fingerprint sync (Agents + Settings)
|
||||
|
||||
`/dashboard/agents` and `Settings > CLI Fingerprint` use `src/shared/constants/cliCompatProviders.ts`.
|
||||
This keeps provider IDs aligned with CLI cards and legacy IDs.
|
||||
|
||||
| CLI ID | Fingerprint Provider ID |
|
||||
| ---------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| `kilo` | `kilocode` |
|
||||
| `copilot` | `github` |
|
||||
| `claude` / `codex` / `antigravity` / `kiro` / `cursor` / `cline` / `opencode` / `droid` / `openclaw` | same ID |
|
||||
|
||||
Legacy IDs still accepted for compatibility: `copilot`, `kimi-coding`, `qwen`.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Get an OmniRoute API Key
|
||||
|
||||
1. Open the OmniRoute dashboard → **API Manager** (`/dashboard/api-manager`)
|
||||
2. Click **Create API Key**
|
||||
3. Give it a name (e.g. `cli-tools`) and select all permissions
|
||||
4. Copy the key — you'll need it for every CLI below
|
||||
|
||||
> Your key looks like: `sk-xxxxxxxxxxxxxxxx-xxxxxxxxx`
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Install CLI Tools
|
||||
|
||||
All npm-based tools require Node.js 18+:
|
||||
|
||||
```bash
|
||||
# Claude Code (Anthropic)
|
||||
npm install -g @anthropic-ai/claude-code
|
||||
|
||||
# OpenAI Codex
|
||||
npm install -g @openai/codex
|
||||
|
||||
# OpenCode
|
||||
npm install -g opencode-ai
|
||||
|
||||
# Cline
|
||||
npm install -g cline
|
||||
|
||||
# KiloCode
|
||||
npm install -g kilocode
|
||||
|
||||
# Kiro CLI (Amazon — requires curl + unzip)
|
||||
apt-get install -y unzip # on Debian/Ubuntu
|
||||
curl -fsSL https://cli.kiro.dev/install | bash
|
||||
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc
|
||||
```
|
||||
|
||||
**Verify:**
|
||||
|
||||
```bash
|
||||
claude --version # 2.x.x
|
||||
codex --version # 0.x.x
|
||||
opencode --version # x.x.x
|
||||
cline --version # 2.x.x
|
||||
kilocode --version # x.x.x (or: kilo --version)
|
||||
kiro-cli --version # 1.x.x
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Set Global Environment Variables
|
||||
|
||||
Add to `~/.bashrc` (or `~/.zshrc`), then run `source ~/.bashrc`:
|
||||
|
||||
```bash
|
||||
# OmniRoute Universal Endpoint
|
||||
export OPENAI_BASE_URL="http://localhost:20128/v1"
|
||||
export OPENAI_API_KEY="sk-your-omniroute-key"
|
||||
export ANTHROPIC_BASE_URL="http://localhost:20128"
|
||||
export ANTHROPIC_AUTH_TOKEN="sk-your-omniroute-key"
|
||||
export GEMINI_BASE_URL="http://localhost:20128/v1"
|
||||
export GEMINI_API_KEY="sk-your-omniroute-key"
|
||||
```
|
||||
|
||||
> For a **remote server** replace `localhost:20128` with the server IP or domain,
|
||||
> e.g. `http://192.168.0.15:20128`.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Configure Each Tool
|
||||
|
||||
### Claude Code
|
||||
|
||||
```bash
|
||||
# Create ~/.claude/settings.json:
|
||||
mkdir -p ~/.claude && cat > ~/.claude/settings.json << EOF
|
||||
{
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "http://localhost:20128",
|
||||
"ANTHROPIC_AUTH_TOKEN": "sk-your-omniroute-key"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Use the unified Anthropic gateway root for Claude Code. Do not append `/v1` here.
|
||||
|
||||
**Test:** `claude "say hello"`
|
||||
|
||||
---
|
||||
|
||||
### OpenAI Codex
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.codex && cat > ~/.codex/config.yaml << EOF
|
||||
model: auto
|
||||
apiKey: sk-your-omniroute-key
|
||||
apiBaseUrl: http://localhost:20128/v1
|
||||
EOF
|
||||
```
|
||||
|
||||
**Test:** `codex "what is 2+2?"`
|
||||
|
||||
---
|
||||
|
||||
### OpenCode
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode && cat > ~/.config/opencode/config.toml << EOF
|
||||
[provider.openai]
|
||||
base_url = "http://localhost:20128/v1"
|
||||
api_key = "sk-your-omniroute-key"
|
||||
EOF
|
||||
```
|
||||
|
||||
**Test:** `opencode`
|
||||
|
||||
---
|
||||
|
||||
### Cline (CLI or VS Code)
|
||||
|
||||
**CLI mode:**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.cline/data && cat > ~/.cline/data/globalState.json << EOF
|
||||
{
|
||||
"apiProvider": "openai",
|
||||
"openAiBaseUrl": "http://localhost:20128/v1",
|
||||
"openAiApiKey": "sk-your-omniroute-key"
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**VS Code mode:**
|
||||
Cline extension settings → API Provider: `OpenAI Compatible` → Base URL: `http://localhost:20128/v1`
|
||||
|
||||
Or use the OmniRoute dashboard → **CLI Tools → Cline → Apply Config**.
|
||||
|
||||
---
|
||||
|
||||
### KiloCode (CLI or VS Code)
|
||||
|
||||
**CLI mode:**
|
||||
|
||||
```bash
|
||||
kilocode --api-base http://localhost:20128/v1 --api-key sk-your-omniroute-key
|
||||
```
|
||||
|
||||
**VS Code settings:**
|
||||
|
||||
```json
|
||||
{
|
||||
"kilo-code.openAiBaseUrl": "http://localhost:20128/v1",
|
||||
"kilo-code.apiKey": "sk-your-omniroute-key"
|
||||
}
|
||||
```
|
||||
|
||||
Or use the OmniRoute dashboard → **CLI Tools → KiloCode → Apply Config**.
|
||||
|
||||
---
|
||||
|
||||
### Continue (VS Code Extension)
|
||||
|
||||
Edit `~/.continue/config.yaml`:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: OmniRoute
|
||||
provider: openai
|
||||
model: auto
|
||||
apiBase: http://localhost:20128/v1
|
||||
apiKey: sk-your-omniroute-key
|
||||
default: true
|
||||
```
|
||||
|
||||
Restart VS Code after editing.
|
||||
|
||||
---
|
||||
|
||||
### Kiro CLI (Amazon)
|
||||
|
||||
```bash
|
||||
# Login to your AWS/Kiro account:
|
||||
kiro-cli login
|
||||
|
||||
# The CLI uses its own auth — OmniRoute is not needed as backend for Kiro CLI itself.
|
||||
# Use kiro-cli alongside OmniRoute for other tools.
|
||||
kiro-cli status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Qwen Code (Alibaba)
|
||||
|
||||
Qwen Code supports OpenAI-compatible API endpoints via environment variables or `settings.json`.
|
||||
|
||||
**Option 1: Environment variables (`~/.qwen/.env`)**
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.qwen && cat > ~/.qwen/.env << EOF
|
||||
OPENAI_API_KEY="sk-your-omniroute-key"
|
||||
OPENAI_BASE_URL="http://localhost:20128/v1"
|
||||
OPENAI_MODEL="auto"
|
||||
EOF
|
||||
```
|
||||
|
||||
**Option 2: `settings.json` with model providers**
|
||||
|
||||
```json
|
||||
// ~/.qwen/settings.json
|
||||
{
|
||||
"env": {
|
||||
"OPENAI_API_KEY": "sk-your-omniroute-key",
|
||||
"OPENAI_BASE_URL": "http://localhost:20128/v1"
|
||||
},
|
||||
"modelProviders": {
|
||||
"openai": [
|
||||
{
|
||||
"id": "omniroute-default",
|
||||
"name": "OmniRoute (Auto)",
|
||||
"envKey": "OPENAI_API_KEY",
|
||||
"baseUrl": "http://localhost:20128/v1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Option 3: Inline CLI flags**
|
||||
|
||||
```bash
|
||||
OPENAI_BASE_URL="http://localhost:20128/v1" \
|
||||
OPENAI_API_KEY="sk-your-omniroute-key" \
|
||||
OPENAI_MODEL="auto" \
|
||||
qwen
|
||||
```
|
||||
|
||||
> For a **remote server** replace `localhost:20128` with the server IP or domain.
|
||||
|
||||
**Test:** `qwen "say hello"`
|
||||
|
||||
### Cursor (Desktop App)
|
||||
|
||||
> **Note:** Cursor routes requests through its cloud. For OmniRoute integration,
|
||||
> enable **Cloud Endpoint** in OmniRoute Settings and use your public domain URL.
|
||||
|
||||
Via GUI: **Settings → Models → OpenAI API Key**
|
||||
|
||||
- Base URL: `https://your-domain.com/v1`
|
||||
- API Key: your OmniRoute key
|
||||
|
||||
---
|
||||
|
||||
## Dashboard Auto-Configuration
|
||||
|
||||
The OmniRoute dashboard automates configuration for most tools:
|
||||
|
||||
1. Go to `http://localhost:20128/dashboard/cli-tools`
|
||||
2. Expand any tool card
|
||||
3. Select your API key from the dropdown
|
||||
4. Click **Apply Config** (if tool is detected as installed)
|
||||
5. Or copy the generated config snippet manually
|
||||
|
||||
---
|
||||
|
||||
## Built-in Agents: Droid & OpenClaw
|
||||
|
||||
**Droid** and **OpenClaw** are AI agents built directly into OmniRoute — no installation needed.
|
||||
They run as internal routes and use OmniRoute's model routing automatically.
|
||||
|
||||
- Access: `http://localhost:20128/dashboard/agents`
|
||||
- Configure: same combos and providers as all other tools
|
||||
- No API key or CLI install required
|
||||
|
||||
---
|
||||
|
||||
## Available API Endpoints
|
||||
|
||||
| Endpoint | Description | Use For |
|
||||
| -------------------------- | ----------------------------- | --------------------------- |
|
||||
| `/v1/chat/completions` | Standard chat (all providers) | All modern tools |
|
||||
| `/v1/responses` | Responses API (OpenAI format) | Codex, agentic workflows |
|
||||
| `/v1/completions` | Legacy text completions | Older tools using `prompt:` |
|
||||
| `/v1/embeddings` | Text embeddings | RAG, search |
|
||||
| `/v1/images/generations` | Image generation | GPT-Image, Flux, etc. |
|
||||
| `/v1/audio/speech` | Text-to-speech | ElevenLabs, OpenAI TTS |
|
||||
| `/v1/audio/transcriptions` | Speech-to-text | Deepgram, AssemblyAI |
|
||||
|
||||
### CLI Tools API (New in v3.8)
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
| ------------------------------- | ------ | ------------------------------------------------ |
|
||||
| `/api/cli-tools/detect` | GET | Detect all installed CLI tools and config status |
|
||||
| `/api/cli-tools/detect?tool=ID` | GET | Detect a specific tool by ID |
|
||||
| `/api/cli-tools/config` | GET | List generated configs for all tools |
|
||||
| `/api/cli-tools/config` | POST | Generate config for a specific tool |
|
||||
| `/api/cli-tools/apply` | POST | Apply config to a tool (with backup) |
|
||||
|
||||
---
|
||||
|
||||
## CLI Commands Reference (New in v3.8)
|
||||
|
||||
### `omniroute config`
|
||||
|
||||
Manage CLI tool configurations directly from the terminal.
|
||||
|
||||
```bash
|
||||
omniroute config list # List all tools and config status
|
||||
omniroute config get <tool> # Show config for a specific tool
|
||||
omniroute config set <tool> \ # Generate and write config
|
||||
--api-key sk-your-key \
|
||||
[--base-url http://localhost:20128/v1] \
|
||||
[--model auto]
|
||||
omniroute config validate <tool> # Validate config without writing
|
||||
```
|
||||
|
||||
**Options:** `--base-url`, `--api-key`, `--model`, `--json`, `--non-interactive`, `--yes`, `--help`
|
||||
|
||||
### `omniroute status`
|
||||
|
||||
Show offline status dashboard with version, database, and tool info.
|
||||
|
||||
```bash
|
||||
omniroute status # Human-readable status
|
||||
omniroute status --json # JSON output
|
||||
omniroute status --verbose # Include tool detection details
|
||||
```
|
||||
|
||||
### `omniroute logs`
|
||||
|
||||
Stream usage logs from the API endpoint.
|
||||
|
||||
```bash
|
||||
omniroute logs # Fetch last 100 log lines
|
||||
omniroute logs --follow # Stream in real-time
|
||||
omniroute logs --filter error,warn # Filter by level
|
||||
omniroute logs --lines 500 # Fetch more lines
|
||||
omniroute logs --base-url http://localhost:20128
|
||||
```
|
||||
|
||||
**Options:** `--follow`, `--filter`, `--lines`, `--timeout`, `--base-url`, `--json`, `--help`
|
||||
|
||||
### `omniroute update`
|
||||
|
||||
Check for or apply OmniRoute updates.
|
||||
|
||||
```bash
|
||||
omniroute update --check # Check for updates only
|
||||
omniroute update --dry-run # Preview update without applying
|
||||
omniroute update --yes # Apply update without prompt
|
||||
omniroute update --no-backup # Skip backup creation
|
||||
```
|
||||
|
||||
**Options:** `--check`, `--dry-run`, `--backup`, `--no-backup`, `--yes`, `--help`
|
||||
|
||||
### `omniroute provider`
|
||||
|
||||
Manage provider connections from the CLI.
|
||||
|
||||
```bash
|
||||
omniroute provider add openai --api-key sk-xxx # Add a provider
|
||||
omniroute provider list # List all providers
|
||||
omniroute provider remove <name|id> # Remove a provider
|
||||
omniroute provider test <name|id> # Test connectivity
|
||||
omniroute provider default <name|id> # Set default provider
|
||||
```
|
||||
|
||||
**Options:** `--provider`, `--api-key`, `--provider-name`, `--default-model`, `--base-url`, `--json`, `--yes`, `--help`
|
||||
|
||||
---
|
||||
|
||||
## Quick Setup Script (One Command)
|
||||
|
||||
Set up all CLI tools and configure for OmniRoute:
|
||||
|
||||
```bash
|
||||
OMNIROUTE_URL="http://localhost:20128/v1"
|
||||
OMNIROUTE_ANTHROPIC_URL="http://localhost:20128"
|
||||
OMNIROUTE_KEY="sk-your-omniroute-key"
|
||||
|
||||
npm install -g @anthropic-ai/claude-code @openai/codex opencode-ai cline kilocode @qwen-code/qwen-code
|
||||
|
||||
# Kiro CLI
|
||||
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
|
||||
|
||||
# Write configs
|
||||
mkdir -p ~/.claude ~/.codex ~/.config/opencode ~/.continue
|
||||
|
||||
cat > ~/.claude/settings.json <<< "{\"env\":{\"ANTHROPIC_BASE_URL\":\"$OMNIROUTE_ANTHROPIC_URL\",\"ANTHROPIC_AUTH_TOKEN\":\"$OMNIROUTE_KEY\"}}"
|
||||
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
|
||||
cat >> ~/.bashrc << EOF
|
||||
export OPENAI_BASE_URL="$OMNIROUTE_URL"
|
||||
export OPENAI_API_KEY="$OMNIROUTE_KEY"
|
||||
export ANTHROPIC_BASE_URL="$OMNIROUTE_ANTHROPIC_URL"
|
||||
export ANTHROPIC_AUTH_TOKEN="$OMNIROUTE_KEY"
|
||||
EOF
|
||||
|
||||
source ~/.bashrc
|
||||
echo "✅ All CLIs installed and configured for OmniRoute"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Install all CLIs and configure for OmniRoute (replace with your key and server URL)
|
||||
OMNIROUTE_URL="http://localhost:20128/v1"
|
||||
OMNIROUTE_ANTHROPIC_URL="http://localhost:20128"
|
||||
OMNIROUTE_KEY="sk-your-omniroute-key"
|
||||
|
||||
npm install -g @anthropic-ai/claude-code @openai/codex opencode-ai cline kilocode @qwen-code/qwen-code
|
||||
|
||||
# Kiro CLI
|
||||
apt-get install -y unzip 2>/dev/null; curl -fsSL https://cli.kiro.dev/install | bash
|
||||
|
||||
# Write configs
|
||||
mkdir -p ~/.claude ~/.codex ~/.config/opencode ~/.continue
|
||||
|
||||
cat > ~/.claude/settings.json <<< "{\"env\":{\"ANTHROPIC_BASE_URL\":\"$OMNIROUTE_ANTHROPIC_URL\",\"ANTHROPIC_AUTH_TOKEN\":\"$OMNIROUTE_KEY\"}}"
|
||||
cat > ~/.codex/config.yaml <<< "model: auto\napiKey: $OMNIROUTE_KEY\napiBaseUrl: $OMNIROUTE_URL"
|
||||
cat >> ~/.bashrc << EOF
|
||||
export OPENAI_BASE_URL="$OMNIROUTE_URL"
|
||||
export OPENAI_API_KEY="$OMNIROUTE_KEY"
|
||||
export ANTHROPIC_BASE_URL="$OMNIROUTE_ANTHROPIC_URL"
|
||||
export ANTHROPIC_AUTH_TOKEN="$OMNIROUTE_KEY"
|
||||
EOF
|
||||
|
||||
source ~/.bashrc
|
||||
echo "✅ All CLIs installed and configured for OmniRoute"
|
||||
```
|
||||
@@ -568,23 +568,22 @@ bin/
|
||||
├── omniroute.mjs Main CLI entry (Node ESM)
|
||||
├── reset-password.mjs Reset the management password from CLI
|
||||
├── mcp-server.mjs MCP server launcher (stdio)
|
||||
├── cli-commands.mjs Command dispatcher
|
||||
├── nodeRuntimeSupport.mjs Node version guard
|
||||
└── cli/
|
||||
├── index.mjs
|
||||
├── args.mjs
|
||||
├── program.mjs Commander program builder
|
||||
├── runtime.mjs withRuntime helper (server-first/db-fallback)
|
||||
├── output.mjs Output formatters (json/jsonl/table/csv)
|
||||
├── i18n.mjs t() helper with locales
|
||||
├── api.mjs API fetch helper
|
||||
├── data-dir.mjs
|
||||
├── encryption.mjs
|
||||
├── io.mjs
|
||||
├── provider-catalog.mjs
|
||||
├── provider-store.mjs
|
||||
├── provider-test.mjs
|
||||
├── settings-store.mjs
|
||||
├── sqlite.mjs
|
||||
└── commands/
|
||||
├── registry.mjs Command registration
|
||||
├── setup.mjs
|
||||
├── doctor.mjs
|
||||
└── providers.mjs
|
||||
├── providers.mjs
|
||||
└── ... (one file per command/group)
|
||||
```
|
||||
|
||||
Two binaries are exposed in `package.json` → `bin`:
|
||||
|
||||
108
docs/dev/plugins.md
Normal file
108
docs/dev/plugins.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# OmniRoute CLI Plugin System
|
||||
|
||||
Extend the `omniroute` CLI without modifying its core. Plugins follow the `omniroute-cmd-*` naming convention, similar to `gh extension` or `kubectl plugin`.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# Install a plugin from npm
|
||||
omniroute plugin install stripe
|
||||
|
||||
# Install a local plugin in development
|
||||
omniroute plugin install ./my-plugin
|
||||
|
||||
# List installed plugins
|
||||
omniroute plugin list
|
||||
|
||||
# Scaffold a new plugin
|
||||
omniroute plugin scaffold myplugin
|
||||
cd omniroute-cmd-myplugin
|
||||
omniroute plugin install .
|
||||
```
|
||||
|
||||
## Plugin anatomy
|
||||
|
||||
A plugin is an npm package named `omniroute-cmd-<name>` (or `@scope/omniroute-cmd-<name>`).
|
||||
|
||||
```
|
||||
omniroute-cmd-myplugin/
|
||||
├── package.json # must have "type": "module" and "main": "index.mjs"
|
||||
├── index.mjs # exports register(program, ctx) + optional meta
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "omniroute-cmd-myplugin",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"main": "index.mjs",
|
||||
"engines": { "omniroute": ">=4.0.0" },
|
||||
"keywords": ["omniroute-plugin", "omniroute-cmd"]
|
||||
}
|
||||
```
|
||||
|
||||
### `index.mjs`
|
||||
|
||||
```js
|
||||
export const meta = {
|
||||
name: "myplugin",
|
||||
version: "0.1.0",
|
||||
description: "My plugin for OmniRoute",
|
||||
omnirouteApi: ">=4.0.0",
|
||||
};
|
||||
|
||||
export function register(program, ctx) {
|
||||
program
|
||||
.command("myplugin")
|
||||
.description(meta.description)
|
||||
.option("-n, --name <name>")
|
||||
.action(async (opts, cmd) => {
|
||||
const gOpts = cmd.optsWithGlobals();
|
||||
const res = await ctx.apiFetch("/api/combos", {
|
||||
baseUrl: gOpts.baseUrl,
|
||||
apiKey: gOpts.apiKey,
|
||||
});
|
||||
const data = await res.json();
|
||||
ctx.emit(data, gOpts);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Plugin context API
|
||||
|
||||
The `ctx` object passed to `register(program, ctx)`:
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------------------------- | ---------------- | -------------------------------------------------- |
|
||||
| `ctx.apiFetch(path, opts)` | `async function` | Authenticated fetch to the OmniRoute server |
|
||||
| `ctx.emit(data, opts)` | `function` | Output in table/json/jsonl/csv per `--output` flag |
|
||||
| `ctx.t(key)` | `async function` | i18n translation lookup |
|
||||
| `ctx.withSpinner(label, fn)` | `async function` | Wraps async fn with ora spinner |
|
||||
| `ctx.baseUrl` | `string` | Resolved base URL |
|
||||
| `ctx.apiKey` | `string \| null` | API key if provided |
|
||||
|
||||
## Discovery
|
||||
|
||||
Plugins are discovered from:
|
||||
|
||||
1. `~/.omniroute/plugins/<name>/` — user-local installs
|
||||
2. `OMNIROUTE_PLUGIN_PATH` env var — custom directory
|
||||
|
||||
Loading errors are caught and printed as warnings — a broken plugin never crashes the CLI.
|
||||
|
||||
## Security
|
||||
|
||||
Plugins run with the same Node.js process privileges as `omniroute`. Only install plugins from sources you trust. `omniroute plugin install` shows an explicit warning and requires `--yes` or interactive confirmation.
|
||||
|
||||
## Publishing
|
||||
|
||||
1. Ensure `package.json` has `"keywords": ["omniroute-plugin"]`
|
||||
2. `npm publish` as normal
|
||||
3. Users discover via `omniroute plugin search <query>` (searches npm registry)
|
||||
|
||||
## Example plugin
|
||||
|
||||
See [`examples/omniroute-cmd-hello/`](../../examples/omniroute-cmd-hello/) for a minimal working example.
|
||||
@@ -41,9 +41,8 @@ Claude / Codex / OpenCode / Cline / KiloCode / Continue / Cursor / Windsurf / He
|
||||
### Source of Truth
|
||||
|
||||
The dashboard cards in `/dashboard/cli-tools` are generated from
|
||||
`src/shared/constants/cliTools.ts`. The internal helper `bin/cli-commands.mjs`
|
||||
keeps the small set of "fully scriptable" tools that `omniroute setup` can write
|
||||
config files for automatically.
|
||||
`src/shared/constants/cliTools.ts`. The `omniroute setup` command can write
|
||||
config files automatically for the scriptable tools.
|
||||
|
||||
### Current Catalog (v3.8.0)
|
||||
|
||||
@@ -450,15 +449,12 @@ The `omniroute` binary (installed via `npm install -g omniroute` or bundled
|
||||
with the desktop app) provides commands beyond running the server. The full
|
||||
matrix is implemented in:
|
||||
|
||||
- `bin/omniroute.mjs` — entry point and `--help` text
|
||||
- `bin/cli/index.mjs` — dispatcher for the supported subcommands
|
||||
- `bin/cli/commands/setup.mjs`, `bin/cli/commands/doctor.mjs`,
|
||||
`bin/cli/commands/providers.mjs` — the three core subcommands
|
||||
|
||||
Other subcommands listed in `--help` (status, logs, combo, keys, mcp, a2a,
|
||||
tunnel, backup, restore, quota, health, cache, env, completion, dashboard,
|
||||
serve, stop, restart, open, update, test) are wired through
|
||||
`bin/cli-commands.mjs` and require a running server for most of them.
|
||||
- `bin/omniroute.mjs` — entry point, env loading, special-case dispatch (`--mcp`)
|
||||
- `bin/cli/program.mjs` — Commander program builder
|
||||
- `bin/cli/commands/<cmd>.mjs` — one file per command/group, registered in `registry.mjs`
|
||||
- `bin/cli/output.mjs` — output formatters (json/jsonl/table/csv)
|
||||
- `bin/cli/runtime.mjs` — withRuntime helper (server-first/db-fallback)
|
||||
- `bin/cli/i18n.mjs` — t() helper with locales
|
||||
|
||||
### Server Lifecycle
|
||||
|
||||
@@ -541,10 +537,9 @@ omniroute reset-encrypted-columns # Show warning + dry-run for encrypted c
|
||||
omniroute reset-encrypted-columns --force # Actually null out encrypted credentials in SQLite
|
||||
```
|
||||
|
||||
### Other subcommands (via `cli-commands.mjs`)
|
||||
### Other subcommands
|
||||
|
||||
These are dispatched in `bin/cli-commands.mjs` and assume a running OmniRoute
|
||||
server, unless noted otherwise:
|
||||
These assume a running OmniRoute server, unless noted otherwise:
|
||||
|
||||
```bash
|
||||
omniroute status # Comprehensive runtime status
|
||||
|
||||
@@ -295,6 +295,20 @@ CLI_ALLOW_CONFIG_WRITES=true
|
||||
CLI_CLAUDE_BIN=/host-cli/bin/claude
|
||||
```
|
||||
|
||||
### CLI Binary (`omniroute`) helpers
|
||||
|
||||
These variables tune the `omniroute` CLI binary's own behavior (not the sidecar
|
||||
detection above).
|
||||
|
||||
| Variable | Default | Source File | Description |
|
||||
| --------------------------- | ---------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `OMNIROUTE_LANG` | _(system)_ | `bin/cli/i18n.mjs` | Force CLI output language. BCP-47 locale (e.g. `en`, `pt-BR`). Overrides system locale env vars (LC_ALL, LC_MESSAGES). |
|
||||
| `OMNIROUTE_SHOW_LOG` | _(unset)_ | `bin/cli/runtime/processSupervisor.mjs` | Set to `1` to forward server stdout/stderr to the terminal in supervised mode. Equivalent to `--log` flag on `omniroute serve`. |
|
||||
| `OMNIROUTE_CLI_TOKEN` | _(unset)_ | `bin/cli/api.mjs` | Machine-auth token injected as `x-omniroute-cli-token` header. Auto-generated in task 8.12. |
|
||||
| `OMNIROUTE_HTTP_TIMEOUT_MS` | `30000` | `bin/cli/api.mjs` | Per-attempt HTTP timeout (ms) for CLI → server requests. |
|
||||
| `OMNIROUTE_VERBOSE` | `0` | `bin/cli/api.mjs` | Set to `1` to print retry/backoff diagnostics to stderr during CLI commands. |
|
||||
| `OMNIROUTE_PLUGIN_PATH` | _(unset)_ | `bin/cli/plugins.mjs` | Custom directory for CLI plugin discovery (`omniroute-cmd-*` packages). Defaults to `~/.omniroute/plugins/` when unset. |
|
||||
|
||||
---
|
||||
|
||||
## 10. Internal Agent & MCP Integrations
|
||||
|
||||
43
docs/security/CLI_TOKEN_AUTH.md
Normal file
43
docs/security/CLI_TOKEN_AUTH.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# CLI Machine-ID Token Authentication
|
||||
|
||||
OmniRoute's CLI uses a **machine-derived token** to authenticate to the local server without requiring an explicit API key. This enables zero-config local use while preserving security for remote access.
|
||||
|
||||
## How it works
|
||||
|
||||
1. **CLI side** (`bin/cli/utils/cliToken.mjs`): computes `SHA-256(machineId + salt).hex[0..32]` using [`node-machine-id`](https://github.com/automation-stack/node-machine-id) and injects the result as the `x-omniroute-cli-token` header on every `apiFetch` call.
|
||||
|
||||
2. **Server side** (`src/lib/middleware/cliTokenAuth.ts`): `isCliTokenAuthValid(request)` accepts the token only if:
|
||||
- `OMNIROUTE_DISABLE_CLI_TOKEN` is not `"true"`
|
||||
- The header is present and exactly 32 hex characters
|
||||
- The originating IP is loopback (`127.0.0.1`, `::1`, `::ffff:127.0.0.1`)
|
||||
- The token matches the server's own machine-derived hash (timing-safe compare)
|
||||
|
||||
3. `requireManagementAuth` and other route guards call `isCliTokenAuthValid` before checking API keys — so the CLI gets transparent localhost access without storing any credential.
|
||||
|
||||
## Threat model
|
||||
|
||||
| Scenario | Risk | Mitigation |
|
||||
| ------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Another user on same host | Could compute the same token | `machine-id` is per-device; on single-user desktops this is acceptable. Use `OMNIROUTE_DISABLE_CLI_TOKEN=true` in multi-user setups. |
|
||||
| Token leak via logs | Logs may reveal the token | The header value is masked in audit logs (`x-omniroute-cli-token: ***`). |
|
||||
| Replay attack | Token is static | Only accepted from `127.0.0.1`/`::1`. Rejected for any other `x-forwarded-for` IP. |
|
||||
| Reuse on another machine | Machine-bound by design | `node-machine-id` reads `/etc/machine-id` (Linux), `IOPlatformUUID` (macOS), `MachineGuid` (Windows). Different per host. |
|
||||
|
||||
## Opt-out
|
||||
|
||||
Set `OMNIROUTE_DISABLE_CLI_TOKEN=true` in `.env` or the server environment to disable this mechanism entirely. All access then requires an explicit API key.
|
||||
|
||||
## Audit logging
|
||||
|
||||
Every request authenticated via CLI token is logged with `event: "cli_token_auth"`, the source IP, user-agent, path, and the first 8 characters of the machine-id hash (non-reversible).
|
||||
|
||||
## API key precedence
|
||||
|
||||
An explicit `Authorization: Bearer <key>` header (from `--api-key` or `OMNIROUTE_API_KEY`) always takes precedence over the CLI token and is evaluated first.
|
||||
|
||||
## Related files
|
||||
|
||||
- `bin/cli/utils/cliToken.mjs` — CLI token generation
|
||||
- `src/lib/middleware/cliTokenAuth.ts` — server validation
|
||||
- `src/lib/api/requireManagementAuth.ts` — integration into auth pipeline
|
||||
- `tests/unit/cli-machine-token.test.ts` — unit tests
|
||||
Reference in New Issue
Block a user