diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e5f77b9d4..52fd17a945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,51 +2,81 @@ ## [Unreleased] -### ✨ Added - -- **`@omniroute/opencode-plugin` bundled + `omniroute setup opencode`** ([#3726] β€” thanks @herjarsa): - The opencode-plugin now ships pre-built inside the `omniroute` npm package (`package.json` - `files` includes `@omniroute/`). A new `omniroute setup opencode` CLI command automates - installation: - 1. Copies the bundled plugin into `~/.config/opencode/plugins/omniroute/` - 2. Creates/updates `opencode.json` with the plugin entry (idempotent, - replaces legacy `opencode-omniroute-auth` entries automatically) - 3. Optional `--auth` flag runs `opencode auth login --provider ` - The prepublish pipeline (Step 8.8) now builds the plugin's `dist/` via tsup so every - published tarball includes it. Users no longer need to extract the plugin manually. - -### πŸ› Fixed - -- **`@omniroute/opencode-plugin`: baseURL resolution for partner/tiered providers** - ([#3711] / [#3726] β€” thanks @herjarsa): - The `provider.models` hook now checks `_provider.options.baseURL` (set by the config - hook or opencode.json) as a third fallback after plugin opts and auth.json. Previously, - providers whose baseURL came from options returned zero models. A diagnostic `console.warn` - fires when no baseURL is resolvable from any source. - --- -## [3.8.22] β€” TBD ## [3.8.23] β€” TBD -### πŸ› Bug Fixes +### ✨ New Features -- **Emergency budget fallback no longer leaks the failing provider's API key to the emergency provider** (combo/resilience audit): the executor-level emergency hop in `chatCore` re-sent the FAILING provider's credentials to the emergency provider's endpoint (e.g. the OpenAI key in the `Authorization` header of a request to `integrate.api.nvidia.com`) on every quota/billing error of a non-stream request β€” a cross-provider credential leak that also never succeeded upstream (the foreign key is always rejected). The hop is now orchestrated exclusively by the routing layer (`src/sse/handlers/chat.ts`), which resolves credentials FOR the emergency provider via account selection, and it no longer fires inside combo targets (the combo is the operator's fallback policy; the global fallback #689 still runs after it). Restores the five `#1731` fast-skip integration tests that had been `test.skip`-ed since v3.8.2, plus a new credential-leak guard test. -- **`/v1/messages/count_tokens` now honors the connection's proxy assignment**: the provider-side token count was issued with no proxy context at all β€” every count call went DIRECT to the provider regardless of configured account/provider/global proxies, leaking the host IP for proxy-isolated setups. The route now resolves the connection proxy (`safeResolveProxy`) and wraps the executor call in `runWithProxyContext`, exactly like chat execution. Validated by a new integration test that also pins per-target proxy independence inside combos. -- **Proxy resolution failures are no longer silent**: `safeResolveProxy` downgraded any resolution error (DB error, corrupt registry row) to a `debug` log and fell back to a DIRECT connection β€” invisible proxy bypass for traffic-isolation setups. Now logged at `warn` with the connection id. +- **Emergency budget fallback: opt-out env switch `OMNIROUTE_EMERGENCY_FALLBACK`** ([#3741](https://github.com/diegosouzapw/OmniRoute/pull/3741) β€” thanks @zoispag): adds an `OMNIROUTE_EMERGENCY_FALLBACK` environment variable that disables the budget-exhaustion emergency reroute to `nvidia/openai/gpt-oss-120b` entirely when set to `false` or `0`. Default behavior (enabled) is unchanged. + +- **Auto-Combo: live model intelligence scoring via Arena ELO + models.dev** ([#3660](https://github.com/diegosouzapw/OmniRoute/pull/3660) β€” thanks @pizzav-xyz): replaces the static fitness lookup with a 5-layer resolution chain (user override β†’ Arena ELO β†’ models.dev tiers β†’ hardcoded map β†’ neutral fallback). A sync pipeline auto-fetches Arena AI leaderboard ELO scores and derives intelligence tiers from models.dev capabilities; combo picks now update as leaderboard rankings change without any manual configuration. + +- **Vertex AI: dynamic model discovery** ([#3712](https://github.com/diegosouzapw/OmniRoute/pull/3712) β€” thanks @artickc): the `vertex` provider now queries the Generative Language models API at runtime to surface the full account catalog β€” including image-generation models (Imagen, `gemini-*-image`), embeddings, and partner models β€” instead of returning only the small hardcoded registry list. + +- **Vertex AI: self-tracked USD spend on the Limits page** ([#3724](https://github.com/diegosouzapw/OmniRoute/pull/3724) β€” thanks @artickc): since the Google Cloud Billing API is inaccessible via the proxy credential, Vertex connections now track their own cumulative USD spend locally (based on token-cost accounting) and display it on the Limits page as "$ used since account added." + +- **Gemini: rate-limit metadata for known per-model RPM/RPD caps** ([#3686](https://github.com/diegosouzapw/OmniRoute/pull/3686) β€” thanks @hartmark): injects known rate-limit headers (RPM/RPD) for Gemini models that carry per-model limits (e.g. Gemma 4's 15 RPM / generous RPD), so the cooldown engine applies them correctly instead of locking out the whole account on daily-limit hits. + +- **Model Lockout: full settings UI with success-decay recovery** ([#3629](https://github.com/diegosouzapw/OmniRoute/pull/3629) β€” thanks @Chewji9875): end-to-end wiring of the per-model lockout feature β€” settings UI (enable/disable, configure thresholds), backend integration, structured error classification, and a success-decay mechanism that gradually recovers a locked model's fitness as successful calls accumulate. Lockout now applies to all providers when enabled, not just per-model-quota providers. + +### πŸ”§ Bug Fixes + +- **`@omniroute/opencode-plugin` bundled in the npm tarball + `omniroute setup opencode` CLI command** ([#3726](https://github.com/diegosouzapw/OmniRoute/pull/3726) β€” thanks @herjarsa): the plugin was never compiled as part of the publish pipeline, requiring manual extraction. Now ships pre-built inside the `omniroute` package and installed via `omniroute setup opencode` (copies plugin into `~/.config/opencode/plugins/omniroute/`, updates `opencode.json` idempotently). Also fixes `provider.models` baseURL resolution β€” checks `_provider.options.baseURL` as a third fallback so partner/tiered providers no longer return zero models. ([#3711](https://github.com/diegosouzapw/OmniRoute/issues/3711)) + +- **MiMoCode 403 "Illegal access" fixed** ([#3728](https://github.com/diegosouzapw/OmniRoute/pull/3728) β€” thanks @felipesartori): the Xiaomi free endpoint gates requests on a recognized MiMoCode system-prompt signature; OmniRoute forwarded raw requests without the marker, causing 403 on every call. The executor now injects the required anti-abuse signature. + +- **"Test all models" flow: i18n crash, status icons, auto-hide** ([#3729](https://github.com/diegosouzapw/OmniRoute/pull/3729) β€” thanks @felipesartori): three bugs in the provider-detail test-all-models flow β€” `providerText()` crash because the `testAllResults` template requires `{ok, total}` but callers passed `{ok, error}`; missing `online`/`offline` status icons on model rows; results panel not auto-hiding after run completes. + +- **OAuth token-refresh invalidation loop fixed** ([#3692](https://github.com/diegosouzapw/OmniRoute/pull/3692) β€” thanks @diegosouzapw): `refreshClaudeOAuthToken` returned `null` instead of the error sentinel on non-canonical 400 bodies, causing the caller to retry every 60 seconds β€” observed as 1,352 consecutive refresh attempts on one Claude account. Fixed alongside hardening of `safeResolveProxy` (proxy resolution errors now warn instead of silently falling back to DIRECT) and adding egress-IP visibility to `safeLogEvents`. + +- **`safeLogEvents` async hotfix** (thanks @diegosouzapw): PR #3692 introduced a `lazy await import(proxyEgress)` inside a sync `safeLogEvents` β€” an ES syntax error that broke every consumer loading `chatHelpers` via `tsx` and caused 14 tests to fail at module load. Made `safeLogEvents` async; `void`-ed the single `chat.ts` call site. + +- **Kiro: quota tracking for IAM Identity Center accounts** ([#3722](https://github.com/diegosouzapw/OmniRoute/pull/3722) β€” thanks @artickc): `getKiroUsage` returned "0 used" for IAM Identity Center accounts (and `kiro-cli` imports) because those connections frequently lack a persisted `profileArn`. Now falls back to a name-based profile lookup so quota displays correctly. + +- **Empty Claude SSE stream now surfaces a real error** ([#3689](https://github.com/diegosouzapw/OmniRoute/pull/3689) β€” thanks @TechNickAI): when a Claude stream completed with lifecycle events but no content block, the proxy returned a synthetic `"[Proxy Error] The upstream API returned an empty response"` as a *successful* assistant message. Now emits a proper SSE error event; the missing-finalizer synthetic path is preserved for streams that already produced content. + +- **Vertex AI Express-mode API keys** ([#3690](https://github.com/diegosouzapw/OmniRoute/pull/3690) β€” thanks @artickc): the Vertex executor rejected every non-JSON credential with "Vertex AI requires a valid Service Account JSON." Now accepts Express-mode API key strings (`AIza*`) alongside Service Account JSON, routing them through the correct token endpoint. + +- **Anthropic: strip `top_p` when `temperature` is set** ([#3691](https://github.com/diegosouzapw/OmniRoute/pull/3691) β€” thanks @zhiru): Anthropic API rejects requests containing both `temperature` and `top_p`; VS Code's Claude extension sends both in every request, causing 400s on all routed calls. The OpenAIβ†’Claude translator now drops `top_p` when `temperature` is present. + +- **Combo reasoning token buffer: conservative application + feature flag** ([#3700](https://github.com/diegosouzapw/OmniRoute/pull/3700) β€” thanks @rdself): tightens the #3588 buffer (only applies when the model is explicitly thinking-capable, has a non-default known output cap, and the full buffered value fits inside that cap) and adds a `reasoningTokenBufferEnabled` feature flag in combo defaults so users can fully disable it from Settings. + +- **Emergency budget fallback: cross-provider credential leak fixed** ([#3699](https://github.com/diegosouzapw/OmniRoute/pull/3699) β€” thanks @diegosouzapw): the executor-level emergency hop re-sent the failing provider's API key to the emergency provider's endpoint (e.g. the OpenAI `Authorization` header going to `integrate.api.nvidia.com`). Now orchestrated exclusively by the routing layer, which resolves credentials for the emergency provider via account selection and no longer fires inside combo targets. + +- **`/v1/messages/count_tokens` now honors the connection's proxy assignment** ([#3699](https://github.com/diegosouzapw/OmniRoute/pull/3699) β€” thanks @diegosouzapw): token count calls went DIRECT regardless of configured proxies, leaking the host IP for proxy-isolated setups. Now wraps execution in `runWithProxyContext`, exactly like chat execution. + +- **Gemini: context-mode fallback for signatureless tool calls** ([#3688](https://github.com/diegosouzapw/OmniRoute/pull/3688) β€” thanks @diegosouzapw): fixes HTTP 400 on multi-turn thinking-model tool calls when `thought_signature` is unavailable β€” standard Gemini provider now falls back to context mode instead of sending the unsigned call. + +- **Antigravity: preserve `gemini-3.1-pro` High/Low budget tiers** ([#3696](https://github.com/diegosouzapw/OmniRoute/pull/3696) β€” thanks @diegosouzapw): upstream accepts the suffixed ids; stop collapsing to bare `gemini-3.1-pro`. + +- **Stream combo: fail over on empty/content-filtered response** ([#3685](https://github.com/diegosouzapw/OmniRoute/pull/3685) β€” thanks @diegosouzapw): streaming combos now route to the next target instead of surfacing a blank reply. + +- **Qwen Web: migrated to v2 chat API** ([#3723](https://github.com/diegosouzapw/OmniRoute/pull/3723) β€” thanks @diegosouzapw): the legacy `/api/chat/completions` endpoint was retired upstream returning `504` HTML from Alibaba's gateway for all requests. The executor now uses the two-step v2 flow (`/api/v2/chats/new` β†’ `/api/v2/chat/completions?chat_id=`), replays the full browser cookie jar (cna + ssxmod_itna/itna2 + token) required by Alibaba's WAF instead of only a Bearer token, parses phase-based SSE (thinkβ†’reasoning, answerβ†’content), and refreshes the model catalog to current ids (`qwen3.7-max`, `qwen3.7-plus`, `qwen3.6-plus`; legacy ids kept as aliases). 17 unit tests. (Closes [#3288](https://github.com/diegosouzapw/OmniRoute/issues/3288)) + +### ♻️ Code Quality + +- **Dashboard god-component (#3501): Phases 1g β†’ 1t complete β€” ≀800 LOC target reached** ([#3717](https://github.com/diegosouzapw/OmniRoute/pull/3717), [#3721](https://github.com/diegosouzapw/OmniRoute/pull/3721), [#3725](https://github.com/diegosouzapw/OmniRoute/pull/3725), [#3727](https://github.com/diegosouzapw/OmniRoute/pull/3727) β€” thanks @diegosouzapw): four extraction phases bring `ProviderDetailPageClient.tsx` from 4,062 to 781 LOC β€” the ≀800 target set at the start of the refactor. Extracted OAuth flow helpers, quota display, traffic-inspector panel, logs viewer, combo-target editor, and remaining inline UI into standalone components under `providers/[id]/components/`. + +### 🌍 Internationalization + +- **zh-CN: comprehensive Simplified Chinese translation improvements** ([#3736](https://github.com/diegosouzapw/OmniRoute/pull/3736) β€” thanks @sdfsdfw2): broad pass on Simplified Chinese UI strings for accuracy and consistency. + +### πŸ“ Maintenance + +- **CI: bump GitHub Actions artifacts/cache actions to latest** (thanks @diegosouzapw): `actions/download-artifact` 4β†’8 ([#3733](https://github.com/diegosouzapw/OmniRoute/pull/3733)), `actions/cache` 4β†’5 ([#3734](https://github.com/diegosouzapw/OmniRoute/pull/3734)), `actions/upload-artifact` 4β†’7 ([#3735](https://github.com/diegosouzapw/OmniRoute/pull/3735)). + +- **File-size ratchet baseline reconciled** ([#3705](https://github.com/diegosouzapw/OmniRoute/pull/3705) β€” thanks @diegosouzapw): freezes 27 inherited/previously-grown files at their current LOC and registers `providerLimits.ts` in the gate; ongoing shrink tracked via #3501. + +- **docs: add FUNDING.yml and README Support section** ([#3698](https://github.com/diegosouzapw/OmniRoute/pull/3698) β€” thanks @diegosouzapw) + +- **docs(changelog): restore `#3590` bullet lost on the v3.8.20 release branch** (thanks @diegosouzapw): the fix reached `main` pre-tag via cherry-pick `#3591`, but its changelog bullet only existed on `release/v3.8.20` after the squash-merge; restored per the 2026-06-12 release-branch leftover audit. ### βœ… Tests -- **Combo strategy fallback coverage** (`tests/unit/combo-strategy-fallbacks.test.ts`, 11 tests): fill-first / p2c / random / cost-optimized / strict-random fallback paths (previously happy-path only), price-tie stability, stale strict-random deck degradation, unknown-strategy normalization to priority, and circuit-breaker HALF_OPEN recovery inside the combo loop + `preScreenTargets` (lazy-recovery contract). -- **`#1731` fast-skip suite restored** (`tests/integration/combo-provider-exhaustion.test.ts`): the five skipped tests were rewritten against the current routing policy (quota-exhausted 429 marks the provider for the request; transient 429 retries other connections; connection errors skip per-connection; nothing persists across requests) and re-enabled β€” 8/8 green. -- **Proxy context passthrough** (`tests/integration/proxy-context-passthrough.test.ts`): combo targets each execute under their own connection's proxy; `count_tokens` runs inside the connection's proxy context. -### πŸ› Fixed - -- chore(quality-gate): reconcile check-file-size baseline β€” freeze 27 inherited/this-round grown files at current LOC + register providerLimits.ts (greens the file-size gate; shrink tracked via #3501) -- fix(gemini): standard Gemini provider no longer sends tool calls without a thought_signature (falls back to context mode when the signature is unavailable), fixing HTTP 400 on multi-turn thinking-model tool calls (#3688) -- fix(antigravity): preserve gemini-3.1-pro High/Low budget tiers (upstream accepts the suffixed ids; stop collapsing to bare gemini-3.1-pro) (#3696) -- fix: streaming combos now fail over to the next target when an upstream returns an empty/content-filtered response instead of surfacing a blank reply (#3685) -- fix(qwen-web): migrate the Qwen Web provider to the v2 chat API. The legacy `/api/chat/completions` endpoint was retired upstream and returned `504` HTML from Alibaba's gateway for every request regardless of credentials, so no token refresh could help (#3288, discussion #2768). The executor now uses the two-step v2 flow (`/api/v2/chats/new` β†’ `/api/v2/chat/completions?chat_id=`), replays the full browser cookie jar (cna + ssxmod_itna/itna2 + token) required by Alibaba's WAF instead of only a Bearer token, parses the phase-based SSE (thinkβ†’reasoning, answerβ†’content), and maps the WAF/expired HTML page to a clear actionable auth error instead of surfacing raw HTML. The credential requirement is now a full Cookie header, browser-login capture grabs the WAF cookies, and the model catalog is refreshed to the current upstream ids (`qwen3.7-max`, `qwen3.7-plus`, `qwen3.6-plus`; legacy ids kept as aliases). 17 unit tests. +- **Combo strategy fallback coverage** (`tests/unit/combo-strategy-fallbacks.test.ts`, 11 tests β€” thanks @diegosouzapw): fill-first / p2c / random / cost-optimized / strict-random fallback paths (previously happy-path only), price-tie stability, stale strict-random deck degradation, unknown-strategy normalization to priority, and circuit-breaker HALF_OPEN recovery inside the combo loop + `preScreenTargets` (lazy-recovery contract). +- **`#1731` fast-skip suite restored** (`tests/integration/combo-provider-exhaustion.test.ts` β€” thanks @diegosouzapw): 5 previously-skipped integration tests rewritten against the current routing policy β€” 8/8 green. +- **Proxy context passthrough** (`tests/integration/proxy-context-passthrough.test.ts` β€” thanks @diegosouzapw): combo targets each execute under their own connection's proxy; `count_tokens` runs inside the connection's proxy context. --- diff --git a/bin/cli/api-commands/agent-skills.mjs b/bin/cli/api-commands/agent-skills.mjs new file mode 100644 index 0000000000..34b7f9e8fa --- /dev/null +++ b/bin/cli/api-commands/agent-skills.mjs @@ -0,0 +1,70 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_agent_skills(parent) { + const tag = parent.command("agent-skills").description("Agent Skills endpoints"); + tag.command("get-api-agent-skills") + .description("List agent skills catalog") + .option("--category ", "Filter by category (api = REST API skills, cli = CLI skills)") + .option("--area ", "Filter by area slug (e.g. \"providers\", \"models\", \"cli-serve\")") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/agent-skills"; + const qs = new URLSearchParams(); + if (opts.category != null) qs.set("category", String(opts.category)); + if (opts.area != null) qs.set("area", String(opts.area)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-agent-skills-id-") + .description("Get a single agent skill") + .requiredOption("--id ", "Canonical skill ID") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/agent-skills/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-agent-skills-id-raw") + .description("Get raw SKILL.md content") + .requiredOption("--id ", "Canonical skill ID") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/agent-skills/{id}/raw"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-agent-skills-coverage") + .description("Get SKILL.md coverage stats") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/agent-skills/coverage"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-agent-skills-generate") + .description("Trigger SKILL.md generator") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/agent-skills/generate"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/agentbridge.mjs b/bin/cli/api-commands/agentbridge.mjs new file mode 100644 index 0000000000..6622291383 --- /dev/null +++ b/bin/cli/api-commands/agentbridge.mjs @@ -0,0 +1,155 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_agentbridge(parent) { + const tag = parent.command("agentbridge").description("AgentBridge endpoints"); + tag.command("get-api-tools-agent-bridge-agents") + .description("List all 9 IDE agents with current state") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/agents"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-agent-bridge-state") + .description("Get global AgentBridge server state") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/state"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-agent-bridge-server") + .description("Control AgentBridge MITM server") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/server"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-agent-bridge-agents-agent-id-dns") + .description("Enable or disable DNS for one agent") + .requiredOption("--agent-id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/agents/{agentId}/dns"; + url = url.replace("{agentId}", encodeURIComponent(opts.agentId ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-agent-bridge-agents-agent-id-mappings") + .description("Get model mappings for one agent") + .requiredOption("--agent-id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/agents/{agentId}/mappings"; + url = url.replace("{agentId}", encodeURIComponent(opts.agentId ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-tools-agent-bridge-agents-agent-id-mappings") + .description("Update model mappings for one agent") + .requiredOption("--agent-id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/agents/{agentId}/mappings"; + url = url.replace("{agentId}", encodeURIComponent(opts.agentId ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-agent-bridge-bypass") + .description("List bypass patterns (hosts never decrypted)") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/bypass"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-tools-agent-bridge-bypass") + .description("Update user bypass patterns") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/bypass"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-agent-bridge-cert") + .description("Download or regenerate the AgentBridge CA certificate") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/cert"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-agent-bridge-upstream-ca") + .description("Get configured upstream CA cert path") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/upstream-ca"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-agent-bridge-upstream-ca") + .description("Set upstream CA cert path for corporate TLS environments") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/agent-bridge/upstream-ca"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/api-keys.mjs b/bin/cli/api-commands/api-keys.mjs index 3ac9e570af..445df84546 100644 --- a/bin/cli/api-commands/api-keys.mjs +++ b/bin/cli/api-commands/api-keys.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_api_keys(parent) { const tag = parent.command("api-keys").description("API Keys endpoints"); - tag - .command("get-api-keys") + tag.command("get-api-keys") .description("List API keys") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/keys"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-keys") + tag.command("post-api-keys") .description("Create API key") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,26 +26,16 @@ export function register_api_keys(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-keys-id-") + tag.command("delete-api-keys-id-") .description("Delete API key") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/keys/{id}"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/audio.mjs b/bin/cli/api-commands/audio.mjs index 707d9f4e64..4465f65bc3 100644 --- a/bin/cli/api-commands/audio.mjs +++ b/bin/cli/api-commands/audio.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_audio(parent) { const tag = parent.command("audio").description("Audio endpoints"); - tag - .command("post-api-v1-audio-speech") + tag.command("post-api-v1-audio-speech") .description("Generate speech audio") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_audio(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-audio-transcriptions") + tag.command("post-api-v1-audio-transcriptions") .description("Transcribe audio") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -40,12 +33,7 @@ export function register_audio(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/chat.mjs b/bin/cli/api-commands/chat.mjs index 4912dfa079..9b6497beb6 100644 --- a/bin/cli/api-commands/chat.mjs +++ b/bin/cli/api-commands/chat.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_chat(parent) { const tag = parent.command("chat").description("Chat endpoints"); - tag - .command("post-api-v1-chat-completions") + tag.command("post-api-v1-chat-completions") .description("Create chat completion") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_chat(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-providers-provider-chat-completions") + tag.command("post-api-v1-providers-provider-chat-completions") .description("Create chat completion (provider-specific)") .requiredOption("--provider ", "") .option("--body ", "JSON body or @path/to/file.json") @@ -42,17 +35,11 @@ export function register_chat(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-api-chat") + tag.command("post-api-v1-api-chat") .description("Ollama-compatible chat endpoint") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -64,12 +51,7 @@ export function register_chat(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/cli-tools.mjs b/bin/cli/api-commands/cli-tools.mjs index 30f68eb0b0..40c879e825 100644 --- a/bin/cli/api-commands/cli-tools.mjs +++ b/bin/cli/api-commands/cli-tools.mjs @@ -5,82 +5,56 @@ import { readFileSync } from "node:fs"; export function register_cli_tools(parent) { const tag = parent.command("cli-tools").description("CLI Tools endpoints"); - tag - .command("get-api-cli-tools-backups") + tag.command("get-api-cli-tools-backups") .description("List CLI tool backups") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/backups"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-backups") + tag.command("post-api-cli-tools-backups") .description("Create CLI tool backup") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/backups"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-runtime-tool-id-") + tag.command("get-api-cli-tools-runtime-tool-id-") .description("Get runtime status for a CLI tool") .requiredOption("--tool-id ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/runtime/{toolId}"; url = url.replace("{toolId}", encodeURIComponent(opts.toolId ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-guide-settings-tool-id-") + tag.command("get-api-cli-tools-guide-settings-tool-id-") .description("Get guide settings for a tool") .requiredOption("--tool-id ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/guide-settings/{toolId}"; url = url.replace("{toolId}", encodeURIComponent(opts.toolId ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-antigravity-mitm") + tag.command("get-api-cli-tools-antigravity-mitm") .description("Get Antigravity MITM proxy settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/antigravity-mitm"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-antigravity-mitm") + tag.command("post-api-cli-tools-antigravity-mitm") .description("Update Antigravity MITM proxy settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -92,45 +66,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-antigravity-mitm") + tag.command("delete-api-cli-tools-antigravity-mitm") .description("Reset Antigravity MITM proxy settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/antigravity-mitm"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-antigravity-mitm-alias") + tag.command("get-api-cli-tools-antigravity-mitm-alias") .description("Get Antigravity MITM alias configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/antigravity-mitm/alias"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-cli-tools-antigravity-mitm-alias") + tag.command("put-api-cli-tools-antigravity-mitm-alias") .description("Update Antigravity MITM alias configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -142,31 +100,20 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-claude-settings") + tag.command("get-api-cli-tools-claude-settings") .description("Get Claude CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/claude-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-claude-settings") + tag.command("post-api-cli-tools-claude-settings") .description("Apply Claude CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -178,45 +125,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-claude-settings") + tag.command("delete-api-cli-tools-claude-settings") .description("Reset Claude CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/claude-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-cline-settings") + tag.command("get-api-cli-tools-cline-settings") .description("Get Cline CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/cline-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-cline-settings") + tag.command("post-api-cli-tools-cline-settings") .description("Apply Cline CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -228,45 +159,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-cline-settings") + tag.command("delete-api-cli-tools-cline-settings") .description("Reset Cline CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/cline-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-codex-profiles") + tag.command("get-api-cli-tools-codex-profiles") .description("Get Codex profiles") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/codex-profiles"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-codex-profiles") + tag.command("post-api-cli-tools-codex-profiles") .description("Create Codex profile") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -278,17 +193,11 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-cli-tools-codex-profiles") + tag.command("put-api-cli-tools-codex-profiles") .description("Update Codex profile") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -300,45 +209,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-codex-profiles") + tag.command("delete-api-cli-tools-codex-profiles") .description("Delete Codex profile") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/codex-profiles"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-codex-settings") + tag.command("get-api-cli-tools-codex-settings") .description("Get Codex CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/codex-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-codex-settings") + tag.command("post-api-cli-tools-codex-settings") .description("Apply Codex CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -350,45 +243,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-codex-settings") + tag.command("delete-api-cli-tools-codex-settings") .description("Reset Codex CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/codex-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-droid-settings") + tag.command("get-api-cli-tools-droid-settings") .description("Get Droid CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/droid-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-droid-settings") + tag.command("post-api-cli-tools-droid-settings") .description("Apply Droid CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -400,45 +277,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-droid-settings") + tag.command("delete-api-cli-tools-droid-settings") .description("Reset Droid CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/droid-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-kilo-settings") + tag.command("get-api-cli-tools-kilo-settings") .description("Get Kilo CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/kilo-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-kilo-settings") + tag.command("post-api-cli-tools-kilo-settings") .description("Apply Kilo CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -450,45 +311,29 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-kilo-settings") + tag.command("delete-api-cli-tools-kilo-settings") .description("Reset Kilo CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/kilo-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cli-tools-openclaw-settings") + tag.command("get-api-cli-tools-openclaw-settings") .description("Get OpenClaw CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/openclaw-settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cli-tools-openclaw-settings") + tag.command("post-api-cli-tools-openclaw-settings") .description("Apply OpenClaw CLI settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -500,26 +345,16 @@ export function register_cli_tools(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cli-tools-openclaw-settings") + tag.command("delete-api-cli-tools-openclaw-settings") .description("Reset OpenClaw CLI settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cli-tools/openclaw-settings"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/cloud.mjs b/bin/cli/api-commands/cloud.mjs index d03353a072..e942307196 100644 --- a/bin/cli/api-commands/cloud.mjs +++ b/bin/cli/api-commands/cloud.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_cloud(parent) { const tag = parent.command("cloud").description("Cloud endpoints"); - tag - .command("post-api-cloud-auth") + tag.command("post-api-cloud-auth") .description("Authenticate with cloud worker") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_cloud(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-cloud-credentials-update") + tag.command("put-api-cloud-credentials-update") .description("Update cloud worker credentials") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -40,17 +33,11 @@ export function register_cloud(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-cloud-model-resolve") + tag.command("post-api-cloud-model-resolve") .description("Resolve model via cloud") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -62,31 +49,20 @@ export function register_cloud(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cloud-models-alias") + tag.command("get-api-cloud-models-alias") .description("Get cloud model aliases") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cloud/models/alias"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-cloud-models-alias") + tag.command("put-api-cloud-models-alias") .description("Update cloud model alias") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -98,12 +74,7 @@ export function register_cloud(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/combos.mjs b/bin/cli/api-commands/combos.mjs index 57fe07c69e..2c3647f94b 100644 --- a/bin/cli/api-commands/combos.mjs +++ b/bin/cli/api-commands/combos.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_combos(parent) { const tag = parent.command("combos").description("Combos endpoints"); - tag - .command("get-api-combos") + tag.command("get-api-combos") .description("List routing combos") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/combos"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-combos") + tag.command("post-api-combos") .description("Create routing combo") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,68 +26,43 @@ export function register_combos(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-combos-id-") + tag.command("patch-api-combos-id-") .description("Update combo") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/combos/{id}"; - const res = await apiFetch(url, { - method: "PATCH", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-combos-id-") + tag.command("delete-api-combos-id-") .description("Delete combo") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/combos/{id}"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-combos-metrics") + tag.command("get-api-combos-metrics") .description("Get combo metrics") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/combos/metrics"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-combos-test") + tag.command("post-api-combos-test") .description("Test a combo configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/combos/test"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/compression.mjs b/bin/cli/api-commands/compression.mjs index d32ea40578..9f96e0f8b0 100644 --- a/bin/cli/api-commands/compression.mjs +++ b/bin/cli/api-commands/compression.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_compression(parent) { const tag = parent.command("compression").description("Compression endpoints"); - tag - .command("get-api-settings-compression") + tag.command("get-api-settings-compression") .description("Get global compression settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/compression"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-settings-compression") + tag.command("put-api-settings-compression") .description("Update global compression settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,17 +26,11 @@ export function register_compression(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-compression-preview") + tag.command("post-api-compression-preview") .description("Preview compression for a message payload") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -54,59 +42,38 @@ export function register_compression(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-compression-language-packs") + tag.command("get-api-compression-language-packs") .description("List Caveman compression language packs") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/compression/language-packs"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-compression-rules") + tag.command("get-api-compression-rules") .description("List Caveman compression rule metadata") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/compression/rules"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-context-rtk-config") + tag.command("get-api-context-rtk-config") .description("Get RTK compression settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/context/rtk/config"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-context-rtk-config") + tag.command("put-api-context-rtk-config") .description("Update RTK compression settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -118,31 +85,20 @@ export function register_compression(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-context-rtk-filters") + tag.command("get-api-context-rtk-filters") .description("List RTK filters and load diagnostics") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/context/rtk/filters"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-context-rtk-test") + tag.command("post-api-context-rtk-test") .description("Run RTK compression preview for text") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -154,28 +110,18 @@ export function register_compression(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-context-rtk-raw-output-id-") + tag.command("get-api-context-rtk-raw-output-id-") .description("Read retained redacted RTK raw output") .requiredOption("--id ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/context/rtk/raw-output/{id}"; url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/embedded-services.mjs b/bin/cli/api-commands/embedded-services.mjs new file mode 100644 index 0000000000..0baa58b8a7 --- /dev/null +++ b/bin/cli/api-commands/embedded-services.mjs @@ -0,0 +1,202 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_embedded_services(parent) { + const tag = parent.command("embedded-services").description("Embedded Services endpoints"); + tag.command("post-api-services-9router-install") + .description("Install 9Router from npm") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/install"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-start") + .description("Start 9Router") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/start"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-stop") + .description("Stop 9Router") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/stop"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-restart") + .description("Restart 9Router") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/restart"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-update") + .description("Update 9Router to a newer npm version") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/update"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-rotate-key") + .description("Rotate the 9Router API key") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/rotate-key"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-services-9router-status") + .description("Get 9Router status") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/status"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-9router-auto-start") + .description("Toggle 9Router auto-start") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/9router/auto-start"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-install") + .description("Install CLIProxyAPI from npm") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/install"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-start") + .description("Start CLIProxyAPI") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/start"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-stop") + .description("Stop CLIProxyAPI") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/stop"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-restart") + .description("Restart CLIProxyAPI") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/restart"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-update") + .description("Update CLIProxyAPI to a newer npm version") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/update"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-services-cliproxy-status") + .description("Get CLIProxyAPI status") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/status"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-services-cliproxy-auto-start") + .description("Toggle CLIProxyAPI auto-start") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/cliproxy/auto-start"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-services-name-logs") + .description("Stream service logs via SSE") + .requiredOption("--name ", "") + .option("--tail ", "Number of historical lines to include in the initial snapshot") + .option("--filter ", "Case-insensitive substring filter applied to log lines. No regex β€” ReDoS-safe by design.") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/services/{name}/logs"; + url = url.replace("{name}", encodeURIComponent(opts.name ?? "")); + const qs = new URLSearchParams(); + if (opts.tail != null) qs.set("tail", String(opts.tail)); + if (opts.filter != null) qs.set("filter", String(opts.filter)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/embeddings.mjs b/bin/cli/api-commands/embeddings.mjs index 77d75271d2..8ae1235a88 100644 --- a/bin/cli/api-commands/embeddings.mjs +++ b/bin/cli/api-commands/embeddings.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_embeddings(parent) { const tag = parent.command("embeddings").description("Embeddings endpoints"); - tag - .command("post-api-v1-embeddings") + tag.command("post-api-v1-embeddings") .description("Create embeddings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_embeddings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-providers-provider-embeddings") + tag.command("post-api-v1-providers-provider-embeddings") .description("Create embeddings (provider-specific)") .requiredOption("--provider ", "") .option("--body ", "JSON body or @path/to/file.json") @@ -42,12 +35,7 @@ export function register_embeddings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/fallback.mjs b/bin/cli/api-commands/fallback.mjs index 0e8824900c..b769ec8032 100644 --- a/bin/cli/api-commands/fallback.mjs +++ b/bin/cli/api-commands/fallback.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_fallback(parent) { const tag = parent.command("fallback").description("Fallback endpoints"); - tag - .command("get-api-fallback-chains") + tag.command("get-api-fallback-chains") .description("List fallback chains") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/fallback/chains"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-fallback-chains") + tag.command("post-api-fallback-chains") .description("Create fallback chain") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,17 +26,11 @@ export function register_fallback(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-fallback-chains") + tag.command("delete-api-fallback-chains") .description("Delete fallback chain") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -54,12 +42,7 @@ export function register_fallback(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "DELETE", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/images.mjs b/bin/cli/api-commands/images.mjs index af14946f57..14cc850844 100644 --- a/bin/cli/api-commands/images.mjs +++ b/bin/cli/api-commands/images.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_images(parent) { const tag = parent.command("images").description("Images endpoints"); - tag - .command("post-api-v1-images-generations") + tag.command("post-api-v1-images-generations") .description("Generate images") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_images(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-providers-provider-images-generations") + tag.command("post-api-v1-providers-provider-images-generations") .description("Generate images (provider-specific)") .requiredOption("--provider ", "") .option("--body ", "JSON body or @path/to/file.json") @@ -42,12 +35,7 @@ export function register_images(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/memory.mjs b/bin/cli/api-commands/memory.mjs new file mode 100644 index 0000000000..6cf8f68679 --- /dev/null +++ b/bin/cli/api-commands/memory.mjs @@ -0,0 +1,251 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_memory(parent) { + const tag = parent.command("memory").description("Memory endpoints"); + tag.command("get-api-memory") + .description("List memory entries") + .option("--api-key-id ", "") + .option("--type ", "") + .option("--session-id ", "") + .option("--q ", "") + .option("--limit ", "") + .option("--page ", "") + .option("--offset ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory"; + const qs = new URLSearchParams(); + if (opts.apiKeyId != null) qs.set("apiKeyId", String(opts.apiKeyId)); + if (opts.type != null) qs.set("type", String(opts.type)); + if (opts.sessionId != null) qs.set("sessionId", String(opts.sessionId)); + if (opts.q != null) qs.set("q", String(opts.q)); + if (opts.limit != null) qs.set("limit", String(opts.limit)); + if (opts.page != null) qs.set("page", String(opts.page)); + if (opts.offset != null) qs.set("offset", String(opts.offset)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-memory") + .description("Create a memory entry") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-memory-id-") + .description("Get a single memory entry") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/{id}"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-memory-id-") + .description("Update a memory entry") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/{id}"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-memory-id-") + .description("Delete a memory entry") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/{id}"; + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-memory-health") + .description("Memory store health check") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/health"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-memory-retrieve-preview") + .description("Dry-run memory retrieval (Playground)") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/retrieve-preview"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-memory-embedding-providers") + .description("List embedding providers") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/embedding-providers"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-memory-engine-status") + .description("Memory engine status") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/engine-status"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-memory-summarize") + .description("Compact old memories") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/summarize"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-memory-reindex") + .description("Trigger vector reindex") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/memory/reindex"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-settings-memory") + .description("Get memory settings") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/memory"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-settings-memory") + .description("Update memory settings") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/memory"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-settings-qdrant") + .description("Get Qdrant settings") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-settings-qdrant") + .description("Update Qdrant settings") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-settings-qdrant-health") + .description("Qdrant health probe") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant/health"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-settings-qdrant-search") + .description("Qdrant semantic search test") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant/search"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-settings-qdrant-cleanup") + .description("Clean up expired Qdrant points") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant/cleanup"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-settings-qdrant-embedding-models") + .description("List Qdrant embedding models") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/qdrant/embedding-models"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/messages.mjs b/bin/cli/api-commands/messages.mjs index cee8c4e5de..6618f31a9e 100644 --- a/bin/cli/api-commands/messages.mjs +++ b/bin/cli/api-commands/messages.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_messages(parent) { const tag = parent.command("messages").description("Messages endpoints"); - tag - .command("post-api-v1-messages") + tag.command("post-api-v1-messages") .description("Create message (Anthropic-compatible)") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_messages(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1-messages-count-tokens") + tag.command("post-api-v1-messages-count-tokens") .description("Count tokens for a message") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -40,12 +33,7 @@ export function register_messages(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/models.mjs b/bin/cli/api-commands/models.mjs index 73946c0e4f..09d0fa0e8a 100644 --- a/bin/cli/api-commands/models.mjs +++ b/bin/cli/api-commands/models.mjs @@ -5,55 +5,36 @@ import { readFileSync } from "node:fs"; export function register_models(parent) { const tag = parent.command("models").description("Models endpoints"); - tag - .command("get-api-v1-models") + tag.command("get-api-v1-models") .description("List available models") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/v1/models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-v1-providers-provider-models") + tag.command("get-api-v1-providers-provider-models") .description("List models for a specific provider") - .requiredOption( - "--provider ", - "Provider id or alias (for example `openai`, `claude`, `cc`)." - ) + .requiredOption("--provider ", "Provider id or alias (for example `openai`, `claude`, `cc`).") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/v1/providers/{provider}/models"; url = url.replace("{provider}", encodeURIComponent(opts.provider ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-models") + tag.command("get-api-models") .description("List models (management)") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-models-alias") + tag.command("post-api-models-alias") .description("Create or update a model alias") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -65,45 +46,29 @@ export function register_models(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-models-catalog") + tag.command("get-api-models-catalog") .description("Get full model catalog") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/models/catalog"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-v1beta-models") + tag.command("get-api-v1beta-models") .description("List models (Gemini format)") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/v1beta/models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-v1beta-models-path-") + tag.command("post-api-v1beta-models-path-") .description("Gemini generateContent") .requiredOption("--path ", "") .option("--body ", "JSON body or @path/to/file.json") @@ -117,12 +82,7 @@ export function register_models(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/moderations.mjs b/bin/cli/api-commands/moderations.mjs index 8bac14117f..0c716202f6 100644 --- a/bin/cli/api-commands/moderations.mjs +++ b/bin/cli/api-commands/moderations.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_moderations(parent) { const tag = parent.command("moderations").description("Moderations endpoints"); - tag - .command("post-api-v1-moderations") + tag.command("post-api-v1-moderations") .description("Create moderation") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,12 +17,7 @@ export function register_moderations(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/oauth.mjs b/bin/cli/api-commands/oauth.mjs index 6aed0c8099..1645bc3220 100644 --- a/bin/cli/api-commands/oauth.mjs +++ b/bin/cli/api-commands/oauth.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_oauth(parent) { const tag = parent.command("oauth").description("OAuth endpoints"); - tag - .command("get-api-oauth-provider-action-") + tag.command("get-api-oauth-provider-action-") .description("OAuth flow handler") .requiredOption("--provider ", "") .requiredOption("--action ", "") @@ -15,44 +14,29 @@ export function register_oauth(parent) { let url = "/api/oauth/{provider}/{action}"; url = url.replace("{provider}", encodeURIComponent(opts.provider ?? "")); url = url.replace("{action}", encodeURIComponent(opts.action ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-oauth-cursor-auto-import") + tag.command("get-api-oauth-cursor-auto-import") .description("Auto-import Cursor OAuth credentials") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/oauth/cursor/auto-import"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-oauth-cursor-import") + tag.command("get-api-oauth-cursor-import") .description("Get Cursor import status") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/oauth/cursor/import"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-oauth-cursor-import") + tag.command("post-api-oauth-cursor-import") .description("Import Cursor OAuth credentials") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -64,45 +48,29 @@ export function register_oauth(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-oauth-kiro-auto-import") + tag.command("get-api-oauth-kiro-auto-import") .description("Auto-import Kiro OAuth credentials") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/oauth/kiro/auto-import"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-oauth-kiro-import") + tag.command("get-api-oauth-kiro-import") .description("Get Kiro import status") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/oauth/kiro/import"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-oauth-kiro-import") + tag.command("post-api-oauth-kiro-import") .description("Import Kiro OAuth credentials") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -114,31 +82,20 @@ export function register_oauth(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-oauth-kiro-social-authorize") + tag.command("get-api-oauth-kiro-social-authorize") .description("Initiate Kiro social OAuth authorization") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/oauth/kiro/social-authorize"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-oauth-kiro-social-exchange") + tag.command("post-api-oauth-kiro-social-exchange") .description("Exchange Kiro social OAuth token") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -150,12 +107,7 @@ export function register_oauth(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/playground.mjs b/bin/cli/api-commands/playground.mjs new file mode 100644 index 0000000000..3866409833 --- /dev/null +++ b/bin/cli/api-commands/playground.mjs @@ -0,0 +1,83 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_playground(parent) { + const tag = parent.command("playground").description("Playground endpoints"); + tag.command("post-api-playground-improve-prompt") + .description("Improve prompt via LLM") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/improve-prompt"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-playground-presets") + .description("List playground presets") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/presets"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-playground-presets") + .description("Create playground preset") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/presets"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-playground-presets-id-") + .description("Get playground preset") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/presets/{id}"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-playground-presets-id-") + .description("Update playground preset") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/presets/{id}"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-playground-presets-id-") + .description("Delete playground preset") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/playground/presets/{id}"; + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/pricing.mjs b/bin/cli/api-commands/pricing.mjs index 76d59680d0..b790e24665 100644 --- a/bin/cli/api-commands/pricing.mjs +++ b/bin/cli/api-commands/pricing.mjs @@ -5,59 +5,39 @@ import { readFileSync } from "node:fs"; export function register_pricing(parent) { const tag = parent.command("pricing").description("Pricing endpoints"); - tag - .command("get-api-pricing") + tag.command("get-api-pricing") .description("Get model pricing") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/pricing"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-pricing") + tag.command("post-api-pricing") .description("Set model pricing") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/pricing"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-pricing-defaults") + tag.command("get-api-pricing-defaults") .description("Get default pricing") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/pricing/defaults"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-pricing-models") + tag.command("get-api-pricing-models") .description("Get pricing per model") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/pricing/models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/provider-nodes.mjs b/bin/cli/api-commands/provider-nodes.mjs index d8a96b51f6..1444f8d267 100644 --- a/bin/cli/api-commands/provider-nodes.mjs +++ b/bin/cli/api-commands/provider-nodes.mjs @@ -5,87 +5,57 @@ import { readFileSync } from "node:fs"; export function register_provider_nodes(parent) { const tag = parent.command("provider-nodes").description("Provider Nodes endpoints"); - tag - .command("get-api-provider-nodes") + tag.command("get-api-provider-nodes") .description("List provider nodes") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-nodes"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-provider-nodes") + tag.command("post-api-provider-nodes") .description("Create provider node") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-nodes"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-provider-nodes-id-") + tag.command("patch-api-provider-nodes-id-") .description("Update provider node") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-nodes/{id}"; - const res = await apiFetch(url, { - method: "PATCH", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-provider-nodes-id-") + tag.command("delete-api-provider-nodes-id-") .description("Delete provider node") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-nodes/{id}"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-provider-nodes-validate") + tag.command("post-api-provider-nodes-validate") .description("Validate a provider node") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-nodes/validate"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-provider-models") + tag.command("get-api-provider-models") .description("List provider models") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/provider-models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/providers.mjs b/bin/cli/api-commands/providers.mjs index 79a76e77bd..d0e56e2f84 100644 --- a/bin/cli/api-commands/providers.mjs +++ b/bin/cli/api-commands/providers.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_providers(parent) { const tag = parent.command("providers").description("Providers endpoints"); - tag - .command("get-api-providers") + tag.command("get-api-providers") .description("List provider connections") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-providers") + tag.command("post-api-providers") .description("Create provider connection") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,31 +26,20 @@ export function register_providers(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-providers-id-") + tag.command("get-api-providers-id-") .description("Get provider connection") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/{id}"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-providers-id-") + tag.command("patch-api-providers-id-") .description("Update provider connection") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -68,96 +51,97 @@ export function register_providers(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PATCH", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-providers-id-") + tag.command("delete-api-providers-id-") .description("Delete provider connection") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/{id}"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-providers-id-test") + tag.command("post-api-providers-id-test") .description("Test provider connection") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/{id}/test"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-providers-id-models") + tag.command("get-api-providers-id-models") .description("List models for a provider") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/{id}/models"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-providers-test-batch") + tag.command("post-api-providers-test-batch") .description("Test multiple providers at once") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/test-batch"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-providers-validate") + tag.command("post-api-providers-validate") .description("Validate provider credentials") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/validate"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-providers-client") + tag.command("get-api-providers-client") .description("Get client-side provider info") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/providers/client"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-providers-agy-auth-import") + .description("Import an Antigravity CLI (agy) token file as an `agy` connection") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/providers/agy-auth/import"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-providers-agy-auth-import-bulk") + .description("Bulk-import multiple Antigravity CLI (agy) token files (up to 50)") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/providers/agy-auth/import-bulk"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-providers-agy-auth-zip-extract") + .description("Extract `.json` token files from an uploaded ZIP for agy bulk import") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/providers/agy-auth/zip-extract"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-providers-agy-auth-apply-local") + .description("Auto-detect and import the local Antigravity CLI (agy) login from disk") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/providers/agy-auth/apply-local"; + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/quota.mjs b/bin/cli/api-commands/quota.mjs new file mode 100644 index 0000000000..5f72dad905 --- /dev/null +++ b/bin/cli/api-commands/quota.mjs @@ -0,0 +1,154 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_quota(parent) { + const tag = parent.command("quota").description("Quota endpoints"); + tag.command("get-api-quota-pools") + .description("List quota pools") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-quota-pools") + .description("Create quota pool") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-quota-pools-id-") + .description("Get quota pool by ID") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("patch-api-quota-pools-id-") + .description("Update quota pool (name or allocations)") + .requiredOption("--id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-quota-pools-id-") + .description("Delete quota pool") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-quota-pools-id-usage") + .description("Get pool usage snapshot (per-key consumption + burn rate)") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/pools/{id}/usage"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-quota-plans") + .description("List resolved provider plans (catalog + manual overrides)") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/plans"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-quota-plans-connection-id-") + .description("Get resolved plan for a connection") + .requiredOption("--connection-id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/plans/{connectionId}"; + url = url.replace("{connectionId}", encodeURIComponent(opts.connectionId ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-quota-plans-connection-id-") + .description("Upsert manual plan override for a connection") + .requiredOption("--connection-id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/plans/{connectionId}"; + url = url.replace("{connectionId}", encodeURIComponent(opts.connectionId ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-quota-plans-connection-id-") + .description("Delete manual plan override (reverts to catalog/auto)") + .requiredOption("--connection-id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/plans/{connectionId}"; + url = url.replace("{connectionId}", encodeURIComponent(opts.connectionId ?? "")); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-quota-preview") + .description("Dry-run quota enforcement check (preview only, no consumption recorded)") + .requiredOption("--api-key-id ", "") + .requiredOption("--pool-id ", "") + .option("--estimated-tokens ", "") + .option("--estimated-usd ", "") + .option("--estimated-requests ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/quota/preview"; + const qs = new URLSearchParams(); + if (opts.apiKeyId != null) qs.set("apiKeyId", String(opts.apiKeyId)); + if (opts.poolId != null) qs.set("poolId", String(opts.poolId)); + if (opts.estimatedTokens != null) qs.set("estimatedTokens", String(opts.estimatedTokens)); + if (opts.estimatedUsd != null) qs.set("estimatedUsd", String(opts.estimatedUsd)); + if (opts.estimatedRequests != null) qs.set("estimatedRequests", String(opts.estimatedRequests)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/registry.mjs b/bin/cli/api-commands/registry.mjs index e214f6cd63..95a5ec8172 100644 --- a/bin/cli/api-commands/registry.mjs +++ b/bin/cli/api-commands/registry.mjs @@ -1,4 +1,6 @@ // AUTO-GENERATED. Do not edit. +import { register_playground } from "./playground.mjs"; +import { register_memory } from "./memory.mjs"; import { register_chat } from "./chat.mjs"; import { register_messages } from "./messages.mjs"; import { register_responses } from "./responses.mjs"; @@ -19,37 +21,17 @@ import { register_usage } from "./usage.mjs"; import { register_pricing } from "./pricing.mjs"; import { register_translator } from "./translator.mjs"; import { register_cli_tools } from "./cli-tools.mjs"; +import { register_embedded_services } from "./embedded-services.mjs"; import { register_oauth } from "./oauth.mjs"; import { register_cloud } from "./cloud.mjs"; import { register_fallback } from "./fallback.mjs"; import { register_telemetry } from "./telemetry.mjs"; +import { register_quota } from "./quota.mjs"; +import { register_agentbridge } from "./agentbridge.mjs"; +import { register_traffic_inspector } from "./traffic-inspector.mjs"; +import { register_agent_skills } from "./agent-skills.mjs"; -export const API_TAGS = [ - "chat", - "messages", - "responses", - "embeddings", - "images", - "audio", - "moderations", - "rerank", - "system", - "models", - "providers", - "provider-nodes", - "api-keys", - "combos", - "settings", - "compression", - "usage", - "pricing", - "translator", - "cli-tools", - "oauth", - "cloud", - "fallback", - "telemetry", -]; +export const API_TAGS = ["playground","memory","chat","messages","responses","embeddings","images","audio","moderations","rerank","system","models","providers","provider-nodes","api-keys","combos","settings","compression","usage","pricing","translator","cli-tools","embedded-services","oauth","cloud","fallback","telemetry","quota","agentbridge","traffic-inspector","agent-skills"]; export function registerApiCommands(program) { const api = program @@ -58,9 +40,9 @@ export function registerApiCommands(program) { api .command("tags") .description("List available API tag groups") - .action(() => { - API_TAGS.forEach((t) => console.log(t)); - }); + .action(() => { API_TAGS.forEach((t) => console.log(t)); }); + register_playground(api); + register_memory(api); register_chat(api); register_messages(api); register_responses(api); @@ -81,8 +63,13 @@ export function registerApiCommands(program) { register_pricing(api); register_translator(api); register_cli_tools(api); + register_embedded_services(api); register_oauth(api); register_cloud(api); register_fallback(api); register_telemetry(api); + register_quota(api); + register_agentbridge(api); + register_traffic_inspector(api); + register_agent_skills(api); } diff --git a/bin/cli/api-commands/rerank.mjs b/bin/cli/api-commands/rerank.mjs index 56c3d69fb3..522999ede6 100644 --- a/bin/cli/api-commands/rerank.mjs +++ b/bin/cli/api-commands/rerank.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_rerank(parent) { const tag = parent.command("rerank").description("Rerank endpoints"); - tag - .command("post-api-v1-rerank") + tag.command("post-api-v1-rerank") .description("Rerank documents") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,12 +17,7 @@ export function register_rerank(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/responses.mjs b/bin/cli/api-commands/responses.mjs index 549bbed641..45ee00080e 100644 --- a/bin/cli/api-commands/responses.mjs +++ b/bin/cli/api-commands/responses.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_responses(parent) { const tag = parent.command("responses").description("Responses endpoints"); - tag - .command("post-api-v1-responses") + tag.command("post-api-v1-responses") .description("Create response (OpenAI Responses API)") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,12 +17,7 @@ export function register_responses(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/settings.mjs b/bin/cli/api-commands/settings.mjs index 31a5437df3..2a2d5ee7b5 100644 --- a/bin/cli/api-commands/settings.mjs +++ b/bin/cli/api-commands/settings.mjs @@ -5,22 +5,16 @@ import { readFileSync } from "node:fs"; export function register_settings(parent) { const tag = parent.command("settings").description("Settings endpoints"); - tag - .command("get-api-settings") + tag.command("get-api-settings") .description("Get application settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-settings") + tag.command("patch-api-settings") .description("Update settings") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -32,31 +26,20 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PATCH", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-payload-rules") + tag.command("get-api-settings-payload-rules") .description("Get payload rules configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/payload-rules"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-settings-payload-rules") + tag.command("put-api-settings-payload-rules") .description("Update payload rules configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -68,101 +51,65 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-combo-defaults") + tag.command("get-api-settings-combo-defaults") .description("Get combo default settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/combo-defaults"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-proxy") + tag.command("get-api-settings-proxy") .description("Get proxy settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/proxy"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-settings-proxy") + tag.command("patch-api-settings-proxy") .description("Update proxy settings") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/proxy"; - const res = await apiFetch(url, { - method: "PATCH", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-settings-proxy-test") + tag.command("post-api-settings-proxy-test") .description("Test proxy connection") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/proxy/test"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-settings-require-login") + tag.command("post-api-settings-require-login") .description("Toggle login requirement") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/require-login"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-ip-filter") + tag.command("get-api-settings-ip-filter") .description("Get IP filter configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/ip-filter"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-settings-ip-filter") + tag.command("put-api-settings-ip-filter") .description("Update IP filter configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -174,31 +121,20 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-system-prompt") + tag.command("get-api-settings-system-prompt") .description("Get system prompt configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/system-prompt"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-settings-system-prompt") + tag.command("put-api-settings-system-prompt") .description("Update system prompt configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -210,31 +146,20 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-settings-thinking-budget") + tag.command("get-api-settings-thinking-budget") .description("Get thinking budget configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/settings/thinking-budget"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("put-api-settings-thinking-budget") + tag.command("put-api-settings-thinking-budget") .description("Update thinking budget configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -246,31 +171,20 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PUT", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-rate-limit") + tag.command("get-api-rate-limit") .description("Get rate limit configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/rate-limit"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-rate-limit") + tag.command("post-api-rate-limit") .description("Update rate limit configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -282,12 +196,32 @@ export function register_settings(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-settings-quota-store") + .description("Get current quota store driver settings") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/quota-store"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-settings-quota-store") + .description("Update quota store driver settings") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/settings/quota-store"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/system.mjs b/bin/cli/api-commands/system.mjs index eb15c55f1c..c0def12050 100644 --- a/bin/cli/api-commands/system.mjs +++ b/bin/cli/api-commands/system.mjs @@ -5,36 +5,25 @@ import { readFileSync } from "node:fs"; export function register_system(parent) { const tag = parent.command("system").description("System endpoints"); - tag - .command("get-api-v1") + tag.command("get-api-v1") .description("API v1 root endpoint") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/v1"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-tags") + tag.command("get-api-tags") .description("List Ollama-compatible model tags") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/tags"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-auth-login") + tag.command("post-api-auth-login") .description("Authenticate user") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -46,157 +35,101 @@ export function register_system(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-auth-logout") + tag.command("post-api-auth-logout") .description("Log out") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/auth/logout"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-init") + tag.command("get-api-init") .description("Initialize application") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/init"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-restart") + tag.command("post-api-restart") .description("Restart the application") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/restart"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-shutdown") + tag.command("post-api-shutdown") .description("Shutdown the application") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/shutdown"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-db-backups") + tag.command("get-api-db-backups") .description("List database backups") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/db-backups"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-db-backups") + tag.command("post-api-db-backups") .description("Create database backup") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/db-backups"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-storage-health") + tag.command("get-api-storage-health") .description("Check storage health") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/storage/health"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-sync-cloud") + tag.command("post-api-sync-cloud") .description("Sync with cloud") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/sync/cloud"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-sync-initialize") + tag.command("post-api-sync-initialize") .description("Initialize cloud sync") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/sync/initialize"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-resilience") + tag.command("get-api-resilience") .description("Get resilience configuration") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/resilience"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("patch-api-resilience") + tag.command("patch-api-resilience") .description("Update resilience configuration") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -208,143 +141,92 @@ export function register_system(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "PATCH", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-resilience-reset") + tag.command("post-api-resilience-reset") .description("Reset circuit breakers") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/resilience/reset"; - const res = await apiFetch(url, { - method: "POST", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-monitoring-health") + tag.command("get-api-monitoring-health") .description("System health check") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/monitoring/health"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-rate-limits") + tag.command("get-api-rate-limits") .description("Get per-account rate limit status") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/rate-limits"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-sessions") + tag.command("get-api-sessions") .description("Get active sessions") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/sessions"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cache") + tag.command("get-api-cache") .description("Get cache statistics") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cache"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cache") + tag.command("delete-api-cache") .description("Clear all caches") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cache"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-cache-stats") + tag.command("get-api-cache-stats") .description("Get detailed cache statistics") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cache/stats"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-cache-stats") + tag.command("delete-api-cache-stats") .description("Clear cache statistics") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/cache/stats"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-evals") + tag.command("get-api-evals") .description("List eval suites") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/evals"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-evals") + tag.command("post-api-evals") .description("Run evaluation") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -356,47 +238,31 @@ export function register_system(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-evals-suite-id-") + tag.command("get-api-evals-suite-id-") .description("Get eval suite details") .requiredOption("--suite-id ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/evals/{suiteId}"; url = url.replace("{suiteId}", encodeURIComponent(opts.suiteId ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-policies") + tag.command("get-api-policies") .description("List routing policies") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/policies"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-policies") + tag.command("post-api-policies") .description("Create routing policy") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -408,58 +274,46 @@ export function register_system(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("delete-api-policies") + tag.command("delete-api-policies") .description("Delete routing policy") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/policies"; - const res = await apiFetch(url, { - method: "DELETE", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-compliance-audit-log") + tag.command("get-api-compliance-audit-log") .description("Get compliance audit log") + .option("--level ", "high = Activity feed events only; all = all audit events") + .option("--action ", "Filter by exact action string (e.g. \"provider.added\")") + .option("--actor ", "Filter by actor identifier") .option("--limit ", "") + .option("--offset ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/compliance/audit-log"; const qs = new URLSearchParams(); + if (opts.level != null) qs.set("level", String(opts.level)); + if (opts.action != null) qs.set("action", String(opts.action)); + if (opts.actor != null) qs.set("actor", String(opts.actor)); if (opts.limit != null) qs.set("limit", String(opts.limit)); + if (opts.offset != null) qs.set("offset", String(opts.offset)); if (qs.toString()) url += "?" + qs.toString(); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-openapi-spec") + tag.command("get-api-openapi-spec") .description("Get OpenAPI specification catalog") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/openapi/spec"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/telemetry.mjs b/bin/cli/api-commands/telemetry.mjs index c8dfa34b24..68a22de0c1 100644 --- a/bin/cli/api-commands/telemetry.mjs +++ b/bin/cli/api-commands/telemetry.mjs @@ -5,31 +5,21 @@ import { readFileSync } from "node:fs"; export function register_telemetry(parent) { const tag = parent.command("telemetry").description("Telemetry endpoints"); - tag - .command("get-api-telemetry-summary") + tag.command("get-api-telemetry-summary") .description("Get telemetry summary") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/telemetry/summary"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-token-health") + tag.command("get-api-token-health") .description("Get token health status") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/token-health"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/traffic-inspector.mjs b/bin/cli/api-commands/traffic-inspector.mjs new file mode 100644 index 0000000000..1572090b54 --- /dev/null +++ b/bin/cli/api-commands/traffic-inspector.mjs @@ -0,0 +1,307 @@ +// AUTO-GENERATED from docs/reference/openapi.yaml. Do not edit. +import { apiFetch } from "../api.mjs"; +import { emit } from "../output.mjs"; +import { readFileSync } from "node:fs"; + +export function register_traffic_inspector(parent) { + const tag = parent.command("traffic-inspector").description("Traffic Inspector endpoints"); + tag.command("get-api-tools-traffic-inspector-requests") + .description("List intercepted requests (filterable)") + .option("--profile ", "") + .option("--host ", "") + .option("--agent ", "") + .option("--status ", "") + .option("--source ", "") + .option("--session-id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/requests"; + const qs = new URLSearchParams(); + if (opts.profile != null) qs.set("profile", String(opts.profile)); + if (opts.host != null) qs.set("host", String(opts.host)); + if (opts.agent != null) qs.set("agent", String(opts.agent)); + if (opts.status != null) qs.set("status", String(opts.status)); + if (opts.source != null) qs.set("source", String(opts.source)); + if (opts.sessionId != null) qs.set("sessionId", String(opts.sessionId)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-tools-traffic-inspector-requests") + .description("Clear the in-memory traffic buffer") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/requests"; + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-requests-id-") + .description("Get a single intercepted request by ID") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/requests/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-requests-id-replay") + .description("Replay a captured request through OmniRoute router") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/requests/{id}/replay"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "POST", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("put-api-tools-traffic-inspector-requests-id-annotation") + .description("Save or update annotation on a request") + .requiredOption("--id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/requests/{id}/annotation"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PUT", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-ws") + .description("Live WebSocket stream of intercepted requests") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/ws"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-export-har") + .description("Export current filtered request list as HAR 1.2") + .option("--profile ", "") + .option("--session-id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/export.har"; + const qs = new URLSearchParams(); + if (opts.profile != null) qs.set("profile", String(opts.profile)); + if (opts.sessionId != null) qs.set("sessionId", String(opts.sessionId)); + if (qs.toString()) url += "?" + qs.toString(); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-hosts") + .description("List custom capture hosts") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/hosts"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-hosts") + .description("Add a custom capture host (edits /etc/hosts)") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/hosts"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-tools-traffic-inspector-hosts-host-") + .description("Remove a custom capture host") + .requiredOption("--host ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/hosts/{host}"; + url = url.replace("{host}", encodeURIComponent(opts.host ?? "")); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("patch-api-tools-traffic-inspector-hosts-host-") + .description("Toggle enabled state of a custom host") + .requiredOption("--host ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/hosts/{host}"; + url = url.replace("{host}", encodeURIComponent(opts.host ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-capture-modes") + .description("Get state of all 4 capture modes") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/capture-modes"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-capture-modes-http-proxy") + .description("Start or stop the HTTP_PROXY listener (port 8080)") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/capture-modes/http-proxy"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-capture-modes-system-proxy") + .description("Apply or revert system-wide proxy settings") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/capture-modes/system-proxy"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-capture-modes-tls-intercept") + .description("Toggle TLS body decryption in HTTP_PROXY mode") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/capture-modes/tls-intercept"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-sessions") + .description("List all saved recording sessions") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions"; + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-sessions") + .description("Start a new recording session") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-sessions-id-") + .description("Get session snapshot (all captured requests)") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("patch-api-tools-traffic-inspector-sessions-id-") + .description("Stop or rename a recording session") + .requiredOption("--id ", "") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "PATCH", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("delete-api-tools-traffic-inspector-sessions-id-") + .description("Delete a recording session") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions/{id}"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "DELETE", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("get-api-tools-traffic-inspector-sessions-id-export-har") + .description("Export a recorded session as HAR 1.2") + .requiredOption("--id ", "") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/sessions/{id}/export.har"; + url = url.replace("{id}", encodeURIComponent(opts.id ?? "")); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); + tag.command("post-api-tools-traffic-inspector-internal-ingest") + .description("Internal ingest endpoint for server.cjs passthrough path") + .option("--body ", "JSON body or @path/to/file.json") + .action(async (opts, cmd) => { + const gOpts = cmd.optsWithGlobals(); + let url = "/api/tools/traffic-inspector/internal/ingest"; + let body; + if (opts.body) { + body = opts.body.startsWith("@") + ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) + : JSON.parse(opts.body); + } + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); + const data = res.ok ? await res.json() : await res.text(); + emit(data, gOpts); + }); +} diff --git a/bin/cli/api-commands/translator.mjs b/bin/cli/api-commands/translator.mjs index dae8df965c..10c1a03e22 100644 --- a/bin/cli/api-commands/translator.mjs +++ b/bin/cli/api-commands/translator.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_translator(parent) { const tag = parent.command("translator").description("Translator endpoints"); - tag - .command("post-api-translator-detect") + tag.command("post-api-translator-detect") .description("Detect request format") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -18,17 +17,11 @@ export function register_translator(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-translator-translate") + tag.command("post-api-translator-translate") .description("Translate between formats") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -40,17 +33,11 @@ export function register_translator(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-translator-send") + tag.command("post-api-translator-send") .description("Send translated request to provider") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -62,26 +49,16 @@ export function register_translator(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-translator-history") + tag.command("get-api-translator-history") .description("Get translation history") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/translator/history"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/bin/cli/api-commands/usage.mjs b/bin/cli/api-commands/usage.mjs index a8d3b7ce4c..40a8b1afb1 100644 --- a/bin/cli/api-commands/usage.mjs +++ b/bin/cli/api-commands/usage.mjs @@ -5,8 +5,7 @@ import { readFileSync } from "node:fs"; export function register_usage(parent) { const tag = parent.command("usage").description("Usage endpoints"); - tag - .command("get-api-usage-analytics") + tag.command("get-api-usage-analytics") .description("Get usage analytics") .option("--period ", "") .action(async (opts, cmd) => { @@ -15,16 +14,11 @@ export function register_usage(parent) { const qs = new URLSearchParams(); if (opts.period != null) qs.set("period", String(opts.period)); if (qs.toString()) url += "?" + qs.toString(); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-call-logs") + tag.command("get-api-usage-call-logs") .description("Get call logs") .option("--limit ", "") .option("--offset ", "") @@ -35,116 +29,76 @@ export function register_usage(parent) { if (opts.limit != null) qs.set("limit", String(opts.limit)); if (opts.offset != null) qs.set("offset", String(opts.offset)); if (qs.toString()) url += "?" + qs.toString(); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-call-logs-id-") + tag.command("get-api-usage-call-logs-id-") .description("Get a specific call log") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/call-logs/{id}"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-connection-id-") + tag.command("get-api-usage-connection-id-") .description("Get usage for a specific connection") .requiredOption("--connection-id ", "") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/{connectionId}"; url = url.replace("{connectionId}", encodeURIComponent(opts.connectionId ?? "")); - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-history") + tag.command("get-api-usage-history") .description("Get usage history") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/history"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-logs") + tag.command("get-api-usage-logs") .description("Get usage logs") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/logs"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-proxy-logs") + tag.command("get-api-usage-proxy-logs") .description("Get proxy logs") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/proxy-logs"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-request-logs") + tag.command("get-api-usage-request-logs") .description("Get request logs") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/request-logs"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("get-api-usage-budget") + tag.command("get-api-usage-budget") .description("Get usage budget status") .action(async (opts, cmd) => { const gOpts = cmd.optsWithGlobals(); let url = "/api/usage/budget"; - const res = await apiFetch(url, { - method: "GET", - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "GET", baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); - tag - .command("post-api-usage-budget") + tag.command("post-api-usage-budget") .description("Configure usage budget") .option("--body ", "JSON body or @path/to/file.json") .action(async (opts, cmd) => { @@ -156,12 +110,7 @@ export function register_usage(parent) { ? JSON.parse(readFileSync(opts.body.slice(1), "utf8")) : JSON.parse(opts.body); } - const res = await apiFetch(url, { - method: "POST", - body, - baseUrl: gOpts.baseUrl, - apiKey: gOpts.apiKey, - }); + const res = await apiFetch(url, { method: "POST", body, baseUrl: gOpts.baseUrl, apiKey: gOpts.apiKey }); const data = res.ok ? await res.json() : await res.text(); emit(data, gOpts); }); diff --git a/electron/package-lock.json b/electron/package-lock.json index 8206cb09e3..fdb25d1b99 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "omniroute-desktop", - "version": "3.8.20", + "version": "3.8.23", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omniroute-desktop", - "version": "3.8.20", + "version": "3.8.23", "license": "MIT", "dependencies": { "electron-updater": "^6.8.9" diff --git a/scripts/check/check-env-doc-sync.mjs b/scripts/check/check-env-doc-sync.mjs index 3fae1fdc70..cc5de4f713 100644 --- a/scripts/check/check-env-doc-sync.mjs +++ b/scripts/check/check-env-doc-sync.mjs @@ -131,6 +131,12 @@ const IGNORE_FROM_CODE = new Set([ // NVIDIA diagnostic/test helpers used only by ad-hoc scripts. "NVIDIA_BASE_URL", "NVIDIA_MODEL", + // XDG standard data directory β€” set by OS/desktop session, not OmniRoute config. + // Read by setup-open-code.mjs to locate platform-specific OpenCode data dir. + "XDG_DATA_HOME", + // Test-only override: points setup-open-code.mjs at a fixture plugin dir without + // requiring the real bundled plugin to be built. + "OMNIROUTE_OPENCODE_PLUGIN_DIR", ]); // Vars documented in ENVIRONMENT.md but intentionally absent from .env.example. diff --git a/scripts/dev/webdav-handler.mjs b/scripts/dev/webdav-handler.mjs index 0113cc1b65..3b0a0893b4 100644 --- a/scripts/dev/webdav-handler.mjs +++ b/scripts/dev/webdav-handler.mjs @@ -663,6 +663,7 @@ async function handlePut(req, res, absPath) { limitExceeded = true; req.destroy(); writeStream.destroy(); + resolve(); } else { writeStream.write(chunk); } @@ -670,7 +671,7 @@ async function handlePut(req, res, absPath) { req.on("end", () => { writeStream.end(); - resolve(); + // Don't resolve here β€” wait for the stream to finish flushing. }); req.on("error", () => { @@ -678,9 +679,10 @@ async function handlePut(req, res, absPath) { resolve(); }); - writeStream.on("error", () => { - resolve(); - }); + // Resolve only after all data has been flushed to the OS (prevents + // fs.renameSync from running before the write stream closes the file). + writeStream.on("finish", resolve); + writeStream.on("error", resolve); }); if (limitExceeded) { diff --git a/tests/unit/autoCombo/tieredRotation.test.ts b/tests/unit/autoCombo/tieredRotation.test.ts index 21c74ed098..dd2974b7bb 100644 --- a/tests/unit/autoCombo/tieredRotation.test.ts +++ b/tests/unit/autoCombo/tieredRotation.test.ts @@ -4,7 +4,7 @@ * and that tiered rotation distributes traffic fairly. */ -import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { selectProvider, type AutoComboConfig } from "../../../open-sse/services/autoCombo/engine"; import { calculateFactors, @@ -17,6 +17,15 @@ import { import { getTaskFitness } from "../../../open-sse/services/autoCombo/taskFitness"; import { resetDiversity } from "../../../open-sse/services/autoCombo/providerDiversity"; +// Stub DB calls introduced by PR #3660 (Arena ELO / models.dev intelligence scoring). +// This file tests rotation logic, not intelligence scoring β€” the DB shouldn't be +// initialized during these unit tests, and the stub makes them fast and isolated. +vi.mock("../../../src/lib/db/modelIntelligence.ts", () => ({ + getModelIntelligenceBySource: vi.fn(() => null), + setUserFitnessOverrideEntry: vi.fn(), + deleteUserFitnessOverrideEntry: vi.fn(), +})); + function makeCandidate(overrides: Partial): ProviderCandidate { return { provider: "unknown",