chorus-codes 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/cache/.previewinfo +1 -1
- package/.next/cache/.rscinfo +1 -1
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/new.html +1 -1
- package/.next/server/app/new.rsc +1 -1
- package/.next/server/app/new.segments/_full.segment.rsc +1 -1
- package/.next/server/app/new.segments/_head.segment.rsc +1 -1
- package/.next/server/app/new.segments/_index.segment.rsc +1 -1
- package/.next/server/app/new.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/new.segments/new/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/new.segments/new.segment.rsc +1 -1
- package/.next/server/app/onboarding.html +1 -1
- package/.next/server/app/onboarding.rsc +1 -1
- package/.next/server/app/onboarding.segments/_full.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_index.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
- package/.next/server/app/personas.html +1 -1
- package/.next/server/app/personas.rsc +1 -1
- package/.next/server/app/personas.segments/_full.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_head.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_index.segment.rsc +1 -1
- package/.next/server/app/personas.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/personas.segments/personas/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/personas.segments/personas.segment.rsc +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +1 -1
- package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- package/.next/server/app/templates.html +1 -1
- package/.next/server/app/templates.rsc +1 -1
- package/.next/server/app/templates.segments/_full.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_head.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_index.segment.rsc +1 -1
- package/.next/server/app/templates.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/templates.segments/templates/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/templates.segments/templates.segment.rsc +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/trace +1 -1
- package/.next/trace-build +1 -1
- package/dist/cli/commands/doctor.js +116 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/init.js +211 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/start.js +240 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.js +54 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.js +97 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/connect.js +108 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/port-utils.js +260 -0
- package/dist/cli/port-utils.js.map +1 -0
- package/dist/cli/runtime-env.js +60 -0
- package/dist/cli/runtime-env.js.map +1 -0
- package/dist/cli/shared.js +54 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli/ui.js +60 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/daemon/agents/claude.js +98 -0
- package/dist/daemon/agents/claude.js.map +1 -0
- package/dist/daemon/agents/codex.js +160 -0
- package/dist/daemon/agents/codex.js.map +1 -0
- package/dist/daemon/agents/gemini.js +111 -0
- package/dist/daemon/agents/gemini.js.map +1 -0
- package/dist/daemon/agents/index.js +59 -0
- package/dist/daemon/agents/index.js.map +1 -0
- package/dist/daemon/agents/kimi.js +206 -0
- package/dist/daemon/agents/kimi.js.map +1 -0
- package/dist/daemon/agents/opencode.js +228 -0
- package/dist/daemon/agents/opencode.js.map +1 -0
- package/dist/daemon/agents/openrouter.js +274 -0
- package/dist/daemon/agents/openrouter.js.map +1 -0
- package/dist/daemon/agents/parsers/claude.js +63 -0
- package/dist/daemon/agents/parsers/claude.js.map +1 -0
- package/dist/daemon/agents/parsers/codex.js +51 -0
- package/dist/daemon/agents/parsers/codex.js.map +1 -0
- package/dist/daemon/agents/parsers/gemini.js +144 -0
- package/dist/daemon/agents/parsers/gemini.js.map +1 -0
- package/dist/daemon/agents/parsers/index.js +31 -0
- package/dist/daemon/agents/parsers/index.js.map +1 -0
- package/dist/daemon/agents/parsers/kimi.js +8 -0
- package/dist/daemon/agents/parsers/kimi.js.map +1 -0
- package/dist/daemon/agents/parsers/opencode.js +105 -0
- package/dist/daemon/agents/parsers/opencode.js.map +1 -0
- package/dist/daemon/agents/parsers/openrouter.js +69 -0
- package/dist/daemon/agents/parsers/openrouter.js.map +1 -0
- package/dist/daemon/agents/parsers/shared.js +17 -0
- package/dist/daemon/agents/parsers/shared.js.map +1 -0
- package/dist/daemon/agents/preflight.js +83 -0
- package/dist/daemon/agents/preflight.js.map +1 -0
- package/dist/daemon/agents/quote.js +45 -0
- package/dist/daemon/agents/quote.js.map +1 -0
- package/dist/daemon/agents/sandbox-guard.js +69 -0
- package/dist/daemon/agents/sandbox-guard.js.map +1 -0
- package/dist/daemon/agents/types.js +6 -0
- package/dist/daemon/agents/types.js.map +1 -0
- package/dist/daemon/api-response.js +65 -0
- package/dist/daemon/api-response.js.map +1 -0
- package/dist/daemon/error-detector.js +329 -0
- package/dist/daemon/error-detector.js.map +1 -0
- package/dist/daemon/headless.js +533 -0
- package/dist/daemon/headless.js.map +1 -0
- package/dist/daemon/index.js +333 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/openrouter.js +192 -0
- package/dist/daemon/openrouter.js.map +1 -0
- package/dist/daemon/orchestrators/claude.js +163 -0
- package/dist/daemon/orchestrators/claude.js.map +1 -0
- package/dist/daemon/orchestrators/codex.js +101 -0
- package/dist/daemon/orchestrators/codex.js.map +1 -0
- package/dist/daemon/orchestrators/cursor-windsurf.js +118 -0
- package/dist/daemon/orchestrators/cursor-windsurf.js.map +1 -0
- package/dist/daemon/orchestrators/gemini.js +108 -0
- package/dist/daemon/orchestrators/gemini.js.map +1 -0
- package/dist/daemon/orchestrators/index.js +90 -0
- package/dist/daemon/orchestrators/index.js.map +1 -0
- package/dist/daemon/orchestrators/kimi.js +108 -0
- package/dist/daemon/orchestrators/kimi.js.map +1 -0
- package/dist/daemon/orchestrators/opencode.js +152 -0
- package/dist/daemon/orchestrators/opencode.js.map +1 -0
- package/dist/daemon/orchestrators/shared.js +60 -0
- package/dist/daemon/orchestrators/shared.js.map +1 -0
- package/dist/daemon/output-watcher.js +131 -0
- package/dist/daemon/output-watcher.js.map +1 -0
- package/dist/daemon/participant-aborts.js +123 -0
- package/dist/daemon/participant-aborts.js.map +1 -0
- package/dist/daemon/reaper.js +46 -0
- package/dist/daemon/reaper.js.map +1 -0
- package/dist/daemon/routes/chats-events.js +62 -0
- package/dist/daemon/routes/chats-events.js.map +1 -0
- package/dist/daemon/routes/chats-stream.js +241 -0
- package/dist/daemon/routes/chats-stream.js.map +1 -0
- package/dist/daemon/routes/chats-validation.js +13 -0
- package/dist/daemon/routes/chats-validation.js.map +1 -0
- package/dist/daemon/routes/chats.js +545 -0
- package/dist/daemon/routes/chats.js.map +1 -0
- package/dist/daemon/routes/openrouter.js +103 -0
- package/dist/daemon/routes/openrouter.js.map +1 -0
- package/dist/daemon/routes/settings.js +199 -0
- package/dist/daemon/routes/settings.js.map +1 -0
- package/dist/daemon/routes/stats.js +155 -0
- package/dist/daemon/routes/stats.js.map +1 -0
- package/dist/daemon/routes/system.js +208 -0
- package/dist/daemon/routes/system.js.map +1 -0
- package/dist/daemon/routes/templates-personas.js +254 -0
- package/dist/daemon/routes/templates-personas.js.map +1 -0
- package/dist/daemon/routes/voices.js +139 -0
- package/dist/daemon/routes/voices.js.map +1 -0
- package/dist/daemon/runner/doer-driver.js +346 -0
- package/dist/daemon/runner/doer-driver.js.map +1 -0
- package/dist/daemon/runner/doer.js +336 -0
- package/dist/daemon/runner/doer.js.map +1 -0
- package/dist/daemon/runner/prior-round.js +140 -0
- package/dist/daemon/runner/prior-round.js.map +1 -0
- package/dist/daemon/runner/prompt-builder.js +292 -0
- package/dist/daemon/runner/prompt-builder.js.map +1 -0
- package/dist/daemon/runner/review-only-phase.js +103 -0
- package/dist/daemon/runner/review-only-phase.js.map +1 -0
- package/dist/daemon/runner/reviewer-driver.js +410 -0
- package/dist/daemon/runner/reviewer-driver.js.map +1 -0
- package/dist/daemon/runner/reviewer.js +384 -0
- package/dist/daemon/runner/reviewer.js.map +1 -0
- package/dist/daemon/runner/run-with-fallback.js +56 -0
- package/dist/daemon/runner/run-with-fallback.js.map +1 -0
- package/dist/daemon/runner/sanitize-name.js +8 -0
- package/dist/daemon/runner/sanitize-name.js.map +1 -0
- package/dist/daemon/runner/stream-file-writer.js +116 -0
- package/dist/daemon/runner/stream-file-writer.js.map +1 -0
- package/dist/daemon/runner/swap-sidecar.js +102 -0
- package/dist/daemon/runner/swap-sidecar.js.map +1 -0
- package/dist/daemon/runner/template-fallback.js +119 -0
- package/dist/daemon/runner/template-fallback.js.map +1 -0
- package/dist/daemon/runner/types.js +3 -0
- package/dist/daemon/runner/types.js.map +1 -0
- package/dist/daemon/runner/verdict.js +51 -0
- package/dist/daemon/runner/verdict.js.map +1 -0
- package/dist/daemon/runner-multiplex.js +364 -0
- package/dist/daemon/runner-multiplex.js.map +1 -0
- package/dist/daemon/runner.js +427 -0
- package/dist/daemon/runner.js.map +1 -0
- package/dist/daemon/ship.js +340 -0
- package/dist/daemon/ship.js.map +1 -0
- package/dist/daemon/template-cache.js +37 -0
- package/dist/daemon/template-cache.js.map +1 -0
- package/dist/daemon/tmux-types.js +9 -0
- package/dist/daemon/tmux-types.js.map +1 -0
- package/dist/daemon/tmux.js +341 -0
- package/dist/daemon/tmux.js.map +1 -0
- package/dist/lib/atomic-write.js +55 -0
- package/dist/lib/atomic-write.js.map +1 -0
- package/dist/lib/chat-events-bus.js +27 -0
- package/dist/lib/chat-events-bus.js.map +1 -0
- package/dist/lib/chat-slug.js +105 -0
- package/dist/lib/chat-slug.js.map +1 -0
- package/dist/lib/cli-detect.js +388 -0
- package/dist/lib/cli-detect.js.map +1 -0
- package/dist/lib/cli-health.js +156 -0
- package/dist/lib/cli-health.js.map +1 -0
- package/dist/lib/cli-paths.js +113 -0
- package/dist/lib/cli-paths.js.map +1 -0
- package/dist/lib/cli-precheck.js +141 -0
- package/dist/lib/cli-precheck.js.map +1 -0
- package/dist/lib/db/chats.js +244 -0
- package/dist/lib/db/chats.js.map +1 -0
- package/dist/lib/db/connection.js +254 -0
- package/dist/lib/db/connection.js.map +1 -0
- package/dist/lib/db/index.js +34 -0
- package/dist/lib/db/index.js.map +1 -0
- package/dist/lib/db/personas.js +65 -0
- package/dist/lib/db/personas.js.map +1 -0
- package/dist/lib/db/phase-events.js +172 -0
- package/dist/lib/db/phase-events.js.map +1 -0
- package/dist/lib/db/secrets.js +53 -0
- package/dist/lib/db/secrets.js.map +1 -0
- package/dist/lib/db/settings.js +47 -0
- package/dist/lib/db/settings.js.map +1 -0
- package/dist/lib/db/templates.js +75 -0
- package/dist/lib/db/templates.js.map +1 -0
- package/dist/lib/db/voices.js +184 -0
- package/dist/lib/db/voices.js.map +1 -0
- package/dist/lib/lineage-maps.js +200 -0
- package/dist/lib/lineage-maps.js.map +1 -0
- package/dist/lib/logger.js +186 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/personas.js +117 -0
- package/dist/lib/personas.js.map +1 -0
- package/dist/lib/runtime-path.js +222 -0
- package/dist/lib/runtime-path.js.map +1 -0
- package/dist/lib/settings/billing.js +58 -0
- package/dist/lib/settings/billing.js.map +1 -0
- package/dist/lib/settings/permissions.js +81 -0
- package/dist/lib/settings/permissions.js.map +1 -0
- package/dist/lib/settings/transport.js +113 -0
- package/dist/lib/settings/transport.js.map +1 -0
- package/dist/lib/telemetry.js +290 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/template-schema.js +319 -0
- package/dist/lib/template-schema.js.map +1 -0
- package/dist/lib/template-validation.js +82 -0
- package/dist/lib/template-validation.js.map +1 -0
- package/dist/lib/voices.js +533 -0
- package/dist/lib/voices.js.map +1 -0
- package/dist/mcp/client.js +138 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/index.js +178 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/tools.js +355 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +2 -1
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js +0 -6077
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js.map +0 -69
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js +0 -6318
- package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js.map +0 -71
- package/.next/dev/types/cache-life.d.ts +0 -145
- package/.next/dev/types/routes.d.ts +0 -84
- package/.next/dev/types/validator.ts +0 -178
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_buildManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Detect whether each supported CLI is installed and runnable.
|
|
4
|
+
*
|
|
5
|
+
* Layered probe:
|
|
6
|
+
* 1. PATH lookup via `which` (Unix) / `where` (Windows)
|
|
7
|
+
* 2. Fallback known install dirs per CLI (covers OpenCode/Kimi installers
|
|
8
|
+
* that drop binaries in non-PATH locations)
|
|
9
|
+
* 3. Verify with `<bin> --version` (2s timeout) so dead symlinks fail
|
|
10
|
+
*
|
|
11
|
+
* Cursor and Windsurf are IDEs invoked via MCP, not CLIs on PATH, so they're
|
|
12
|
+
* not part of this probe — onboarding leaves their checkboxes for the user.
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.detectAllClis = detectAllClis;
|
|
19
|
+
exports.clearDetectionCache = clearDetectionCache;
|
|
20
|
+
exports.validateCliPath = validateCliPath;
|
|
21
|
+
const child_process_1 = require("child_process");
|
|
22
|
+
const fs_1 = require("fs");
|
|
23
|
+
const os_1 = require("os");
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const cli_paths_js_1 = require("./cli-paths.js");
|
|
26
|
+
const BINARY_NAME = {
|
|
27
|
+
'claude-code': 'claude',
|
|
28
|
+
'codex-cli': 'codex',
|
|
29
|
+
'gemini-cli': 'gemini',
|
|
30
|
+
'opencode-cli': 'opencode',
|
|
31
|
+
'kimi-cli': 'kimi',
|
|
32
|
+
};
|
|
33
|
+
const isWindows = (0, os_1.platform)() === 'win32';
|
|
34
|
+
const HOME = (0, os_1.homedir)();
|
|
35
|
+
/**
|
|
36
|
+
* Discovered npm prefix bin dirs — populated lazily by `discoverNpmPrefixes`.
|
|
37
|
+
* Cached at module scope so we shell out once per daemon lifetime, not once
|
|
38
|
+
* per CLI per probe.
|
|
39
|
+
*/
|
|
40
|
+
let cachedNpmDirs = null;
|
|
41
|
+
/**
|
|
42
|
+
* Ask npm where it installs global binaries. Covers users with custom
|
|
43
|
+
* `prefix` configs (e.g. ~/.npm-global, ~/.config/npm), nvm-active
|
|
44
|
+
* versions, or an OS package manager that put npm in a non-default
|
|
45
|
+
* location. Best-effort — a missing/broken npm just yields an empty
|
|
46
|
+
* list so we fall back to the static probes.
|
|
47
|
+
*/
|
|
48
|
+
function discoverNpmPrefixes() {
|
|
49
|
+
if (cachedNpmDirs !== null)
|
|
50
|
+
return cachedNpmDirs;
|
|
51
|
+
const dirs = new Set();
|
|
52
|
+
// Try `npm config get prefix` (1s budget — slow npm shouldn't block detect).
|
|
53
|
+
try {
|
|
54
|
+
const result = (0, child_process_1.spawnSync)('npm', ['config', 'get', 'prefix'], {
|
|
55
|
+
encoding: 'utf-8',
|
|
56
|
+
timeout: 1000,
|
|
57
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
58
|
+
});
|
|
59
|
+
if (result.status === 0) {
|
|
60
|
+
const prefix = result.stdout.trim();
|
|
61
|
+
if (prefix) {
|
|
62
|
+
dirs.add(isWindows ? prefix : path_1.default.join(prefix, 'bin'));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* npm not installed / not on PATH — fall through */
|
|
68
|
+
}
|
|
69
|
+
// NPM_CONFIG_PREFIX env override (common in CI, asdf, custom shells).
|
|
70
|
+
const envPrefix = process.env.NPM_CONFIG_PREFIX || process.env.npm_config_prefix;
|
|
71
|
+
if (envPrefix) {
|
|
72
|
+
dirs.add(isWindows ? envPrefix : path_1.default.join(envPrefix, 'bin'));
|
|
73
|
+
}
|
|
74
|
+
cachedNpmDirs = Array.from(dirs);
|
|
75
|
+
return cachedNpmDirs;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Per-CLI fallback install locations to probe when PATH lookup misses.
|
|
79
|
+
*
|
|
80
|
+
* Covers the common installers in the wild — npm global with various
|
|
81
|
+
* prefixes (default, custom, volta, fnm, nvm), Yarn, PNPM, Bun, Cargo,
|
|
82
|
+
* Homebrew (Intel + Apple Silicon), system package dirs — plus per-CLI
|
|
83
|
+
* installer-script locations (OpenCode + Kimi drop binaries in their
|
|
84
|
+
* own dot-folders by default).
|
|
85
|
+
*
|
|
86
|
+
* Order matters: PATH lookup runs first; this list is the second-chance
|
|
87
|
+
* scan, so cheap/common locations come first to keep the probe fast.
|
|
88
|
+
*/
|
|
89
|
+
function fallbackPaths(cli) {
|
|
90
|
+
const bin = BINARY_NAME[cli];
|
|
91
|
+
const exts = isWindows ? ['.cmd', '.exe', ''] : [''];
|
|
92
|
+
const dirs = [];
|
|
93
|
+
if (isWindows) {
|
|
94
|
+
if (process.env.APPDATA)
|
|
95
|
+
dirs.push(path_1.default.join(process.env.APPDATA, 'npm'));
|
|
96
|
+
if (process.env.LOCALAPPDATA) {
|
|
97
|
+
dirs.push(path_1.default.join(process.env.LOCALAPPDATA, 'Programs'),
|
|
98
|
+
// Volta on Windows
|
|
99
|
+
path_1.default.join(process.env.LOCALAPPDATA, 'Volta', 'bin'));
|
|
100
|
+
}
|
|
101
|
+
dirs.push(path_1.default.join(HOME, 'AppData', 'Roaming', 'npm'), path_1.default.join(HOME, '.volta', 'bin'), path_1.default.join(HOME, '.bun', 'bin'));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
dirs.push(
|
|
105
|
+
// User-local
|
|
106
|
+
path_1.default.join(HOME, '.local', 'bin'), path_1.default.join(HOME, '.npm-global', 'bin'), path_1.default.join(HOME, '.config', 'yarn', 'global', 'node_modules', '.bin'), path_1.default.join(HOME, '.yarn', 'bin'),
|
|
107
|
+
// Node version managers
|
|
108
|
+
path_1.default.join(HOME, '.volta', 'bin'), path_1.default.join(HOME, '.fnm', 'aliases', 'default', 'bin'),
|
|
109
|
+
// Alt package managers
|
|
110
|
+
path_1.default.join(HOME, '.bun', 'bin'), path_1.default.join(HOME, '.cargo', 'bin'), path_1.default.join(HOME, '.local', 'share', 'pnpm'), path_1.default.join(HOME, 'Library', 'pnpm'),
|
|
111
|
+
// System-wide
|
|
112
|
+
'/usr/local/bin', '/opt/homebrew/bin', '/usr/bin',
|
|
113
|
+
// Common npm-global system dirs
|
|
114
|
+
'/usr/local/lib/node_modules/.bin', '/opt/homebrew/lib/node_modules/.bin');
|
|
115
|
+
}
|
|
116
|
+
// CLI-specific installer locations (their own install scripts).
|
|
117
|
+
if (cli === 'opencode-cli') {
|
|
118
|
+
dirs.push(path_1.default.join(HOME, '.opencode', 'bin'));
|
|
119
|
+
}
|
|
120
|
+
if (cli === 'kimi-cli') {
|
|
121
|
+
dirs.push(path_1.default.join(HOME, '.kimi', 'bin'));
|
|
122
|
+
}
|
|
123
|
+
// npm-discovered prefixes — cheapest signal for "where did the user
|
|
124
|
+
// actually install global packages?". Pulled last so the static list
|
|
125
|
+
// wins on cache hits, but still covers exotic setups.
|
|
126
|
+
for (const npmDir of discoverNpmPrefixes()) {
|
|
127
|
+
dirs.push(npmDir);
|
|
128
|
+
}
|
|
129
|
+
const candidates = [];
|
|
130
|
+
// Dedup while preserving order — a user with PNPM_HOME=~/.local/share/pnpm
|
|
131
|
+
// shouldn't pay for two probes of the same dir.
|
|
132
|
+
const seen = new Set();
|
|
133
|
+
for (const dir of dirs) {
|
|
134
|
+
for (const ext of exts) {
|
|
135
|
+
const full = path_1.default.join(dir, `${bin}${ext}`);
|
|
136
|
+
if (seen.has(full))
|
|
137
|
+
continue;
|
|
138
|
+
seen.add(full);
|
|
139
|
+
candidates.push(full);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return candidates;
|
|
143
|
+
}
|
|
144
|
+
function pathLookup(name) {
|
|
145
|
+
const cmd = isWindows ? 'where' : 'which';
|
|
146
|
+
const result = (0, child_process_1.spawnSync)(cmd, [name], { encoding: 'utf-8' });
|
|
147
|
+
if (result.status !== 0)
|
|
148
|
+
return null;
|
|
149
|
+
// `where` returns one path per line on Windows; take the first.
|
|
150
|
+
const first = result.stdout.split(/\r?\n/).map((s) => s.trim()).find((s) => s.length > 0);
|
|
151
|
+
return first || null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Per-CLI version-output signatures. The shape varies wildly between
|
|
155
|
+
* CLIs — claude prints "2.1.126 (Claude Code)", codex prints
|
|
156
|
+
* "codex-cli 0.128.0", but gemini / opencode print just a bare
|
|
157
|
+
* version like "0.40.1" with NO CLI name. So each CLI gets its own
|
|
158
|
+
* matcher rather than a uniform name-substring regex.
|
|
159
|
+
*
|
|
160
|
+
* Strategy:
|
|
161
|
+
* - CLIs whose output includes the name → match the name (case-insensitive).
|
|
162
|
+
* - CLIs that print a bare version → accept output that STARTS with a
|
|
163
|
+
* digit-dot-digit (semver-ish). This rules out e.g. `cat --version`
|
|
164
|
+
* (output starts with "cat (GNU…") while accepting any reasonable
|
|
165
|
+
* `<bin> --version` from a real install.
|
|
166
|
+
*
|
|
167
|
+
* False positives here (a runnable binary that happens to print a bare
|
|
168
|
+
* version) are still better than rubber-stamping `cat --version` as a
|
|
169
|
+
* valid Claude install — which is what the original exit-0-only check
|
|
170
|
+
* did.
|
|
171
|
+
*/
|
|
172
|
+
const STARTS_WITH_VERSION = /^\s*\d+\.\d+/;
|
|
173
|
+
const CLI_SIGNATURES = {
|
|
174
|
+
'claude-code': /\bclaude\b/i,
|
|
175
|
+
'codex-cli': /\bcodex\b/i,
|
|
176
|
+
// Bare version output — "0.40.1" — no CLI name to grep for.
|
|
177
|
+
'gemini-cli': STARTS_WITH_VERSION,
|
|
178
|
+
// Bare version output — "1.14.30" — same as gemini.
|
|
179
|
+
'opencode-cli': STARTS_WITH_VERSION,
|
|
180
|
+
'kimi-cli': /\bkimi\b/i,
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Basename allowlist — the binary's filename must match the expected
|
|
184
|
+
* name (case-insensitive, .exe/.cmd suffixes stripped) before we even
|
|
185
|
+
* try to verify the version output. This is the primary guard against
|
|
186
|
+
* the STARTS_WITH_VERSION regex being too permissive: `npm --version`
|
|
187
|
+
* prints "11.7.0" and would otherwise pass as gemini/opencode. The
|
|
188
|
+
* regex stays as a secondary check — a binary that's named correctly
|
|
189
|
+
* but whose --version output is total junk still gets rejected.
|
|
190
|
+
*
|
|
191
|
+
* Validated locally before adding (2026-05-04):
|
|
192
|
+
* npm 11.7.0 → matches version regex (would've false-passed)
|
|
193
|
+
* pip 24.0 → no (starts with "pip ")
|
|
194
|
+
* node v20.19 → no (starts with "v")
|
|
195
|
+
* python 3.12 → no (starts with "Python ")
|
|
196
|
+
*/
|
|
197
|
+
function basenameMatches(cli, binPath) {
|
|
198
|
+
const expected = BINARY_NAME[cli].toLowerCase();
|
|
199
|
+
const base = path_1.default.basename(binPath).toLowerCase();
|
|
200
|
+
// Strip Windows extensions so claude.exe / claude.cmd both match "claude".
|
|
201
|
+
const stripped = base.replace(/\.(exe|cmd|bat|ps1)$/i, '');
|
|
202
|
+
return stripped === expected;
|
|
203
|
+
}
|
|
204
|
+
function verifyRunnable(cli, binPath, timeoutMs = 2000) {
|
|
205
|
+
if (!(0, fs_1.existsSync)(binPath)) {
|
|
206
|
+
return { ok: false, reason: 'no file at that path' };
|
|
207
|
+
}
|
|
208
|
+
if (!basenameMatches(cli, binPath)) {
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
reason: `expected a binary named "${BINARY_NAME[cli]}" — got "${path_1.default.basename(binPath)}"`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
let result;
|
|
215
|
+
try {
|
|
216
|
+
result = (0, child_process_1.spawnSync)(binPath, ['--version'], {
|
|
217
|
+
encoding: 'utf-8',
|
|
218
|
+
timeout: timeoutMs,
|
|
219
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
return { ok: false, reason: `failed to spawn (${err.message})` };
|
|
224
|
+
}
|
|
225
|
+
if (result.status !== 0) {
|
|
226
|
+
return {
|
|
227
|
+
ok: false,
|
|
228
|
+
reason: `${path_1.default.basename(binPath)} --version exited ${result.status}`,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const output = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
|
|
232
|
+
const signature = CLI_SIGNATURES[cli];
|
|
233
|
+
if (!signature.test(output)) {
|
|
234
|
+
return {
|
|
235
|
+
ok: false,
|
|
236
|
+
reason: `that binary ran, but its --version output doesn't look like the ${BINARY_NAME[cli]} CLI`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return { ok: true };
|
|
240
|
+
}
|
|
241
|
+
function detectOne(cli) {
|
|
242
|
+
// 0. User-supplied manual path wins over PATH/fallback. Without this,
|
|
243
|
+
// a fresh boot's PATH lookup would silently miss a CLI in a custom
|
|
244
|
+
// location even though the user had explicitly told us where to
|
|
245
|
+
// find it via the onboarding "I know where it is" affordance.
|
|
246
|
+
// Read from the sync cache populated at daemon boot — async settings
|
|
247
|
+
// fetch isn't available here without refactoring every detect caller.
|
|
248
|
+
const manual = cli_paths_js_1.cliPaths.getCached(cli);
|
|
249
|
+
if (manual && (0, fs_1.existsSync)(manual) && verifyRunnable(cli, manual).ok) {
|
|
250
|
+
return { id: cli, found: true, path: manual, source: 'manual' };
|
|
251
|
+
}
|
|
252
|
+
// 1. PATH lookup
|
|
253
|
+
const onPath = pathLookup(BINARY_NAME[cli]);
|
|
254
|
+
if (onPath && verifyRunnable(cli, onPath).ok) {
|
|
255
|
+
return { id: cli, found: true, path: onPath, source: 'path' };
|
|
256
|
+
}
|
|
257
|
+
// 2. Fallback known dirs
|
|
258
|
+
for (const candidate of fallbackPaths(cli)) {
|
|
259
|
+
if ((0, fs_1.existsSync)(candidate) && verifyRunnable(cli, candidate).ok) {
|
|
260
|
+
return { id: cli, found: true, path: candidate, source: 'fallback' };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { id: cli, found: false };
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Cache for `detectAllClis` — every detect spawns up to 5 child
|
|
267
|
+
* processes (one `--version` per CLI), so when a daemon route resolves
|
|
268
|
+
* a CLI path on every HTTP poll (e.g. /orchestrators/opencode/models
|
|
269
|
+
* during onboarding), we'd fork ~50 processes/second without a cache.
|
|
270
|
+
*
|
|
271
|
+
* 30s TTL is short enough that a `chorus install <cli>` run from a
|
|
272
|
+
* different shell shows up before the user finishes onboarding, but
|
|
273
|
+
* long enough that a polling UI doesn't keep retriggering scans.
|
|
274
|
+
* Tests can call detectAllClis with `force: true` to bypass.
|
|
275
|
+
*/
|
|
276
|
+
let detectCache = null;
|
|
277
|
+
const DETECT_CACHE_TTL_MS = 30_000;
|
|
278
|
+
function detectAllClis(force = false) {
|
|
279
|
+
const now = Date.now();
|
|
280
|
+
if (!force && detectCache && detectCache.expiresAt > now) {
|
|
281
|
+
return detectCache.results;
|
|
282
|
+
}
|
|
283
|
+
const results = Object.keys(BINARY_NAME).map(detectOne);
|
|
284
|
+
detectCache = { results, expiresAt: now + DETECT_CACHE_TTL_MS };
|
|
285
|
+
return results;
|
|
286
|
+
}
|
|
287
|
+
/** Clear the detection cache. Used by callers that mutated state we
|
|
288
|
+
* know will change the answer (e.g. user just supplied a manual path,
|
|
289
|
+
* or installed a new CLI via the cockpit). */
|
|
290
|
+
function clearDetectionCache() {
|
|
291
|
+
detectCache = null;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Validate a user-supplied path for a given CLI. Used by the
|
|
295
|
+
* "Set path manually" fallback when auto-detect misses.
|
|
296
|
+
*
|
|
297
|
+
* Layered checks (any failure returns found=false + a reason):
|
|
298
|
+
* 1. Basename matches the expected binary name. Catches the common
|
|
299
|
+
* paste-the-wrong-tool mistake — e.g. `/usr/bin/npm` for gemini-cli
|
|
300
|
+
* passes the bare-version regex but its basename is `npm`, not
|
|
301
|
+
* `gemini`. Both round-1 reviewers (claude + gemini) flagged this
|
|
302
|
+
* gap when smoke-testing the previous version.
|
|
303
|
+
* 2. File exists.
|
|
304
|
+
* 3. `--version` exits 0 with output that matches the CLI's signature.
|
|
305
|
+
*
|
|
306
|
+
* Auto-detect doesn't need step 1 — pathLookup/fallback already bound
|
|
307
|
+
* the search to the expected binary name.
|
|
308
|
+
*/
|
|
309
|
+
function validateCliPath(cli, customPath) {
|
|
310
|
+
const trimmed = customPath.trim();
|
|
311
|
+
if (!trimmed)
|
|
312
|
+
return { id: cli, found: false, reason: 'path is empty' };
|
|
313
|
+
// Basename gate — strip extension on Windows so claude.cmd / claude.exe
|
|
314
|
+
// both match `claude`.
|
|
315
|
+
const expectedBin = BINARY_NAME[cli];
|
|
316
|
+
const actualBase = isWindows
|
|
317
|
+
? path_1.default.basename(trimmed).replace(/\.(cmd|exe)$/i, '')
|
|
318
|
+
: path_1.default.basename(trimmed);
|
|
319
|
+
if (actualBase.toLowerCase() !== expectedBin.toLowerCase()) {
|
|
320
|
+
return {
|
|
321
|
+
id: cli,
|
|
322
|
+
found: false,
|
|
323
|
+
reason: `that file is named "${actualBase}", but the ${cli} binary should be "${expectedBin}". Pasted the wrong path?`,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// Symlink-aware validation:
|
|
327
|
+
// - Reject sockets / pipes / directories outright (lstat).
|
|
328
|
+
// - For symlinks, realpath the target and re-check it's a regular
|
|
329
|
+
// file. This keeps Homebrew / asdf / mise / npm-global / fnm /
|
|
330
|
+
// volta installs working (most ship the user-facing binary as a
|
|
331
|
+
// symlink) while neutralising the TOCTOU attack from Audit D3:
|
|
332
|
+
// we persist the CANONICAL path, so a later swap of the symlink
|
|
333
|
+
// can't redirect daemon spawns to a malicious binary.
|
|
334
|
+
// - existsSync alone (the pre-fix call) followed symlinks silently
|
|
335
|
+
// and stored the symlink path — that's the attack surface we're
|
|
336
|
+
// closing.
|
|
337
|
+
let canonical = trimmed;
|
|
338
|
+
let lstat;
|
|
339
|
+
try {
|
|
340
|
+
lstat = (0, fs_1.lstatSync)(trimmed);
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
return { id: cli, found: false, reason: `no file at ${trimmed}` };
|
|
344
|
+
}
|
|
345
|
+
if (lstat.isSymbolicLink()) {
|
|
346
|
+
try {
|
|
347
|
+
canonical = path_1.default.resolve(path_1.default.dirname(trimmed),
|
|
348
|
+
// realpath resolves the chain; spawning the canonical target
|
|
349
|
+
// means a later symlink-swap can't redirect us.
|
|
350
|
+
(0, fs_1.realpathSync)(trimmed));
|
|
351
|
+
const realStat = (0, fs_1.lstatSync)(canonical);
|
|
352
|
+
if (!realStat.isFile()) {
|
|
353
|
+
return {
|
|
354
|
+
id: cli,
|
|
355
|
+
found: false,
|
|
356
|
+
reason: `symlink target is not a regular file: ${canonical}`,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return {
|
|
362
|
+
id: cli,
|
|
363
|
+
found: false,
|
|
364
|
+
reason: `symlink could not be resolved: ${trimmed}`,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else if (!lstat.isFile()) {
|
|
369
|
+
return {
|
|
370
|
+
id: cli,
|
|
371
|
+
found: false,
|
|
372
|
+
reason: `path is not a regular file: ${trimmed}`,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
// Verify via the user-pasted path so verifyRunnable's internal
|
|
376
|
+
// basename check passes — "claude" symlinked to a versioned target
|
|
377
|
+
// like "2.1.126" is the canonical real-world install (npm/Homebrew
|
|
378
|
+
// both do this). Spawning the symlink path runs the same binary as
|
|
379
|
+
// spawning the resolved target since the kernel follows the link.
|
|
380
|
+
const v = verifyRunnable(cli, trimmed);
|
|
381
|
+
if (!v.ok)
|
|
382
|
+
return { id: cli, found: false, reason: v.reason };
|
|
383
|
+
// Persist the canonical (realpath-resolved) target. Daemon spawns
|
|
384
|
+
// will hit the resolved binary even if the symlink is later swapped
|
|
385
|
+
// by an attacker — closes the TOCTOU window from Audit D3.
|
|
386
|
+
return { id: cli, found: true, path: canonical, source: 'manual' };
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=cli-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-detect.js","sourceRoot":"","sources":["../../src/lib/cli-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-CLI health state, persisted in the settings table.
|
|
4
|
+
*
|
|
5
|
+
* Records the most recent failure mode the error-detector observed per
|
|
6
|
+
* lineage, plus a timestamp and (when available) a reset-at time so the UI
|
|
7
|
+
* can show "Codex resets at 10:05 PM".
|
|
8
|
+
*
|
|
9
|
+
* Recorded by: daemon's runner when it forwards cli_error events.
|
|
10
|
+
* Read by: home-page CLI status panel via GET /cli/health.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.recordHealth = recordHealth;
|
|
14
|
+
exports.getHealth = getHealth;
|
|
15
|
+
exports.getAllHealth = getAllHealth;
|
|
16
|
+
exports.clearStaleHealth = clearStaleHealth;
|
|
17
|
+
exports.kindToStatus = kindToStatus;
|
|
18
|
+
exports.classifyOpenRouterError = classifyOpenRouterError;
|
|
19
|
+
const db_1 = require("./db");
|
|
20
|
+
const KEY = (l) => `cli_health.${l}`;
|
|
21
|
+
const ALL_LINEAGES = [
|
|
22
|
+
'anthropic',
|
|
23
|
+
'openai',
|
|
24
|
+
'google',
|
|
25
|
+
'opencode',
|
|
26
|
+
'moonshot',
|
|
27
|
+
'openrouter',
|
|
28
|
+
];
|
|
29
|
+
async function recordHealth(input) {
|
|
30
|
+
const payload = {
|
|
31
|
+
lineage: input.lineage,
|
|
32
|
+
status: input.status,
|
|
33
|
+
message: input.message,
|
|
34
|
+
resetAt: input.resetAt,
|
|
35
|
+
updatedAt: Date.now(),
|
|
36
|
+
};
|
|
37
|
+
await db_1.settings.set(KEY(input.lineage), payload);
|
|
38
|
+
}
|
|
39
|
+
async function getHealth(lineage) {
|
|
40
|
+
const raw = await db_1.settings.get(KEY(lineage));
|
|
41
|
+
if (raw && typeof raw === 'object' && 'status' in raw) {
|
|
42
|
+
return raw;
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
lineage,
|
|
46
|
+
status: 'unknown',
|
|
47
|
+
updatedAt: 0,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async function getAllHealth() {
|
|
51
|
+
return Promise.all(ALL_LINEAGES.map(getHealth));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sweep cli-health entries and reset any whose `resetAt` has passed.
|
|
55
|
+
* Called periodically from the reaper so the home-page fleet card flips
|
|
56
|
+
* back to green automatically once a quota window expires — no refresh,
|
|
57
|
+
* no manual intervention. Bounded by ALL_LINEAGES so this is O(7) DB
|
|
58
|
+
* roundtrips per tick (six writes max even in the worst case).
|
|
59
|
+
*
|
|
60
|
+
* Returns the list of lineages whose state was cleared so the caller
|
|
61
|
+
* can log them.
|
|
62
|
+
*/
|
|
63
|
+
async function clearStaleHealth() {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
const cleared = [];
|
|
66
|
+
for (const lineage of ALL_LINEAGES) {
|
|
67
|
+
const h = await getHealth(lineage);
|
|
68
|
+
if (h.status !== 'healthy' &&
|
|
69
|
+
h.status !== 'unknown' &&
|
|
70
|
+
typeof h.resetAt === 'number' &&
|
|
71
|
+
h.resetAt > 0 &&
|
|
72
|
+
h.resetAt <= now) {
|
|
73
|
+
await recordHealth({ lineage, status: 'healthy' });
|
|
74
|
+
cleared.push(lineage);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return cleared;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Translate an error-detector CliErrorKind into a HealthStatus.
|
|
81
|
+
* Used by the runner when forwarding cli_error events.
|
|
82
|
+
*/
|
|
83
|
+
function kindToStatus(kind) {
|
|
84
|
+
switch (kind) {
|
|
85
|
+
case 'quota_exhausted':
|
|
86
|
+
return 'quota_exhausted';
|
|
87
|
+
case 'token_refresh_lost':
|
|
88
|
+
case 'mcp_handshake_failed':
|
|
89
|
+
return 'auth_invalid';
|
|
90
|
+
default:
|
|
91
|
+
return 'unknown';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Classify a headless-shim error kind (e.g. `openrouter_402`,
|
|
96
|
+
* `openrouter_401`, `openrouter_429`) into a health status + friendlier
|
|
97
|
+
* one-liner the cockpit can show on the fleet card and run-page error
|
|
98
|
+
* banner. Returns null when the kind isn't a known OpenRouter HTTP code,
|
|
99
|
+
* so callers can fall through to generic handling.
|
|
100
|
+
*
|
|
101
|
+
* Reference: https://openrouter.ai/docs/errors — 402 means "your account
|
|
102
|
+
* is out of credits", 401 a bad/revoked key, 429 a rate cap, 403 a model
|
|
103
|
+
* the key isn't allowed to call (paid tier / BYOK), 5xx an upstream
|
|
104
|
+
* outage. We deliberately collapse 401 + 403 to auth_invalid since the
|
|
105
|
+
* remediation is the same (fix the key).
|
|
106
|
+
*/
|
|
107
|
+
function classifyOpenRouterError(kind, message) {
|
|
108
|
+
const m = (message ?? '').trim();
|
|
109
|
+
if (kind === 'auth_missing') {
|
|
110
|
+
return {
|
|
111
|
+
status: 'auth_invalid',
|
|
112
|
+
message: 'No OpenRouter API key saved.',
|
|
113
|
+
cta: 'Add your key on the Connect page.',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (!kind.startsWith('openrouter_'))
|
|
117
|
+
return null;
|
|
118
|
+
const statusCode = Number(kind.slice('openrouter_'.length));
|
|
119
|
+
if (statusCode === 402) {
|
|
120
|
+
return {
|
|
121
|
+
status: 'quota_exhausted',
|
|
122
|
+
message: m || 'OpenRouter account is out of credits.',
|
|
123
|
+
cta: 'Top up at openrouter.ai/credits.',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
127
|
+
return {
|
|
128
|
+
status: 'auth_invalid',
|
|
129
|
+
message: m || 'OpenRouter rejected the API key.',
|
|
130
|
+
cta: 'Replace the key on the Connect page.',
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (statusCode === 429) {
|
|
134
|
+
return {
|
|
135
|
+
status: 'rate_limited',
|
|
136
|
+
message: m || 'OpenRouter rate-limited the request.',
|
|
137
|
+
cta: 'Slow down or pick a higher-tier model.',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (statusCode === 404) {
|
|
141
|
+
return {
|
|
142
|
+
status: 'unknown',
|
|
143
|
+
message: m || 'OpenRouter could not find the requested model.',
|
|
144
|
+
cta: 'Pick a different model on the Connect page.',
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (statusCode >= 500 && statusCode < 600) {
|
|
148
|
+
return {
|
|
149
|
+
status: 'rate_limited',
|
|
150
|
+
message: m || `OpenRouter upstream error (${statusCode}).`,
|
|
151
|
+
cta: 'Try again in a moment.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=cli-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-health.js","sourceRoot":"","sources":["../../src/lib/cli-health.ts"],"names":[],"mappings":"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"}
|