@mars-sea/dsh-commandcode-provider 0.11.3 → 0.11.5
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/CHANGELOG.md +14 -0
- package/lib/client.js +73 -23
- package/lib/client.js.map +1 -1
- package/lib/index.js +7 -5
- package/lib/index.js.map +1 -1
- package/package.json +39 -38
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["record","record","stringField","reject","createNetServer","createHttpServer"],"sources":["../src/capabilities.ts","../src/model-prices.ts","../src/cost-facts.ts","../src/cost-projection.ts","../src/accounts.ts","../src/image-request.ts","../src/image-tokens.ts","../src/adapter.ts","../src/command-locales.ts","../src/commands.ts","../src/wire-shared.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/usage-remote.ts","../src/login.ts","../src/web-search.ts","../src/tui-settings.ts","../src/transport-retry.ts","../src/index.ts"],"sourcesContent":["/**\n * Static capability snapshot for the Command Code provider: model →\n * reasoning-effort levels, vision/thinking flags, model → minimum plan tier,\n * subscription-plan labels, deals, and hourly (peak/off-peak) pricing.\n *\n * Everything in this module is synced from official sources (the command-code\n * CLI bundle's model table and the official plan/pricing/model docs — see the\n * dsh-commandcode-upstream skill for the exact extraction procedures), and\n * changes whenever an upstream CLI release reshuffles models/plans/prices.\n * Keeping the snapshot in its own module confines those frequent sync diffs\n * here: src/adapter.ts holds only the stable wire/runtime logic and imports\n * these tables + read helpers.\n *\n * Snapshot read helpers (planLabel, dealLabel, formatContext,\n * capabilityDescription, peakPricing*, compareByPlan, modelVisibleInPlan,\n * subscriptionPlanInfo, isFreeModel) live here too — they exist only to read\n * the tables, so a sync never has to touch src/adapter.ts.\n *\n * Ported from pi-commandcode-provider (MIT); originally part of src/adapter.ts\n * and split out so upstream syncs stay reviewable.\n */\n// ---------------------------------------------------------------------------\n// Static capability snapshot (from the official command-code@1.53.0 bundled\n// model catalog, dist/cli.mjs). The Provider API does not expose reasoning\n// metadata; models omitted here let Command Code choose their reasoning\n// depth, matching the official CLI.\n// ---------------------------------------------------------------------------\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n // Re-verified against the authoritative command-code@1.53.0 bundled model\n // table (dist/cli.mjs, the provider effort map): exactly these models carry\n // selectable efforts. Models marked 'reasoning:!0' without efforts\n // (e.g. Tencent Hy3, GLM-5/5.1/5.2-Fast)\n // think automatically and are absent here - the CLI omits\n // 'reasoning_effort' for them, so the picker must not offer a selector. Do\n // NOT add entries from the OAuth provider tables (anthropic/openai) - only\n // the Provider-API table is authoritative for this plugin's route.\n // `stealth/ox-alpha` (['low', 'high', 'max']) was removed in\n // command-code@1.34.0 when its preview ended; its successor,\n // `z-ai/glm-5.3-flash`, ships the same effort set.\n // `tencent/hy4-preview` gained ['low', 'medium', 'high'] in\n // command-code@1.38.0 (it previously thought automatically with no\n // selectable levels).\n // `moonshotai/Kimi-K3` gained ['low', 'high', 'max'] in command-code@1.39.3\n // (it previously thought automatically with no selectable levels).\n // `claude-fable-5-1` (Claude Fable 5.1, command-code@1.40.0) ships the same\n // five-level effort set as its predecessor `claude-fable-5` and is served\n // by the Provider API (the Provider/Max tier; see KNOWN_PLANS).\n // command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` and command-code@1.43.0\n // added `google/gemini-3.8-flash`; both carry effort sets matching their\n // existing family members. command-code@1.45.0 added selectable\n // ['low', 'medium', 'high', 'xhigh'] efforts for the Muse Spark family\n // (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor); they previously reasoned\n // automatically with no selectable levels. command-code@1.48.0 added the\n // `max` effort tier to Muse Spark 1.3 (previously ['low','medium','high',\n // 'xhigh']); 1.3 and 1.3-contributor now ship different effort sets.\n // command-code@1.49.0 added `gpt-6-astra` with the five-level effort set.\n // command-code@1.51.0 briefly added `deepseek/deepseek-v4.1-flash-beta`\n // (text+image, reasoning without selectable efforts, hidden behind a\n // 2026-09-10 expiry gate); command-code@1.51.2 removed it from the bundle\n // entirely, so no snapshot entry is needed.\n 'Qwen/Qwen3.8-Max': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-Max-0902': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-27B': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-Flash': ['low', 'medium', 'xhigh'],\n 'claude-fable-5-1': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-fable-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-7': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-8': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-4-6': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n // `deepseek/deepseek-v4-flash-fast` joined in command-code@1.39.0\n // (\"Add DeepSeek V4 Flash Fast\"); 1.39.1 dropped `medium` for it, and\n // the 1.39.2 table ships ['low', 'high', 'max'].\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0 added DeepSeek V4.1 Flash (\"Add new\n // deepseek/deepseek-v4.1-flash model\"); the bundle ships\n // ['low', 'high', 'max'] for it.\n 'deepseek/deepseek-v4.1-flash': ['low', 'high', 'max'],\n 'deepseek/deepseek-v4-flash': ['high', 'max'],\n 'deepseek/deepseek-v4-flash-vision-exp': ['high', 'max'],\n 'deepseek/deepseek-v4-pro': ['high', 'max'],\n 'google/gemini-3.1-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.6-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.7-flash': ['low', 'medium', 'high'],\n 'gpt-5.3-codex': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4-mini': ['low', 'medium', 'high'],\n 'gpt-5.5': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-sol': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-terra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // `moonshotai/Kimi-K3` gained selectable ['low', 'high', 'max'] efforts in\n // command-code@1.39.3 (\"Add low, high, and max reasoning effort support for\n // Kimi K3\"); it previously reasoned automatically with no levels.\n 'moonshotai/Kimi-K3': ['low', 'high', 'max'],\n // command-code@1.43.0 added Gemini 3.8 Flash with the same three-level\n // effort set as the rest of the Gemini Flash family.\n 'google/gemini-3.8-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n 'tencent/hy4-preview': ['low', 'medium', 'high'],\n 'xai/grok-4.5': ['low', 'medium', 'high'],\n 'xai/grok-4.6': ['low', 'medium', 'high', 'xhigh'],\n 'z-ai/glm-5.3-flash': ['low', 'high', 'max'],\n 'zai-org/GLM-5.2': ['high', 'max'],\n 'zai-org/GLM-5.3': ['low', 'high', 'max'],\n // Muse Spark family (command-code@1.45.0: \"Reasoning levels for Muse\n // Spark 1.3\") gained selectable ['low', 'medium', 'high', 'xhigh'] efforts\n // — they previously reasoned automatically with no levels.\n 'meta/muse-spark-1.1': ['low', 'medium', 'high', 'xhigh'],\n 'meta/muse-spark-1.2': ['low', 'medium', 'high', 'xhigh'],\n 'meta/muse-spark-1.2-contributor': ['low', 'medium', 'high', 'xhigh'],\n // command-code@1.48.0 added `max` to Muse Spark 1.3; 1.3-contributor keeps\n // the four-level set.\n 'meta/muse-spark-1.3': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'meta/muse-spark-1.3-contributor': ['low', 'medium', 'high', 'xhigh'],\n // command-code@1.49.0 added GPT-6 Astra with the full five-level effort set.\n 'gpt-6-astra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.51.3 gave MiniMax M3 selectable ['low', 'medium', 'high']\n // efforts (it previously reasoned automatically with no levels and lived in\n // KNOWN_THINKING_MODELS; the hidden `minimax/minimax-m3-free` sibling gained\n // the same set in the bundle). No CLI changelog entry exists for 1.51.1–1.51.3\n // yet — this was read from the 1.51.3 bundled model table.\n // command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free` with\n // automatic reasoning and no selectable efforts, so the effort map is\n // unchanged by that release.\n 'MiniMaxAI/MiniMax-M3': ['low', 'medium', 'high'],\n}\n\n/**\n * Models whose Capabilities include Vision, per the official Command Code\n * model registry (`https://commandcode.ai/docs/reference/cli/models`, generated\n * from the same registry as `cmd --list-models` / the `/model` picker).\n *\n * The Provider API does not expose modality metadata, so this snapshot is the\n * source of truth for image-input gating. Command Code's own CLI falls back to\n * a client-side VISION side-call for text-only models; this adapter does not\n * reproduce that interactive feature, so images sent to a model outside this\n * list are refused loudly (`UNSUPPORTED_CONTENT`) instead of being dropped or\n * sent to a model that cannot read them.\n *\n * Keep in sync with the official registry when new models ship (see the\n * dsh-commandcode-upstream skill).\n */\nexport const KNOWN_IMAGE_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.6-Plus',\n 'Qwen/Qwen3.7-Flash',\n 'Qwen/Qwen3.7-Plus',\n 'Qwen/Qwen3.8-27B',\n 'Qwen/Qwen3.8-Flash',\n 'Qwen/Qwen3.8-Max',\n // command-code@1.41.0 added Qwen 3.8 Max 0902; Vision per the official\n // registry (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'Qwen/Qwen3.8-Max-0902',\n 'claude-fable-5-1',\n 'claude-fable-5',\n 'claude-haiku-4-5-20251001',\n 'claude-opus-4-7',\n 'claude-opus-4-8',\n 'claude-opus-5',\n 'claude-sonnet-4-6',\n 'claude-sonnet-5',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0 added DeepSeek V4.1 Flash; Vision per the official\n // registry (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'deepseek/deepseek-v4.1-flash',\n 'google/gemini-3.1-flash-lite',\n 'google/gemini-3.5-flash',\n 'google/gemini-3.5-flash-lite',\n 'google/gemini-3.6-flash',\n 'google/gemini-3.7-flash',\n // command-code@1.43.0 added Gemini 3.8 Flash; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"].\n 'google/gemini-3.8-flash',\n 'gpt-5.3-codex',\n 'gpt-5.4',\n 'gpt-5.4-mini',\n 'gpt-5.5',\n 'gpt-5.6-luna',\n 'gpt-5.6-sol',\n 'gpt-5.6-terra',\n // command-code@1.49.0 added GPT-6 Astra; Vision per the official registry\n // and the CLI's inputModalities:[\"text\",\"image\"].\n 'gpt-6-astra',\n // command-code@1.44.0 added Muse Spark 1.3 and its Contributor sibling;\n // both are Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'meta/muse-spark-1.1',\n 'meta/muse-spark-1.2',\n 'meta/muse-spark-1.2-contributor',\n 'meta/muse-spark-1.3',\n 'meta/muse-spark-1.3-contributor',\n 'moonshotai/Kimi-K2.5',\n 'moonshotai/Kimi-K2.6',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'moonshotai/Kimi-K3',\n 'sakana/fugu-ultra',\n 'stepfun/Step-3.7-Flash',\n 'thinkingmachines/inkling',\n 'thinkingmachines/inkling-small',\n 'xai/grok-4.5',\n // command-code@1.47.0 marked Grok 4.6 vision-capable (it was text-only in\n // 1.46.0); re-verified present in the 1.53.0 bundle's\n // inputModalities:[\"text\",\"image\"] entries.\n 'xai/grok-4.6',\n 'xiaomi/mimo-v2.5',\n 'z-ai/glm-5.3-flash',\n])\n\n/**\n * Models the official CLI's model table (command-code@1.53.0) marks\n * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they\n * think automatically, with Command Code driving the depth. This is the\n * authoritative \"thinks, effort not adjustable\" set: `KNOWN_EFFORTS` (which\n * mirrors the CLI's effort map exactly) stays the sole source for selectable\n * effort levels, and this snapshot is not surfaced in the picker's compact\n * description — it exists for programmatic consumers.\n *\n * Source: the command-code@1.53.0 bundled model table (dist/cli.mjs),\n * cross-checked with https://commandcode.ai/docs/reference/cli/models.\n * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it\n * selectable `['low', 'high', 'max']` efforts; the preview then ended in\n * 1.34.0, removing the model from the catalog entirely. `tencent/hy4-preview`\n * joined this set in command-code@1.37.0 — reasoning:!0, no efforts, 1M\n * context, routed through OpenRouter — then gained selectable\n * `['low', 'medium', 'high']` efforts in command-code@1.38.0 and moved to\n * `KNOWN_EFFORTS`. `moonshotai/Kimi-K3` followed the same path in\n * command-code@1.39.3 — it gained `['low', 'high', 'max']` efforts and moved\n * to `KNOWN_EFFORTS`. command-code@1.42.0 added `meituan/LongCat-2.0:free`\n * (reasoning:!0, no efforts). command-code@1.45.0 gave the Muse Spark family\n * (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor) selectable\n * `['low', 'medium', 'high', 'xhigh']` efforts — they moved to `KNOWN_EFFORTS`.\n * command-code@1.51.3 gave `MiniMaxAI/MiniMax-M3` selectable\n * `['low', 'medium', 'high']` efforts — it moved to `KNOWN_EFFORTS` too.\n * command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free`\n * (reasoning:!0, no efforts).)\n * command-code@1.53.0 added `deepseek/deepseek-v4.1-flash` with selectable\n * ['low', 'high', 'max'] efforts, so it lives in `KNOWN_EFFORTS`, not here.)\n * Keep in sync via the dsh-commandcode-upstream skill.\n */\nexport const KNOWN_THINKING_MODELS: ReadonlySet<string> = new Set([\n 'Qwen/Qwen3.6-Max-Preview',\n 'Qwen/Qwen3.6-Plus',\n 'Qwen/Qwen3.7-Flash',\n 'Qwen/Qwen3.7-Max',\n 'Qwen/Qwen3.7-Plus',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'stepfun/Step-3.5-Flash',\n 'stepfun/Step-3.7-Flash',\n 'tencent/hy3-paid',\n 'nvidia/nemotron-3-ultra-550b-a55b',\n 'thinkingmachines/inkling',\n 'thinkingmachines/inkling-small',\n 'poolside/laguna-s-2.1-free',\n // LongCat 2.0 (command-code@1.42.0, Meituan's trillion-parameter coding\n // model, 1M context) is free and text-only, with automatic reasoning.\n 'meituan/LongCat-2.0:free',\n // Ling 3.0 Flash Sante (command-code@1.52.0, 262K context, text-only) is\n // free and reasons automatically with no selectable efforts.\n 'inclusionai/ling-3.0-flash-sante:free',\n])\n\n/**\n * Catalog models the Provider API serves ONLY through `/provider/v1/messages`\n * (Anthropic Messages shape). Every other model in the catalog answers on\n * `/provider/v1/chat/completions`; these reject it outright with HTTP 400\n * `Model \"<id>\" must be called via /provider/v1/messages (Anthropic Messages\n * shape)`.\n *\n * Measured 2026-09-16 against the live catalog (command-code@1.54.0): all 69\n * models were posted to `/provider/v1/chat/completions`; exactly these eight\n * — the whole Claude family — refused, and every one of them is routed\n * normally by `/alpha/generate` (a lower-plan key gets the ordinary\n * `MODEL_NOT_IN_PLAN` 403 there, never a routing error). So the CLI transport\n * is a complete fallback and the adapter does not need a Messages transport.\n *\n * Note what this list is NOT: it is not a plan gate. `claude-sonnet-5` is\n * Pro-tier and `claude-opus-4-8` Provider-tier, so the accounts entitled to\n * these models are exactly the non-Go ones, which `resolveProtocol()` sends to\n * the Provider API by default — picking any Claude model there failed every\n * request before this snapshot existed.\n *\n * Keep in sync when models ship (see the dsh-commandcode-upstream skill).\n * `requiresMessagesEndpoint()` additionally treats any `claude-*` id as\n * Messages-only, so a Claude model added upstream is routed correctly by an\n * un-updated plugin instead of hard-failing with the 400 above; the worst case\n * of that rule going stale the other way (upstream teaching\n * `/provider/v1/chat/completions` to serve Claude) is one model riding the CLI\n * transport it already works on.\n */\nexport const MESSAGES_ONLY_MODELS: ReadonlySet<string> = new Set([\n 'claude-sonnet-5',\n 'claude-sonnet-4-6',\n 'claude-fable-5-1',\n 'claude-fable-5',\n 'claude-opus-5',\n 'claude-opus-4-8',\n 'claude-opus-4-7',\n 'claude-haiku-4-5-20251001',\n])\n\n/** True when the Provider API will only serve `modelId` via `/provider/v1/messages`. */\nexport function requiresMessagesEndpoint(modelId: string): boolean {\n return MESSAGES_ONLY_MODELS.has(modelId) || modelId.startsWith('claude-')\n}\n\n/**\n * The minimum subscription plan a model is included in, per the official plan\n * pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`, `/docs/plans/max`\n * and `/docs/resources/pricing-limits`). Each plan's model list is a superset of\n * the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max. Models absent from every\n * plan list (Claude Opus/Fable, Fugu Ultra) are Provider-tier.\n * `claude-fable-5-1` (Claude Fable 5.1, added in command-code@1.40.0) is\n * Provider/Max-tier exactly like `claude-fable-5` — its availability matrix on\n * the official plan/pricing pages grants individual-provider/max/ultra and\n * teams-pro only, and the CLI's plan-access map blocks it on Go/GOAT/Pro.\n * command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` (Go) and 1.42.0 added\n * `meituan/LongCat-2.0:free` (Go, free promo); command-code@1.43.0 added\n * `google/gemini-3.8-flash` (GOAT) and 1.44.0 added `meta/muse-spark-1.3`\n * (GOAT) plus its Contributor sibling (Go); command-code@1.52.0 added the\n * free `inclusionai/ling-3.0-flash-sante:free` (Go); command-code@1.53.0\n * added `deepseek/deepseek-v4.1-flash` (Go).\n *\n * The Provider API exposes no plan metadata, so this snapshot is the source of\n * truth for the picker's plan annotation — it answers \"which plan do I need to\n * actually use this model?\" at a glance. Plan labels use the official tier\n * names (`Go`, `GOAT`, `Pro`, `Provider`), with `Max` implying Provider.\n *\n * Keep in sync with the official plan pages when they change (see the\n * dsh-commandcode-upstream skill).\n */\nexport const KNOWN_PLANS: Readonly<Record<string, string>> = {\n // --- Go (44) ---\n 'MiniMaxAI/MiniMax-M2.5': 'go',\n 'MiniMaxAI/MiniMax-M2.7': 'go',\n 'MiniMaxAI/MiniMax-M3': 'go',\n 'Qwen/Qwen3.6-Max-Preview': 'go',\n 'Qwen/Qwen3.6-Plus': 'go',\n 'Qwen/Qwen3.7-Flash': 'go',\n 'Qwen/Qwen3.7-Max': 'go',\n 'Qwen/Qwen3.7-Plus': 'go',\n 'Qwen/Qwen3.8-27B': 'go',\n 'Qwen/Qwen3.8-Flash': 'go',\n 'Qwen/Qwen3.8-Max': 'go',\n // command-code@1.41.0 added Qwen 3.8 Max 0902; it sits on the Go plan page.\n 'Qwen/Qwen3.8-Max-0902': 'go',\n // command-code@1.39.0 added DeepSeek V4 Flash Fast; it is a Go-tier model\n // alongside the rest of the DeepSeek V4 family.\n 'deepseek/deepseek-v4-flash-fast': 'go',\n // command-code@1.53.0 added DeepSeek V4.1 Flash (\"Add new\n // deepseek/deepseek-v4.1-flash model\"); the pricing page's embedded\n // availability grants it every plan including Go, and the Go/GOAT/Pro/Max\n // plan pages all list it.\n 'deepseek/deepseek-v4.1-flash': 'go',\n 'deepseek/deepseek-v4-flash': 'go',\n 'deepseek/deepseek-v4-flash-vision-exp': 'go',\n 'deepseek/deepseek-v4-pro': 'go',\n 'gpt-5.6-luna': 'go',\n // command-code@1.42.0 added Meituan's LongCat 2.0 as a free Go-tier model\n // (\"LongCat 2.0 free model\" — 100% off while it lasts, every plan).\n 'meituan/LongCat-2.0:free': 'go',\n // command-code@1.52.0 added Ling 3.0 Flash Sante as a free Go-tier model\n // (\"free, up to 100 requests a day\", every plan) — the successor to the\n // retired `inclusionai/ling-3.0-flash-free` promo.\n 'inclusionai/ling-3.0-flash-sante:free': 'go',\n // command-code@1.44.0 added Muse Spark 1.3 Contributor on every plan\n // including Go, like its 1.2 Contributor sibling.\n 'meta/muse-spark-1.2-contributor': 'go',\n 'meta/muse-spark-1.3-contributor': 'go',\n\n 'moonshotai/Kimi-K2.5': 'go',\n 'moonshotai/Kimi-K2.6': 'go',\n 'moonshotai/Kimi-K2.7-Code': 'go',\n 'moonshotai/Kimi-K2.7-Code-Highspeed': 'go',\n 'moonshotai/Kimi-K3': 'go',\n 'nvidia/nemotron-3-ultra-550b-a55b': 'go',\n 'poolside/laguna-s-2.1-free': 'go',\n 'stepfun/Step-3.5-Flash': 'go',\n 'stepfun/Step-3.7-Flash': 'go',\n 'tencent/hy3-paid': 'go',\n 'tencent/hy4-preview': 'go',\n 'thinkingmachines/inkling': 'go',\n 'thinkingmachines/inkling-small': 'go',\n 'xai/grok-4.5': 'go',\n 'xiaomi/mimo-v2.5': 'go',\n 'xiaomi/mimo-v2.5-pro': 'go',\n 'z-ai/glm-5.3-flash': 'go',\n 'zai-org/GLM-5': 'go',\n 'zai-org/GLM-5.1': 'go',\n 'zai-org/GLM-5.2': 'go',\n 'zai-org/GLM-5.2-Fast': 'go',\n 'zai-org/GLM-5.3': 'go',\n // --- GOAT (6 more) ---\n 'google/gemini-3.7-flash': 'goat',\n // command-code@1.43.0 added Gemini 3.8 Flash; the pricing page marks it\n // \"Available on GOAT and above\", like the rest of the Gemini Flash family.\n 'google/gemini-3.8-flash': 'goat',\n 'gpt-5.6-sol': 'goat',\n 'meta/muse-spark-1.2': 'goat',\n // command-code@1.44.0 added Muse Spark 1.3; the pricing page marks it\n // \"Available on GOAT and above\", like the 1.2/1.1 models.\n 'meta/muse-spark-1.3': 'goat',\n 'xai/grok-4.6': 'goat',\n // --- Pro (13 more) ---\n 'claude-haiku-4-5-20251001': 'pro',\n 'claude-sonnet-4-6': 'pro',\n 'claude-sonnet-5': 'pro',\n 'google/gemini-3.1-flash-lite': 'pro',\n 'google/gemini-3.5-flash': 'pro',\n 'google/gemini-3.5-flash-lite': 'pro',\n 'google/gemini-3.6-flash': 'pro',\n 'gpt-5.3-codex': 'pro',\n 'gpt-5.4': 'pro',\n 'gpt-5.4-mini': 'pro',\n 'gpt-5.5': 'pro',\n 'gpt-5.6-terra': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider / Max (7) ---\n 'claude-fable-5-1': 'provider',\n 'claude-fable-5': 'provider',\n 'claude-opus-4-7': 'provider',\n 'claude-opus-4-8': 'provider',\n 'claude-opus-5': 'provider',\n // command-code@1.49.0 added GPT-6 Astra; per the pricing page it sits on\n // Max (Provider/Max tier).\n 'gpt-6-astra': 'provider',\n 'sakana/fugu-ultra': 'provider',\n}\n\n/** Official display labels for each plan tier. */\nexport const PLAN_LABELS: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/**\n * Plan-tier sort weights, low to high. Models outside the snapshot (unknown\n * plans) sort after every known tier, keeping known models predictable.\n */\nexport const PLAN_ORDER: Readonly<Record<string, number>> = {\n go: 0,\n goat: 1,\n pro: 2,\n provider: 3,\n max: 4,\n}\n\n/**\n * Whether a model is free (requests cost no credits), per the pricing page's\n * deals (`KNOWN_DEALS` `free: true`). Free models lead the picker regardless\n * of tier — they are usable by every account, so they are the best default\n * candidates.\n */\nexport function isFreeModel(modelId: string): boolean {\n return KNOWN_DEALS[modelId]?.free === true\n}\n\n/**\n * Comparator for the model picker: free models first (zero credit cost, usable\n * by every account), then by plan tier (lowest first), then by model name,\n * then by id as a tiebreak. Models with no known plan sort last.\n */\nexport function compareByPlan(\n a: { id: string; name: string },\n b: { id: string; name: string },\n): number {\n const freeDelta = Number(isFreeModel(b.id)) - Number(isFreeModel(a.id))\n if (freeDelta !== 0) return freeDelta\n const pa = PLAN_ORDER[KNOWN_PLANS[a.id] ?? ''] ?? Number.MAX_SAFE_INTEGER\n const pb = PLAN_ORDER[KNOWN_PLANS[b.id] ?? ''] ?? Number.MAX_SAFE_INTEGER\n if (pa !== pb) return pa - pb\n const nameDiff = a.name.localeCompare(b.name)\n if (nameDiff !== 0) return nameDiff\n return a.id.localeCompare(b.id)\n}\n\n/**\n * Subscription plan table, synced from the official CLI bundle's plan maps\n * (located by the `\"individual-go\"` key in command-code@1.53.0 `dist/cli.mjs`,\n * re-verified unchanged through 1.53.0): subscription `planId`\n * prefix → display name and the plan's monthly credit total. This is the\n * account's own subscription (from `/alpha/billing/subscriptions`) — distinct\n * from {@link KNOWN_PLANS}, which maps catalog models to their minimum tier.\n *\n * `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on\n * the {@link PLAN_ORDER} scale, used by the picker's plan filter\n * ({@link modelVisibleInPlan}) to hide models above the account's tier.\n */\nexport const KNOWN_SUBSCRIPTION_PLANS: Readonly<Record<string, { name: string; monthlyCredits: number; tierWeight: number }>> = {\n 'individual-go': { name: 'Go', monthlyCredits: 10, tierWeight: 0 },\n 'individual-goat': { name: 'GOAT', monthlyCredits: 70, tierWeight: 1 },\n 'individual-pro': { name: 'Pro', monthlyCredits: 30, tierWeight: 2 },\n 'individual-pro-v1': { name: 'Pro', monthlyCredits: 80, tierWeight: 2 },\n 'individual-provider': { name: 'Provider', monthlyCredits: 15, tierWeight: 3 },\n 'individual-max': { name: 'Max', monthlyCredits: 150, tierWeight: 4 },\n 'individual-ultra': { name: 'Ultra', monthlyCredits: 300, tierWeight: 4 },\n 'teams-pro': { name: 'Teams Pro', monthlyCredits: 40, tierWeight: 2 },\n}\n\n/** Plan-id prefixes, longest first — the CLI's prefix-match order. */\nconst SUBSCRIPTION_PLAN_PREFIXES = Object.keys(KNOWN_SUBSCRIPTION_PLANS).sort((a, b) => b.length - a.length)\n\n/**\n * Resolve a subscription `planId` (e.g. `individual-pro-v1`) to its display\n * name and monthly credit total, mirroring the CLI's `getPlanInfo`:\n * normalize (lowercase, `_` → `-`), then longest-prefix match so\n * `individual-pro-v1` wins over `individual-pro`. Unknown ids return\n * `undefined`.\n */\nexport function subscriptionPlanInfo(planId: string): { name: string; monthlyCredits: number; tierWeight: number } | undefined {\n const normalized = planId.toLowerCase().replace(/_/g, '-')\n const prefix = SUBSCRIPTION_PLAN_PREFIXES.find((candidate) => normalized.startsWith(candidate))\n return prefix === undefined ? undefined : KNOWN_SUBSCRIPTION_PLANS[prefix]\n}\n\n/**\n * The billing facts the picker's plan filter needs, fetched by mirroring the\n * CLI's `createBilling` flow (whoami → orgId, then `/alpha/billing/subscriptions`\n * for the plan id and `/alpha/billing/credits` for the on-demand balances).\n */\nexport interface CommandCodeBillingAccess {\n /** Account plan tier weight on the {@link PLAN_ORDER} scale; undefined when the plan is unknown. */\n tierWeight: number | undefined\n /**\n * Purchased + free on-demand credit balance. The official access model\n * (`evaluateModelAccess` in the CLI) allows every model when the account\n * holds any on-demand credits — the plan gate only applies at zero balance.\n */\n onDemandCredits: number\n}\n\n/**\n * Whether the picker lists `modelId` for an account with the given billing\n * access. Fails open at every uncertainty: no billing data, an unknown plan,\n * a non-finite weight (corrupt billing fact), or a model outside\n * {@link KNOWN_PLANS} all keep the model visible — the server remains the\n * final gate (`403 MODEL_NOT_IN_PLAN`).\n */\nexport function modelVisibleInPlan(modelId: string, access: CommandCodeBillingAccess | undefined): boolean {\n if (access === undefined) return true\n if (access.onDemandCredits > 0) return true\n if (access.tierWeight === undefined || !Number.isFinite(access.tierWeight)) return true\n const tier = KNOWN_PLANS[modelId]\n if (tier === undefined) return true\n const weight = PLAN_ORDER[tier]\n if (weight === undefined) return true\n return weight <= access.tierWeight\n}\n\n/**\n * Active pricing deals per the official pricing page\n * (`/docs/resources/pricing-limits#deals`). Each entry records the model's\n * promotional label and — critically — when it expires, so the picker never\n * shows a stale discount after the plugin's snapshot has gone out of date.\n *\n * - `expiresAt` is an ISO timestamp. When it is in the past (checked at\n * render time against `Date.now()`), the deal label is hidden until the\n * snapshot is refreshed from the official page. `undefined` means\n * \"no expiry\" (permanent).\n * - `free` marks models whose requests cost no credits (Laguna S 2.1), shown\n * as a `FREE` badge; it degrades to a plain discount once the deal lapses.\n *\n * Keep in sync with the official pricing page when deals change (see the\n * dsh-commandcode-upstream skill).\n */\nexport interface KnownDeal {\n /** Promotional label, e.g. \"50% off\" or \"2× usage\". */\n label: string\n /** Deal end date (ISO). `undefined` = permanent / no expiry. */\n expiresAt?: string\n /** Model is free (requests cost no credits). */\n free?: boolean\n}\n\nexport const KNOWN_DEALS: Readonly<Record<string, KnownDeal>> = {\n // Gemini 3.7 Flash's 50% off deal was retired from the official pricing\n // page's #deals section (command-code@1.38.2 sync); the model now shows at\n // full price.\n 'MiniMaxAI/MiniMax-M3': { label: '50% off' },\n 'xiaomi/mimo-v2.5-pro': { label: '99% off' },\n 'xiaomi/mimo-v2.5': { label: '98% off' },\n // The MiniMax M3 / M2.7 FREE promo variants were retired in\n // command-code@1.39.2 (\"Retire MiniMax free models\"): the official CLI hides\n // them and the pricing page no longer lists them as free, so the free\n // entries that shipped through 1.38.2 (with a 2026-09-05 expiry) are removed\n // here rather than left to lapse on schedule. The paid MiniMax M3 / M2.7\n // rows keep their own rates.\n 'poolside/laguna-s-2.1-free': { label: 'FREE', free: true },\n // Meituan's LongCat 2.0 (command-code@1.42.0, \"LongCat 2.0 free model\") is\n // 100% off while it lasts — a permanent-style deal (no fixed end date; the\n // pricing page's DEAL block says \"Term: while it lasts\"). Free requests cost\n // no credits on every plan, like Laguna S 2.1.\n 'meituan/LongCat-2.0:free': { label: 'FREE', free: true },\n // Ling 3.0 Flash Sante (command-code@1.52.0) is free \"up to 100 requests a\n // day\" while the promo lasts — a permanent-style deal (no fixed end date,\n // like LongCat 2.0). Free requests cost no credits on every plan.\n 'inclusionai/ling-3.0-flash-sante:free': { label: 'FREE', free: true },\n}\n\n/**\n * Models with time-of-day (peak/off-peak) pricing, per the official pricing\n * page (`/docs/resources/pricing-limits`). Since 2026-08-16 16:00 UTC, DeepSeek\n * charges by the hour: peak hours are 01:00–04:00 and 06:00–10:00 UTC (7h per\n * weekday, full price) **Monday to Friday only**; the other 17 hours of a\n * weekday and every hour of Saturday/Sunday (UTC) are off-peak at half price.\n * The V4 Flash Vision (exp) variant (command-code@1.32.0) shares the V4 Flash\n * rates exactly — $0.15/$0.60 off-peak and $0.30/$1.20 peak, per the page's own\n * `timeOfDay` block, not merely 2× its own off-peak figures: a rate that is\n * internally consistent can still be the wrong row, which is why the vendored\n * price table (`./model-prices.ts`) is synced from the page and not hand-kept.\n * The picker shows the\n * *current* state as a compact\n * label (`Peak`/`Half`) matching the English noun style of the other markers\n * (`Image`, `FREE`), so a developer can tell at a glance whether calling the\n * model right now is cheap or expensive.\n *\n * Authoritative extraction: the pricing page embeds a model JSON array whose\n * hourly-priced entries carry a `timeOfDay` block\n * (`{ windows: \"01–04 & 06–10 UTC, Mon–Fri\", peakHoursPerDay: 7,\n * offPeakHoursPerDay: 17, peak: {...}, offPeak: {...} }`). Exactly four models\n * carry it: V4 Pro, V4 Flash, V4 Flash Vision (exp), and V4.1 Flash (added in\n * command-code@1.53.0 at $0.15/$0.60 off-peak, $0.30/$1.20 peak — the same\n * schedule as the other three).\n *\n * Extraction caution: the rendered HTML rows are a trap. Each annotation div\n * sits inside its OWN row's container, immediately before the NEXT row starts,\n * so flattening the page to text makes every annotation look like it belongs\n * to the model printed after it — that is how `deepseek/deepseek-v4-flash-fast`\n * was wrongly added here (its row is flat-priced at $0.28/$0.56/$0.07 and has\n * no `timeOfDay` block). Trust the embedded JSON's `timeOfDay` membership and\n * the 2× price relation, never the flat-text neighbor.\n *\n * Keep in sync with the official pricing page when the model set, the peak\n * windows, or the weekday rule change (see the dsh-commandcode-upstream skill).\n */\nexport const KNOWN_PEAK_PRICING: ReadonlySet<string> = new Set([\n 'deepseek/deepseek-v4-pro',\n 'deepseek/deepseek-v4-flash',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0 added DeepSeek V4.1 Flash with the same `timeOfDay`\n // block as the other DeepSeek models (off-peak $0.15/$0.60, peak\n // $0.30/$1.20, 01–04 & 06–10 UTC Mon–Fri).\n 'deepseek/deepseek-v4.1-flash',\n])\n\n/**\n * Peak hours (UTC, hour-of-day range end-exclusive): 01–03 and 06–09.\n * Weekday-only — see `peakPricingState()`; weekends are fully off-peak.\n *\n * Exported because the vendored price table (`./model-prices.ts`) ships these\n * windows to the browser with the table itself: the composer prices a session\n * against the very schedule this snapshot knows rather than restating it, so\n * there is one place to update when the windows move.\n */\nexport const PEAK_HOUR_RANGES: ReadonlyArray<readonly [number, number]> = [\n [1, 4],\n [6, 10],\n]\n\n/**\n * Whether `now` (defaults to `Date.now()`) falls inside a peak-pricing window,\n * ignoring which model is asking. Peak rates apply Monday–Friday (UTC) only,\n * so a weekend timestamp is off-peak even inside {@link PEAK_HOUR_RANGES}.\n *\n * Model-independent on purpose: `peakPricingState()` adds the membership test\n * on top for the picker's label, while the price table selects peak rates from\n * a row's own `peak` block — so a model whose catalog id spelling differs from\n * the one in {@link KNOWN_PEAK_PRICING} still gets the right half of the day.\n */\nexport function isPeakPricingHour(now: number = Date.now()): boolean {\n const at = new Date(now)\n const day = at.getUTCDay()\n if (day === 0 || day === 6) return false\n const hour = at.getUTCHours()\n return PEAK_HOUR_RANGES.some(([start, end]) => hour >= start && hour < end)\n}\n\n/**\n * Whether `now` (defaults to `Date.now()`) falls in a peak-pricing window for\n * time-of-day-priced models. Peak rates apply Monday–Friday (UTC) only: the\n * official rule charges Saturday and Sunday completely off-peak for all 24\n * hours, so a weekend timestamp is off-peak even inside `PEAK_HOUR_RANGES`.\n * `undefined` for models outside the snapshot.\n */\nexport function peakPricingState(\n modelId: string,\n now: number = Date.now(),\n): 'peak' | 'off-peak' | undefined {\n if (!KNOWN_PEAK_PRICING.has(modelId)) return undefined\n return isPeakPricingHour(now) ? 'peak' : 'off-peak'\n}\n\n/**\n * Compact label for the current peak/off-peak state: `Peak` (full price) or\n * `Half` (off-peak, half price). These English nouns match the picker's other\n * markers (`Go`, `Image`, `FREE`), and since they appear only on time-of-day\n * priced models they double as a \"priced by the hour\" signal. Returns undefined\n * for models without time-of-day pricing.\n */\nexport function peakPricingLabel(\n modelId: string,\n now: number = Date.now(),\n): string | undefined {\n const state = peakPricingState(modelId, now)\n if (state === undefined) return undefined\n return state === 'peak' ? 'Peak' : 'Half'\n}\n\n// ---------------------------------------------------------------------------\n// Snapshot read helpers (kept with the tables: a model/plan/deal sync must\n// never touch src/adapter.ts)\n// ---------------------------------------------------------------------------\n/**\n * Official display label for a model's minimum plan, or undefined for models\n * outside the snapshot (e.g. future catalog additions).\n */\nexport function planLabel(modelId: string): string | undefined {\n const plan = KNOWN_PLANS[modelId]\n return plan === undefined ? undefined : PLAN_LABELS[plan]\n}\n\n/**\n * The active deal label for a model, or undefined when the model has no deal\n * or the deal has expired. Expiry is judged against `now` (defaults to\n * `Date.now()`), so a snapshot that has gone stale stops showing its discount\n * the moment the official end date passes — the user never believes a lapsed\n * deal is still live. Permanent deals (no `expiresAt`) never lapse.\n */\nexport function dealLabel(modelId: string, now: number = Date.now()): string | undefined {\n const deal = KNOWN_DEALS[modelId]\n if (deal === undefined) return undefined\n if (deal.expiresAt !== undefined && now >= Date.parse(deal.expiresAt)) return undefined\n return deal.label\n}\n\n/**\n * Compact human-readable context window, e.g. `1_000_000 -> \"1M\"`,\n * `256_000 -> \"256K\"`, `262_144 -> \"262K\"` (floor to the nearest K).\n * Returns undefined for unknown/absent sizes; values under 1K render raw.\n */\nexport function formatContext(contextWindow: number | undefined): string | undefined {\n if (contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) {\n return undefined\n }\n if (contextWindow >= 1_000_000) {\n const m = contextWindow / 1_000_000\n // Round to one decimal only when it adds information: 1_048_576 -> \"1M\",\n // 1_050_000 -> \"1.1M\".\n const rounded = Math.round(m * 10) / 10\n return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}M`\n }\n if (contextWindow < 1_000) return String(Math.floor(contextWindow))\n return `${Math.floor(contextWindow / 1_000)}K`\n}\n\n/**\n * Compact one-line summary for the model picker: plan tier, then any active\n * deal (discount or FREE), then the current peak/off-peak state (`Peak`/`Half`)\n * for time-of-day-priced models, then `Image` for Vision-capable models, then\n * the context window. Text-only models simply omit the Image marker — \"Text\n * only\" adds nothing the picker needs to show.\n */\nexport function capabilityDescription(\n modelId: string,\n contextWindow?: number,\n now: number = Date.now(),\n): string {\n const parts: string[] = []\n const plan = planLabel(modelId)\n if (plan !== undefined) parts.push(plan)\n const deal = dealLabel(modelId, now)\n if (deal !== undefined) parts.push(deal)\n const peak = peakPricingLabel(modelId, now)\n if (peak !== undefined) parts.push(peak)\n if (KNOWN_IMAGE_MODELS.has(modelId)) parts.push('Image')\n const ctx = formatContext(contextWindow)\n if (ctx !== undefined) parts.push(ctx)\n return parts.join(' · ')\n}\n","/**\n * Vendored Command Code model prices: the per-token rates the official\n * pricing page publishes, which is what lets the composer price a session in\n * dollars.\n *\n * Source: the model array embedded in\n * https://commandcode.ai/docs/resources/pricing-limits, read out of its\n * Next.js flight payload. That payload is the only place the `timeOfDay` and\n * `contextTiers` blocks exist, so it is what the generator parses — but it is\n * NOT trusted on its own: the generator also reads the page's rendered table\n * and reports any rate where the two disagree. A figure can be internally\n * consistent and still be the wrong row (this table once carried\n * `0.22 → 0.44` for a model the page prices `0.15 → 0.30` — exactly the 2× the\n * peak/off-peak rule promises), so the cross-check exists to catch that class\n * of error rather than to restate the invariant. Every figure is USD per\n * 1,000,000 tokens, which the page confirms itself: its Go-plan estimate for\n * DeepSeek V4 Flash (800 in / 200 out on a $10 budget) resolves to the ~42K\n * requests the page states, and ~26K once its typical 50K cache reads are\n * priced at the cacheRead rate.\n *\n * Three buckets are always published (inputCost, outputCost, cacheReadCost);\n * cacheWriteCost is published for a minority of models. A model without the\n * key has UNPRICED cache-write tokens: never invent a multiplier for them, and\n * never fold them into the input rate. A published `0` is a different fact and\n * is kept as a real zero — see the note on the GPT rows below.\n *\n * Time-of-day models store a `peak` triplet only. The page repeats the flat\n * rates inside its own offPeak block, so the top-level rates ARE the off-peak\n * rates and only the peak override is worth keeping — the generator asserts\n * that equality and refuses to emit otherwise. Whether \"now\" counts as peak is\n * decided by `isPeakPricingHour()` in ./capabilities.ts, on the same\n * Monday-Friday UTC schedule the model picker labels.\n *\n * Context-tiered models carry every band, with inclusive prompt-token bounds\n * and an unbounded final band. The durable cost projection selects each\n * request's band from its input/cache buckets, never from session totals.\n *\n * Do not hand-edit the table below: run `node scripts/sync-model-prices.mjs`,\n * which re-reads the page, asserts the structure and the off-peak equality,\n * prints cross-check warnings for a human, and rewrites\n * only the rows. `--check` reports drift without writing (exit 1 on drift,\n * exit 2 when the page could not be read, so a network failure never reads as\n * \"up to date\"). Everything else in this file — this doc, the types, the slug\n * rules, the table builder — is written by hand and survives that rewrite.\n *\n * @module dsh-commandcode-provider/model-prices\n */\n\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\nimport { KNOWN_PLANS, PEAK_HOUR_RANGES, isFreeModel } from './capabilities.ts'\n\n/**\n * One pricing-page row. `rates` is `[input, output, cacheRead, cacheWrite?]`\n * and `peak` is the `[input, output, cacheRead]` triplet charged inside the\n * peak windows. All figures are USD per 1,000,000 tokens.\n */\ninterface ModelPriceRow {\n readonly id: string\n readonly rates: readonly number[]\n readonly peak?: readonly number[]\n readonly contextTiers?: readonly { maxContext?: number; rates: readonly number[] }[]\n}\n\n/**\n * Every price row the page publishes, ordered by its own slug.\n *\n * Note on the GPT rows: `gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini` and\n * `gpt-5.5` carry a LITERAL `cacheWriteCost: 0` — a different fact from a\n * missing key, because `ratesOf()` keeps it and the readout then charges\n * cache writes at zero instead of reporting them unpriced. That is what the\n * page's JSON says; its rendered column shows `—` for exactly these four while\n * rendering a genuine zero as `$0.00` elsewhere, so the page contradicts\n * itself. The table stays faithful to the machine-readable source and the\n * discrepancy is recorded in AGENTS.md rather than papered over here.\n */\nconst MODEL_PRICE_ROWS: readonly ModelPriceRow[] = [\n { id: 'claude-fable-5', rates: [10, 50, 1, 12.5] },\n { id: 'claude-fable-5-1', rates: [10, 50, 0.25, 12.5] },\n { id: 'claude-haiku-4-5', rates: [1, 5, 0.1, 1.25] },\n { id: 'claude-opus-4-6', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-4-7', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-4-8', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-5', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-sonnet-4-6', rates: [3, 15, 0.3, 3.75] },\n { id: 'claude-sonnet-5', rates: [2, 10, 0.2, 2.5] },\n { id: 'deepseek-v4-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'deepseek-v4-flash-fast', rates: [0.28, 0.56, 0.07] },\n { id: 'deepseek-v4-flash-vision-exp', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'deepseek-v4-pro', rates: [0.66, 1.98, 0.022], peak: [1.32, 3.96, 0.044] },\n { id: 'deepseek-v4.1-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'fugu-ultra', rates: [5, 30, 0.5] },\n { id: 'gemini-3.1-flash-lite', rates: [0.25, 1.5, 0.03] },\n { id: 'gemini-3.5-flash', rates: [1.5, 9, 0.15] },\n { id: 'gemini-3.5-flash-lite', rates: [0.3, 2.5, 0.03] },\n { id: 'gemini-3.6-flash', rates: [1.5, 7.5, 0.15] },\n { id: 'gemini-3.7-flash', rates: [1.5, 7.5, 0.15, 0.08334] },\n { id: 'gemini-3.8-flash', rates: [1.5, 7.5, 0.15] },\n { id: 'glm-5', rates: [1, 3.2, 0.2] },\n { id: 'glm-5.1', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.2', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.2-fast', rates: [3, 10.25, 0.5] },\n { id: 'glm-5.3', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.3-flash', rates: [0.15, 0.5, 0.03] },\n { id: 'gpt-5.3-codex', rates: [2, 8, 0.5, 0] },\n { id: 'gpt-5.4', rates: [2.5, 15, 0.25, 0] },\n { id: 'gpt-5.4-mini', rates: [0.75, 4.5, 0.075, 0] },\n { id: 'gpt-5.5', rates: [5, 30, 0.5, 0] },\n { id: 'gpt-5.6-luna', rates: [0.2, 1.2, 0.02, 0.25], contextTiers: [{\"maxContext\":272000,\"rates\":[0.2,1.2,0.02,0.25]},{\"rates\":[0.4,1.8,0.04,0.5]}] },\n { id: 'gpt-5.6-sol', rates: [5, 30, 0.5, 6.25], contextTiers: [{\"maxContext\":272000,\"rates\":[5,30,0.5,6.25]},{\"rates\":[10,45,1,12.5]}] },\n { id: 'gpt-5.6-terra', rates: [2, 12, 0.2, 2.5], contextTiers: [{\"maxContext\":272000,\"rates\":[2,12,0.2,2.5]},{\"rates\":[4,18,0.4,5]}] },\n { id: 'gpt-6-astra', rates: [10, 50, 1, 12.5], contextTiers: [{\"maxContext\":272000,\"rates\":[10,50,1,12.5]},{\"rates\":[20,75,2,25]}] },\n { id: 'grok-4.5', rates: [2, 6, 0.5] },\n { id: 'grok-4.6', rates: [2, 6, 0.5], contextTiers: [{\"maxContext\":200000,\"rates\":[2,6,0.5]},{\"rates\":[4,12,1]}] },\n { id: 'inkling', rates: [1, 4.05, 0.17] },\n { id: 'inkling-small', rates: [0.5, 1.2, 0.1] },\n { id: 'kimi-k2.5', rates: [0.6, 3, 0.1] },\n { id: 'kimi-k2.6', rates: [0.95, 4, 0.16] },\n { id: 'kimi-k2.7-code', rates: [0.95, 4, 0.19] },\n { id: 'kimi-k2.7-code-highspeed', rates: [1.9, 8, 0.38] },\n { id: 'kimi-k3', rates: [3, 15, 0.3] },\n { id: 'mimo-v2.5', rates: [0.14, 0.28, 0.0028] },\n { id: 'mimo-v2.5-pro', rates: [0.435, 0.87, 0.0036] },\n { id: 'minimax-m2.5', rates: [0.3, 1.2, 0.03] },\n { id: 'minimax-m2.7', rates: [0.3, 1.2, 0.06] },\n { id: 'minimax-m3', rates: [0.3, 1.2, 0.06] },\n { id: 'muse-spark-1.1', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.2', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.2-contributor', rates: [0.1, 0.2, 0.002] },\n { id: 'muse-spark-1.3', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.3-contributor', rates: [0.1, 0.2, 0.002] },\n { id: 'nemotron-3-ultra', rates: [0.6, 2.4, 0.12] },\n { id: 'qwen-3.6-max', rates: [1.3, 7.8, 0.26, 1.63] },\n { id: 'qwen-3.6-plus', rates: [0.5, 3, 0.1], contextTiers: [{\"maxContext\":256000,\"rates\":[0.5,3,0.1]},{\"rates\":[2,6,0.2]}] },\n { id: 'qwen-3.7-flash', rates: [0.03, 0.13, 0.006, 0.038], contextTiers: [{\"maxContext\":32000,\"rates\":[0.03,0.13,0.006,0.038]},{\"maxContext\":256000,\"rates\":[0.1,0.4,0.02,0.125]},{\"rates\":[0.2,0.8,0.04,0.25]}] },\n { id: 'qwen-3.7-max', rates: [2.5, 7.5, 0.5, 3.13] },\n { id: 'qwen-3.7-plus', rates: [0.4, 1.6, 0.08, 0.5], contextTiers: [{\"maxContext\":256000,\"rates\":[0.4,1.6,0.08,0.5]},{\"rates\":[1.2,4.8,0.24,1.5]}] },\n { id: 'qwen-3.8-27b', rates: [0.4, 3, 0.04] },\n { id: 'qwen-3.8-flash', rates: [0.16, 0.47, 0.016] },\n { id: 'qwen-3.8-max', rates: [2, 6, 0.25, 2.5] },\n { id: 'qwen-3.8-max-0902', rates: [2, 6, 0.25] },\n { id: 'step-3.5-flash', rates: [0.1, 0.3, 0.02] },\n { id: 'step-3.7-flash', rates: [0.2, 1.15, 0.04] },\n { id: 'tencent/hy3-paid', rates: [0.14, 0.58, 0.035] },\n { id: 'tencent/hy4-preview', rates: [0.834, 2.501, 0.042] },\n]\n\n/**\n * Catalog ids no candidate rule can reach, because the page names the model\n * differently from the catalog. `tests/model-prices.test.ts` fails whenever a\n * catalog model has no price, so a new miss lands here as a visible decision\n * rather than a silently unpriced model.\n */\nconst PRICE_SLUG_OVERRIDES: Readonly<Record<string, string>> = {\n // The page lists it by its short name; the catalog carries the full one.\n 'nvidia/nemotron-3-ultra-550b-a55b': 'nemotron-3-ultra',\n}\n\n/**\n * Plausible price slugs for one catalog model id, most specific first.\n *\n * The page normalizes to lowercase and usually drops the vendor segment, but\n * not consistently: `tencent/hy4-preview` keeps its prefix while\n * `Qwen/Qwen3.8-Max-0902` becomes `qwen-3.8-max-0902`, with a hyphen the\n * catalog id does not have. Generating candidates and taking the first that\n * exists in the vendored table absorbs that drift without a hand-maintained\n * map of seventy ids.\n */\nfunction priceSlugCandidates(modelId: string): string[] {\n const lower = modelId.toLowerCase()\n const bare = lower.includes('/') ? lower.slice(lower.indexOf('/') + 1) : lower\n const out = new Set<string>()\n const add = (slug: string): void => {\n const hyphenated = slug.replace(/^([a-z]+)(\\d)/, '$1-$2')\n out.add(slug)\n out.add(hyphenated)\n out.add(slug.replace(/-\\d{8}$/, ''))\n out.add(slug.replace(/-(preview|latest)$/, ''))\n out.add(hyphenated.replace(/-\\d{8}$/, ''))\n out.add(hyphenated.replace(/-(preview|latest)$/, ''))\n }\n add(lower)\n add(bare)\n return [...out]\n}\n\n/** The pricing-page slug for one catalog model id, or undefined when unpriced. */\nfunction priceSlugFor(modelId: string, known: ReadonlySet<string>): string | undefined {\n const override = PRICE_SLUG_OVERRIDES[modelId]\n if (override !== undefined) return known.has(override) ? override : undefined\n return priceSlugCandidates(modelId).find((slug) => known.has(slug))\n}\n\n/** Split a stored triplet/quadruplet into the wire rate shape. */\nfunction ratesOf(values: readonly number[]): CommandCodeModelRates {\n // Indexed access is asserted rather than defaulted: the generator above only\n // ever emits rows with the three published rates, so a short row is a broken\n // table and must not silently become a free model.\n const rates: CommandCodeModelRates = {\n inputCost: values[0]!,\n outputCost: values[1]!,\n cacheReadCost: values[2]!,\n }\n if (values[3] !== undefined) rates.cacheWriteCost = values[3]\n return rates\n}\n\n/** Build the full price row the browser prices a session with. */\nfunction wireRow(id: string, slug: string, row: ModelPriceRow): CommandCodeModelPrice {\n const price: CommandCodeModelPrice = { id, slug, ...ratesOf(row.rates) }\n if (row.peak !== undefined) price.peak = ratesOf(row.peak)\n if (row.contextTiers !== undefined) price.contextTiers = row.contextTiers.map(tier => ({\n ...ratesOf(tier.rates), ...(tier.maxContext === undefined ? {} : { maxContext: tier.maxContext }),\n }))\n return price\n}\n\n/**\n * Build the table the composer prices a session with.\n *\n * Rows are keyed by CATALOG id wherever the two namespaces reconcile, because\n * that is what a session reports, and every row also carries its page slug as a\n * second lookup key. Price rows no catalog model claims are served under the\n * slug alone, so drift in either direction still prices: a page rename the\n * catalog has not followed, or a model the catalog snapshot has not learned\n * yet. Free models are served explicitly at zero so the composer can say so\n * instead of showing nothing.\n *\n * The peak windows travel with the table, so the browser applies the very\n * schedule this snapshot knows instead of restating it.\n */\nexport function modelPriceTable(): CommandCodePriceTable {\n const bySlug = new Map(MODEL_PRICE_ROWS.map((row) => [row.id, row]))\n const known = new Set(bySlug.keys())\n const models: CommandCodeModelPrice[] = []\n const claimed = new Set<string>()\n\n for (const catalogId of Object.keys(KNOWN_PLANS)) {\n if (isFreeModel(catalogId) || catalogId.endsWith(':free')) {\n models.push({ id: catalogId, slug: catalogId, inputCost: 0, outputCost: 0, cacheReadCost: 0, free: true })\n continue\n }\n const slug = priceSlugFor(catalogId, known)\n if (slug === undefined) continue\n const row = bySlug.get(slug)\n if (row === undefined) continue\n claimed.add(slug)\n models.push(wireRow(catalogId, slug, row))\n }\n\n for (const row of MODEL_PRICE_ROWS) {\n if (claimed.has(row.id)) continue\n models.push(wireRow(row.id, row.id, row))\n }\n\n return {\n models,\n peakHours: PEAK_HOUR_RANGES.map(([start, end]) => [start, end] as [number, number]),\n }\n}\n\n","/** Shared, JSON-only billing facts. No Host or browser runtime imports. */\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\n\nexport interface CostTokens {\n uncachedInputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n}\n\n/** Requests with identical model/rates are folded into one group. */\nexport interface CostUsageGroup {\n provider: string\n model: string\n at: number | null\n contextTokens: number\n tokens: CostTokens\n}\n\nexport interface SessionCostFacts {\n pricingKey: number\n groups: CostUsageGroup[]\n}\n\nexport const zeroCostTokens = (): CostTokens => ({ uncachedInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })\nexport const COST_TOKEN_KEYS = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\n\nexport function peakHour(at: number, windows: ReadonlyArray<readonly [number, number]>): boolean {\n const time = new Date(at)\n return time.getUTCDay() !== 0 && time.getUTCDay() !== 6\n && windows.some(([start, end]) => time.getUTCHours() >= start && time.getUTCHours() < end)\n}\n\n/**\n * All prompt billing buckets determine a request's band, never cumulative session input.\n *\n * A tiered model returns the matching band and does NOT then apply `peak`: the\n * page publishes those two dimensions independently, no row carries both today,\n * and the generator would report a tiered row on every sync — so the combination\n * becoming real is visible before it reaches a user. This ordering is a latent\n * choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // The first band whose bound accepts the prompt. ORDER IS LOAD-BEARING, and\n // both producers enforce it: the generator refuses non-ascending bounds or a\n // bounded last band, and the wire parser rejects the same shapes — so a\n // conforming table cannot present bands out of order, and this `find` cannot\n // select a band a later one should have won.\n const tier = price.contextTiers?.find(tier => tier.maxContext === undefined || contextTokens <= tier.maxContext)\n if (tier !== undefined) return tier\n return price.peak !== undefined && at !== null && peakHour(at, table.peakHours) ? price.peak : price\n}\n\n/** Cache version and wire guard: changing bands/rates must refold historical groups. */\nexport function pricingKey(table: CommandCodePriceTable): number {\n const rates = (r: CommandCodeModelRates) => [r.inputCost, r.outputCost, r.cacheReadCost, r.cacheWriteCost ?? null]\n const canonical = JSON.stringify(['commandCodeCost-v1', table.peakHours, table.models.map(p => [p.id, p.slug, p.free === true, rates(p), p.peak ? rates(p.peak) : null, p.contextTiers?.map(t => [t.maxContext ?? null, rates(t)]) ?? null])])\n let hash = 2166136261\n for (const c of canonical) hash = Math.imul(hash ^ c.charCodeAt(0), 16777619) >>> 0\n return hash\n}\n\n/** Only safe to merge requests whose billing classification is identical. */\nexport function costGroupKey(group: CostUsageGroup, table: CommandCodePriceTable): string {\n const price = table.models.find(p => p.id === group.model || p.slug === group.model)\n return JSON.stringify([group.provider, group.model, price === undefined ? null : requestRates(price, group.at, group.contextTokens, table), group.at === null])\n}\n","/** Durable cost facts: mirrors token-meter's replacement/retry rules across v1/v2 logs. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { modelPriceTable } from './model-prices.ts'\nimport { COST_TOKEN_KEYS, costGroupKey, pricingKey, zeroCostTokens, type CostTokens, type CostUsageGroup, type SessionCostFacts } from './cost-facts.ts'\n\ninterface CostState {\n selection: { provider: string; model: string } | null\n at: number | null\n last: { turn: number; step: number; group: CostUsageGroup } | null\n facts: SessionCostFacts\n}\ninterface LogEvent { type: string; time: number; data: unknown }\nconst record = (v: unknown): Record<string, unknown> | undefined => typeof v === 'object' && v !== null && !Array.isArray(v) ? v as Record<string, unknown> : undefined\nconst finite = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v >= 0\n\nfunction tokensOf(value: unknown): CostTokens | undefined {\n const u = record(value)\n if (!u || !finite(u.inputTokens) || !finite(u.outputTokens)) return undefined\n if (u.cacheReadTokens !== undefined && !finite(u.cacheReadTokens) || u.cacheWriteTokens !== undefined && !finite(u.cacheWriteTokens)) return undefined\n return { uncachedInputTokens: u.inputTokens, outputTokens: u.outputTokens, cacheReadTokens: u.cacheReadTokens as number ?? 0, cacheWriteTokens: u.cacheWriteTokens as number ?? 0 }\n}\n\n/** Current v2 settlements store the last usage in their stream; v1 stores chunk events. */\nfunction usageOf(type: string, data: Record<string, unknown>): CostTokens | undefined {\n if (type === 'assistant/chunk') {\n const chunk = record(data.chunk)\n return chunk?.type === 'usage' ? tokensOf(chunk.usage) : undefined\n }\n if (type !== 'assistant/message' && type !== 'assistant/attempt') return undefined\n const direct = tokensOf(data.usage)\n if (direct !== undefined) return direct\n if (!Array.isArray(data.stream)) return undefined\n for (let i = data.stream.length - 1; i >= 0; i--) {\n const item = record(data.stream[i])\n const chunk = item?.type === 'chunk' ? record(item.chunk) : undefined\n if (chunk?.type === 'usage') return tokensOf(chunk.usage)\n }\n return undefined\n}\n\nfunction parseState(value: unknown): CostState {\n const s = record(value), facts = record(s?.facts)\n if (!s || !facts || !finite(facts.pricingKey) || !Array.isArray(facts.groups)) throw new TypeError('invalid commandCodeCost state')\n const group = (v: unknown): boolean => {\n const g = record(v), t = record(g?.tokens)\n return !!g && typeof g.provider === 'string' && typeof g.model === 'string' && (g.at === null || finite(g.at)) && finite(g.contextTokens) && !!t && COST_TOKEN_KEYS.every(k => finite(t[k]))\n }\n const sel = record(s.selection), last = record(s.last)\n if (!(s.selection === null || sel && typeof sel.provider === 'string' && typeof sel.model === 'string')\n || !(s.at === null || finite(s.at)) || !facts.groups.every(group)\n || !(s.last === null || last && finite(last.turn) && finite(last.step) && group(last.group))) throw new TypeError('invalid commandCodeCost state')\n return value as CostState\n}\n\n/** Optional registry uses only synchronous parse/view; no new runtime module is required. */\nexport function createCostProjection(table = modelPriceTable()) {\n const version = pricingKey(table)\n return {\n key: 'commandCodeCost', stateVersion: version,\n stateSchema: { parse: parseState },\n init: (): CostState => ({ selection: null, at: null, last: null, facts: { pricingKey: version, groups: [] } }),\n apply(state: CostState, event: LogEvent): CostState {\n const data = record(event.data)\n if (!data) return state\n if (event.type === 'request/header') {\n const config = record(record(data.header)?.config)\n return { ...state, selection: config && typeof config.provider === 'string' && typeof config.model === 'string' ? { provider: config.provider, model: config.model } : null }\n }\n if (event.type === 'step/start' || event.type === 'llm/retry-started') return { ...state, at: finite(event.time) ? event.time : null, last: null }\n const tokens = usageOf(event.type, data)\n if (tokens === undefined || !finite(data.turn) || !finite(data.step)) return state\n const previous = state.last?.turn === data.turn && state.last.step === data.step ? state.last.group : undefined\n const group: CostUsageGroup = { provider: state.selection?.provider ?? '', model: state.selection?.model ?? '', at: state.at, contextTokens: tokens.uncachedInputTokens + tokens.cacheReadTokens + tokens.cacheWriteTokens, tokens }\n if (previous && JSON.stringify(previous) === JSON.stringify(group)) return state\n const groups = state.facts.groups.map(g => ({ ...g, tokens: { ...g.tokens } }))\n if (previous) {\n const old = groups.find(g => costGroupKey(g, table) === costGroupKey(previous, table))\n if (old) for (const k of COST_TOKEN_KEYS) old.tokens[k] -= previous.tokens[k]\n }\n let target = groups.find(g => costGroupKey(g, table) === costGroupKey(group, table))\n if (!target) { target = { ...group, tokens: zeroCostTokens() }; groups.push(target) }\n for (const k of COST_TOKEN_KEYS) target.tokens[k] += tokens[k]\n return { ...state, last: { turn: data.turn, step: data.step, group }, facts: { pricingKey: version, groups: groups.filter(g => COST_TOKEN_KEYS.some(k => g.tokens[k] > 0)) } }\n },\n wire: {\n view: (state: CostState) => state.facts,\n viewSchema: { parse(value: unknown): SessionCostFacts { return parseState({ selection: null, at: null, last: null, facts: value }).facts } },\n },\n }\n}\n\nexport function installCostProjection(ctx: Context): void {\n ctx.inject(['sessionProjections'], c => {\n const registry = c.get('sessionProjections') as { register(definition: ReturnType<typeof createCostProjection>): () => void } | undefined\n if (typeof registry?.register === 'function') c.effect(() => registry.register(createCostProjection()), 'commandcode cost projection')\n })\n}\n","/**\n * Multi-account pool for the Command Code provider (host side).\n *\n * One Command Code subscription (e.g. the Go plan's 5-hour window) is\n * metered; a user with several subscriptions wants a request that hits one\n * account's limit to continue on the next account without a visible failure.\n * This module owns that rotation:\n *\n * - {@link CommandCodeAccountPool.resolveKey} hands out the first account\n * whose key is not currently marked exhausted — or, when the request's\n * model matches a {@link CommandCodeModelAccountRule} and that account is\n * usable, the routed account — resolving each slot's key lazily (literal\n * config key → credential seam → launch environment → the official CLI\n * auth file for the default slot only).\n * - {@link CommandCodeAccountPool.markRejected} records a 429 (rate limit,\n * window unknown) or 401 (invalid key, disabled until the config changes)\n * against the exact API key, so several slots sharing one key share one\n * state.\n * - When every account is marked, the pool probes each key's\n * `/alpha/billing/credits` window limits (through the injected\n * {@link CommandCodeAccountPoolDeps.probeWindow}): an account whose window\n * no longer reports `exceeded` is revived, otherwise the pool throws a\n * `RATE_LIMIT` error naming the earliest reset time.\n *\n * The pool is deliberately cordis-free (like the adapter): every host fact\n * arrives through injected thunks, so node tests can drive it directly.\n *\n * @module dsh-commandcode-provider/accounts\n */\n\nimport { LlmError } from '@deepseek-ai/dsh-llm'\nimport type { CredentialRef } from '@deepseek-ai/dsh-credentials'\n\n/**\n * Upper bound on the retry wait this pool attaches to the all-exhausted\n * `RATE_LIMIT` error. Must equal the `backoff.maxDelayMs` in the adapter's\n * `providerRetryPolicy` (which imports it from here): dsh-llm-retry honors a\n * provider-specified wait verbatim only at or below that cap — in normal mode\n * a LONGER attached wait makes the executor abandon the retry entirely\n * instead of falling back to local backoff, which would turn \"poll until the\n * window opens\" into \"fail now\".\n */\nexport const RETRY_MAX_DELAY_MS = 900_000\n\n/** One extra account's raw configuration (composition config or settings). */\nexport interface CommandCodeAccountConfig {\n /** Display label shown in the usage dashboard and settings page. */\n label?: string\n /** Credential reference (environment-variable style name) holding this account's API key. */\n apiKeyEnv?: string\n /** Literal API key (composition config only; never stored in settings). */\n apiKey?: string\n}\n\n/** One account slot after config normalization. */\nexport interface CommandCodeAccountSlot {\n /** Stable id: `default` for the implicit first account, `account-N` for extras. */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Credential reference resolved through the seam; undefined for literal-only slots. */\n ref?: CredentialRef | undefined\n /** Literal key from composition config. */\n literal?: string | undefined\n /** Whether the official CLI auth file may back this slot (default slot only). */\n allowAuthFile: boolean\n}\n\n/** Why a key stopped serving requests. */\nexport type AccountRejection = 'rate-limit' | 'invalid-credential'\n\n/** One key's rotation state. */\nexport interface CommandCodeAccountState {\n kind:\n /** Marked by a 429; the window's reset time is unknown until probed. */\n | 'unknown'\n /** Probed (or marked with a known reset): unusable until `until` (millis). */\n | 'cooldown'\n /** Marked by a 401: skipped until the stored credential changes. */\n | 'disabled'\n /** Human-readable reason for the mark (e.g. `rate limited (429)`). */\n reason: string\n /** Cooldown end in millis; 0 for the other kinds. */\n until: number\n}\n\n/** A slot paired with its resolved key (both pool-internal and UI-facing). */\nexport interface ResolvedAccount {\n slot: CommandCodeAccountSlot\n key: string\n /** The key's current rotation state; undefined means usable. */\n state: CommandCodeAccountState | undefined\n}\n\n/** Five-hour window facts probed from `/alpha/billing/credits`. */\nexport interface FiveHourWindowProbe {\n exceeded: boolean\n resetAt: number\n}\n\n/** Everything the pool needs from the host; all seams are injected. */\nexport interface CommandCodeAccountPoolDeps {\n /** The current account slots, re-read per resolution so settings changes apply live. */\n slots(): readonly CommandCodeAccountSlot[]\n /** Resolve one credential reference through the credentials service or the launch environment. */\n resolveRef(ref: CredentialRef): Promise<string | undefined>\n /** The official CLI auth-file key (`~/.commandcode/auth.json`); default slot only. */\n authFileKey(): string | undefined\n /** Probe one key's five-hour window; undefined when the probe itself failed. */\n probeWindow(apiKey: string): Promise<FiveHourWindowProbe | undefined>\n /**\n * The manually selected account (a slot id, e.g. `default` or an extra's\n * credential reference), re-read per resolution. The preferred account\n * serves whenever it is usable; an unknown id or an exhausted preferred\n * account falls back to the first usable slot.\n */\n preferredId?(): string | undefined\n /**\n * Model → account routing rules, re-read per resolution so settings changes\n * apply live. Each rule lists catalog model ids (see\n * {@link CommandCodeModelAccountRule}) to an account slot id. When the\n * request's model matches a rule and that account is usable, it serves\n * before the preferred/rotation selection; an unusable routed account falls\n * back to the normal selection (the router is a hint, never a hard gate).\n */\n modelAccountRules?(): readonly CommandCodeModelAccountRule[]\n}\n\n/**\n * One \"route these models to that account\" rule. `models` lists catalog ids\n * (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an\n * extra account's credential reference). A request whose model id is in the\n * list routes to that account. The first matching rule in list order wins.\n */\nexport interface CommandCodeModelAccountRule {\n /** Catalog model ids to match against the request's model. */\n models: string[]\n /** Account slot id to prefer for matching models. */\n account: string\n}\n\n/** A labeled, human-readable clock reading for error messages. */\nfunction clockLabel(ms: number): string {\n return new Date(ms).toLocaleString()\n}\n\n/**\n * Whether an account with this rotation state can serve a request right now.\n * `undefined` (never rejected) is usable; a cooldown becomes usable again\n * once its reset time passes; `unknown` (429, reset unprobed) and\n * `disabled` (401) are not.\n */\nexport function accountUsable(state: CommandCodeAccountState | undefined): boolean {\n if (state === undefined) return true\n if (state.kind === 'cooldown') return state.until > 0 && Date.now() >= state.until\n return false\n}\n\n/**\n * Pick the account that should serve now: the manually preferred slot when it\n * is usable, otherwise the first usable account in rotation order; undefined\n * when no account is usable. Shared by the pool (request path) and the plugin\n * entry (the usage view's active badge) so both always agree.\n */\nexport function selectActiveAccount(\n accounts: readonly ResolvedAccount[],\n preferredId: string | undefined,\n): ResolvedAccount | undefined {\n const usable = accounts.filter((account) => accountUsable(account.state))\n if (preferredId !== undefined) {\n const preferred = usable.find((account) => account.slot.id === preferredId)\n if (preferred !== undefined) return preferred\n }\n return usable[0]\n}\n\n/**\n * The first routing rule whose model list contains the request's model id.\n * Undefined when no rule matches.\n */\nexport function matchModelRule(\n model: string,\n rules: readonly CommandCodeModelAccountRule[] | undefined,\n): CommandCodeModelAccountRule | undefined {\n if (model === '' || rules === undefined || rules.length === 0) return undefined\n for (const rule of rules) {\n if (rule.models.includes(model)) return rule\n }\n return undefined\n}\n\n/**\n * The routed account for a request's model: the first usable account whose\n * slot id matches the first matching rule's target. Undefined when no rule\n * matches or the routed account is not usable (the caller then falls back to\n * the normal preferred/rotation selection).\n */\nexport function selectAccountForModel(\n accounts: readonly ResolvedAccount[],\n model: string,\n rules: readonly CommandCodeModelAccountRule[] | undefined,\n): ResolvedAccount | undefined {\n const rule = matchModelRule(model, rules)\n if (rule === undefined) return undefined\n return accounts.find((account) => account.slot.id === rule.account && accountUsable(account.state))\n}\n\n/**\n * The account pool. Rotation state is keyed by API key (never logged), so two\n * slots resolving to the same credential share one mark, and a key changed in\n * the credentials service starts with a clean slate.\n */\nexport class CommandCodeAccountPool {\n /** Rotation state by API key. */\n private readonly states = new Map<string, CommandCodeAccountState>()\n constructor(private readonly deps: CommandCodeAccountPoolDeps) {}\n\n /**\n * Resolve every slot's key, deduplicated by key (first slot wins). Slots\n * without any resolvable key are omitted — they still appear in the\n * settings page as unconfigured, they just cannot serve requests.\n */\n async resolvedAccounts(): Promise<ResolvedAccount[]> {\n const out: ResolvedAccount[] = []\n const seen = new Set<string>()\n for (const slot of this.deps.slots()) {\n const key = await this.resolveSlotKey(slot)\n if (key === undefined || seen.has(key)) continue\n seen.add(key)\n out.push({ slot, key, state: this.states.get(key) })\n }\n return out\n }\n\n /**\n * Every slot paired with its resolved key and rotation state — NOT\n * deduplicated: two slots sharing one credential both appear (the usage\n * view reports them individually), while slots without any resolvable key\n * are omitted. The serving path uses {@link resolvedAccounts} instead.\n */\n async describeAccounts(): Promise<ResolvedAccount[]> {\n const out: ResolvedAccount[] = []\n for (const slot of this.deps.slots()) {\n const key = await this.resolveSlotKey(slot)\n if (key === undefined) continue\n out.push({ slot, key, state: this.states.get(key) })\n }\n return out\n }\n\n /**\n * Hand out the key for a request: the model-routed account when the\n * request's model matches a rule (and that account is usable), else the\n * manually preferred account when usable, else the first usable account in\n * rotation order. Returns `undefined` when no account resolves any key at\n * all (the caller then reports the missing credential). Throws\n * `RATE_LIMIT` — naming the earliest window reset — or\n * `INVALID_CREDENTIAL` when accounts exist but none can serve.\n *\n * `options.model` is the request's model id; routing rules re-read per\n * resolution, so a settings change applies live.\n *\n * `options.exclude` skips one key during the probe-revival pass: the\n * rotation hook excludes the just-rejected key so a probe that clears its\n * window cannot re-offer the same key within the same request (the adapter\n * refuses already-tried keys; the next request picks the revived key up).\n */\n async resolveKey(options?: { exclude?: string; model?: string }): Promise<{ key: string; slot: CommandCodeAccountSlot } | undefined> {\n const accounts = await this.resolvedAccounts()\n if (accounts.length === 0) {\n return undefined\n }\n const routed = selectAccountForModel(accounts, options?.model ?? '', this.deps.modelAccountRules?.())\n if (routed !== undefined) return this.pick(routed)\n const preferred = this.deps.preferredId?.()\n const chosen = selectActiveAccount(accounts, preferred)\n if (chosen !== undefined) return this.pick(chosen)\n\n // Every key is marked: probe the real windows before giving up. Disabled\n // (401) keys are not probed — an invalid key stays invalid. A throwing\n // probe counts as \"unknown\" (like a failed probe): it must not turn the\n // all-exhausted path into a raw rejection instead of RATE_LIMIT.\n await Promise.all(accounts.map(async (account) => {\n if (account.state?.kind === 'disabled') return\n if (options?.exclude !== undefined && account.key === options.exclude) return\n let probe: FiveHourWindowProbe | undefined\n try {\n probe = await this.deps.probeWindow(account.key)\n } catch {\n return\n }\n if (probe === undefined) return\n if (!probe.exceeded) {\n this.states.delete(account.key)\n } else {\n this.states.set(account.key, {\n kind: 'cooldown',\n reason: account.state?.reason ?? 'rate limited (429)',\n until: probe.resetAt,\n })\n }\n }))\n\n // Re-resolve once: the probe pass above may have revived keys (fresh\n // states), and both the revival check and the error classification read\n // the same post-probe snapshot. (Each resolvedAccounts() re-runs the\n // async seams, so two calls — not three — is the minimum here.)\n const latest = await this.resolvedAccounts()\n const revived = selectActiveAccount(latest, preferred)\n if (revived !== undefined) return this.pick(revived)\n\n const disabled = latest.filter((account) => account.state?.kind === 'disabled')\n if (disabled.length === latest.length) {\n // Bilingual: the harness UI renders this message verbatim inside its\n // (already localized) retry/turn-error chrome, so both languages ride\n // in one string — English first, then the Chinese reading.\n throw new LlmError(\n `llm-commandcode: every configured Command Code account (${latest.length}) was rejected with 401`\n + ' — check the stored API keys (Models page / settings) or the auth file'\n + `;已配置的 ${latest.length} 个 Command Code 账户密钥均被拒绝(401)`\n + '——请在设置页检查存储的 API 密钥,或重新运行 command-code login',\n 'INVALID_CREDENTIAL',\n )\n }\n const resets = latest\n .map((account) => account.state)\n .filter((state): state is CommandCodeAccountState => state !== undefined && state.kind === 'cooldown' && state.until > 0)\n .map((state) => state.until)\n const earliest = resets.length > 0 ? Math.min(...resets) : 0\n // Hand dsh-llm-retry the exact wait until the earliest known reset so the\n // retry policy sleeps through the window instead of polling at its\n // backoff cadence. Capped at RETRY_MAX_DELAY_MS: the executor honors a\n // provider wait verbatim only at or below the policy's maxDelayMs — a\n // LONGER attached wait makes it abandon the retry entirely (normal mode),\n // which would turn \"poll until the window opens\" into \"fail now\". Longer\n // resets simply ride the capped local backoff and the probe revival.\n const wait = earliest > 0 ? Math.max(1000, earliest - Date.now()) : 0\n throw new LlmError(\n `llm-commandcode: all ${latest.length} Command Code account(s) have exhausted their usage window`\n + (earliest > 0 ? `; the earliest window resets at ${clockLabel(earliest)}` : '')\n + ' — requests will succeed again after the reset (or add another account)'\n + `;已用尽全部 ${latest.length} 个 Command Code 账户的用量窗口`\n + (earliest > 0 ? `,最早的重置时间为 ${clockLabel(earliest)}` : '')\n + '——窗口重置后请求会自动恢复(也可以添加更多账户)',\n 'RATE_LIMIT',\n wait > 0 && wait <= RETRY_MAX_DELAY_MS ? { providerRetryAfterMs: wait } : undefined,\n )\n }\n\n /**\n * Record a rejection against one key. `rate-limit` (429) marks the key\n * exhausted with an unknown reset (probed lazily at the next resolution\n * once every account is marked); `invalid-credential` (401) disables the\n * key until the stored credential changes.\n */\n markRejected(apiKey: string, rejection: AccountRejection): void {\n if (rejection === 'invalid-credential') {\n this.states.set(apiKey, { kind: 'disabled', reason: 'invalid API key (401)', until: 0 })\n } else {\n this.states.set(apiKey, { kind: 'unknown', reason: 'rate limited (429)', until: 0 })\n }\n }\n\n /**\n * One account's key: literal → credential seam → auth file (default slot).\n *\n * Every source is normalized here, at the single point where a slot's key\n * enters the pool. The adapter sends the key through the harness's\n * `assertUsableApiKey()`, which trims it — a stored key from the credentials\n * seam, a `.env` line, or a shell export all pick up surrounding whitespace\n * — and reports that trimmed form back to `markRejected()`. Returning the\n * raw value would file every 429/401 mark under a key no later lookup can\n * find: rotation would re-offer the same account, the account card would show\n * no mark, and the usage endpoints would 401 while chat kept working.\n * Normalizing once makes resolution, probing, marking, and the request path\n * agree on one string.\n */\n private async resolveSlotKey(slot: CommandCodeAccountSlot): Promise<string | undefined> {\n if (slot.literal !== undefined) {\n const literal = normalizeResolvedKey(slot.literal)\n if (literal !== undefined) return literal\n }\n if (slot.ref !== undefined) {\n const hit = await this.deps.resolveRef(slot.ref)\n if (hit !== undefined) {\n const resolved = normalizeResolvedKey(hit)\n if (resolved !== undefined) return resolved\n }\n }\n if (slot.allowAuthFile) {\n const fromFile = this.deps.authFileKey()\n if (fromFile !== undefined) {\n const fileKey = normalizeResolvedKey(fromFile)\n if (fileKey !== undefined) return fileKey\n }\n }\n return undefined\n }\n\n /** Hand out the chosen account's key. */\n private pick(account: ResolvedAccount): { key: string; slot: CommandCodeAccountSlot } {\n return { key: account.key, slot: account.slot }\n }\n}\n\n/**\n * Normalize one resolved credential to the form every consumer sees. Trim\n * only: a blank-after-trim value means \"no key\" (the slot is omitted and the\n * caller reports `MISSING_CREDENTIAL`), while characters an HTTP header cannot\n * carry are left for `assertUsableApiKey()` to reject with its own message.\n */\nfunction normalizeResolvedKey(value: string): string | undefined {\n const trimmed = value.trim()\n return trimmed === '' ? undefined : trimmed\n}\n","/**\n * Request-image targets: the shape one provider request asks the attachment\n * service to produce.\n *\n * An attachment is stored NORMALIZED, not request-ready — `readImage()` answers\n * the full normalized original, which is what admission accepted. Every request\n * should carry a REQUEST VERSION instead (`readImageRequest()`): the same image\n * re-encoded to a route target and cached under it. On this route that matters\n * three times over, because both transports inline every historical image as\n * base64: bytes become context, latency, and progress against the gateway's\n * undocumented ~50 MB body cap (see the request image budget in `./adapter.ts`).\n *\n * ONE target serves both attachment generations, although they disagree on the\n * shape AND on where the projection happens:\n *\n * ≤ 0.1.5 — `readImageRequest(ref, policy)` takes `{ maxPixels, maxBytes }` and\n * applies the pixel budget itself, aspect-preserving.\n * ≥ 0.1.6 — `readImageRequest(ref, target)` takes the ALREADY PROJECTED\n * `{ width, height, maxBytes }`; there is no pixel budget any more.\n *\n * So the target carries both vocabularies: the projected dimensions, plus the\n * pixel area they came from. Each generation reads the fields it knows and\n * ignores the rest — which is why the object is BUILT HERE and passed as a\n * variable: an object literal at the call site would be rejected by the\n * excess-property check of whichever generation's types this checkout compiles\n * against, and those types are a release behind the engine at runtime.\n *\n * Nothing in here may import a version-specific helper (`longEdgeDimensions`\n * only exists from 0.1.6), so the projection is restated locally.\n *\n * @module dsh-commandcode-provider/image-request\n */\n\nimport type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\n/**\n * Long edge one request image may keep, in pixels.\n *\n * 1568 is Anthropic's documented ceiling — their API downscales anything larger\n * before the model sees it — and it sits inside the high-detail band of the\n * OpenAI and Gemini tile schemes, so no upstream this gateway reaches reads\n * more detail than the target keeps. Screenshots from a Retina display are the\n * case this is for: 2880x1800 becomes 1568x980, a 3.4x pixel cut, and the\n * models lose nothing they would not have downscaled themselves.\n */\nexport const REQUEST_IMAGE_MAX_LONG_EDGE = 1568\n\n/**\n * Encoded bytes one request image may keep, before base64 expansion. The same\n * 1 MiB budget the harness's own multi-provider adapter defaults to; the\n * attachment service keeps its smallest quality-ladder output when no quality\n * fits, so this bounds bytes without ever refusing an image.\n */\nexport const REQUEST_IMAGE_MAX_ENCODED_BYTES = 1024 * 1024\n\n/**\n * One image's request target, in both generations' vocabulary at once. See the\n * module note: the extra fields are deliberate, not leftovers.\n */\nexport interface RequestImageTarget {\n /** ≤0.1.5's pixel budget: the projected area this target came from. */\n maxPixels: number\n /** ≥0.1.6's target width, already projected. */\n width: number\n /** ≥0.1.6's target height, already projected. */\n height: number\n /** Both generations' encoded-byte budget. */\n maxBytes: number\n}\n\n/**\n * Aspect-preserving projection onto a long-edge budget; never enlarges, and\n * never returns a zero dimension (a 1-px degenerate side is what the round of\n * an extreme aspect ratio can produce, and a 0 would make the encoder refuse).\n *\n * A local restatement of the helper 0.1.6 exports from `dsh-attachment`, which\n * 0.1.2–0.1.5 do not have; the math is the whole contract, so keeping the copy\n * here costs less than a version probe would.\n */\nexport function longEdgeDimensions(\n width: number,\n height: number,\n longEdge: number,\n): { width: number; height: number } {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n // Defensive: a malformed reference must not become a zero-sized target.\n return { width: Math.max(1, Math.round(width) || 1), height: Math.max(1, Math.round(height) || 1) }\n }\n if (longEdge >= Math.max(width, height)) return { width, height }\n return width >= height\n ? { width: longEdge, height: Math.max(1, Math.round((longEdge * height) / width)) }\n : { width: Math.max(1, Math.round((longEdge * width) / height)), height: longEdge }\n}\n\n/**\n * The request target for one normalized attachment: its aspect ratio under the\n * long-edge budget, plus the byte budget every generation honours.\n *\n * The area is computed from the PROJECTED dimensions rather than the source's,\n * so ≤0.1.5's own pixel projection lands on the same geometry instead of\n * re-deriving a slightly different one from the original.\n */\nexport function requestImageTarget(ref: ImageAttachmentRef): RequestImageTarget {\n const projected = longEdgeDimensions(ref.width, ref.height, REQUEST_IMAGE_MAX_LONG_EDGE)\n return {\n maxPixels: projected.width * projected.height,\n width: projected.width,\n height: projected.height,\n maxBytes: REQUEST_IMAGE_MAX_ENCODED_BYTES,\n }\n}\n","/**\n * Vision-token accounting for the model families Command Code routes to.\n *\n * The harness's token meter prices request images through\n * `LlmAdapter.imageRequestPricing(provider, model).priceImages(blocks)` and,\n * when a route declares nothing, falls back to a structural estimate that\n * charges a handful of tokens for ANY image. On an image-heavy session that is\n * not a rounding error: a screenshot loop can carry dozens of full-size images\n * that the heuristic prices at ~0 tokens each, so context pressure is\n * under-reported and the session walks into its own context window.\n *\n * This route is a gateway in front of many upstreams — one catalog id per model,\n * but the visual-token rule belongs to whoever serves it. So the estimate is per\n * FAMILY, using each vendor's published rule, and the families are recognised by\n * the catalog id (which names the vendor). Every formula is stated here rather\n * than imported: the only in-tree implementations live inside the official\n * adapters, and this plugin deliberately does not depend on those protocols.\n *\n * These are ESTIMATES for context accounting, not invoices — the provider's own\n * usage remains authoritative for a completed request, exactly as the published\n * per-token rates the session-cost readout uses are.\n *\n * @module dsh-commandcode-provider/image-tokens\n */\n\nimport { longEdgeDimensions } from './image-request.ts'\n\n/** The published visual-token rules this route can tell apart. */\nexport type ImageTokenFamily = 'anthropic' | 'openai' | 'google' | 'deepseek' | 'generic'\n\n/**\n * Which family prices one catalog model id.\n *\n * `generic` is not \"we do not know the model\" but \"we cannot tell its visual\n * rule apart from the known ones\" — the Qwen, MiniMax, xAI, moonshot and\n * sakana families all publish patch- or tile-based accounting close to the\n * Anthropic rule, so the conservative fallback below covers them without\n * pretending to more precision than we have.\n */\nexport function imageTokenFamily(modelId: string): ImageTokenFamily {\n const id = modelId.toLowerCase()\n const vendor = id.includes('/') ? id.slice(0, id.indexOf('/')) : ''\n if (id.startsWith('claude')) return 'anthropic'\n if (id.startsWith('gpt') || /^o[1-9]/.test(id)) return 'openai'\n if (vendor === 'google' || id.startsWith('gemini')) return 'google'\n if (vendor === 'deepseek') return 'deepseek'\n return 'generic'\n}\n\n/**\n * Visual tokens one request image costs on the given family, at the dimensions\n * this route would actually send (see `./image-request.ts`).\n */\nexport function imageTokenCost(family: ImageTokenFamily, width: number, height: number): number {\n switch (family) {\n case 'anthropic': return anthropicImageTokens(width, height)\n case 'openai': return openAiImageTokens(width, height)\n case 'google': return googleImageTokens(width, height)\n case 'deepseek': return deepSeekImageTokens(width, height)\n default: return genericImageTokens(width, height)\n }\n}\n\n/** Convenience for callers that have a model id: family lookup plus the rule. */\nexport function commandCodeImageTokens(modelId: string, width: number, height: number): number {\n return imageTokenCost(imageTokenFamily(modelId), width, height)\n}\n\n/**\n * Anthropic: the image is first scaled so its long edge is at most 1568 px\n * (never enlarged), then charged roughly one token per 750 pixels.\n * Source: Anthropic vision documentation, \"Image size and token usage\".\n */\nfunction anthropicImageTokens(width: number, height: number): number {\n const projected = longEdgeDimensions(width, height, 1568)\n return Math.max(1, Math.ceil((projected.width * projected.height) / 750))\n}\n\n/**\n * OpenAI (high detail): scale to fit inside 2048x2048, then scale the shortest\n * side to 768 px, then charge an 85-token base plus 170 tokens per 512x512\n * tile. Source: OpenAI vision documentation, \"Calculating costs\".\n */\nfunction openAiImageTokens(width: number, height: number): number {\n let scaled = { width: Math.max(1, width), height: Math.max(1, height) }\n const longest = Math.max(scaled.width, scaled.height)\n if (longest > 2048) scaled = scaleBy(scaled, 2048 / longest)\n const shortest = Math.min(scaled.width, scaled.height)\n if (shortest > 768) scaled = scaleBy(scaled, 768 / shortest)\n const tiles = Math.ceil(scaled.width / 512) * Math.ceil(scaled.height / 512)\n return 85 + 170 * tiles\n}\n\n/**\n * Google Gemini: an image whose both sides are at most 384 px costs a flat 258\n * tokens; anything larger is cropped into 768x768 tiles of 258 tokens each.\n * Source: Gemini image-understanding documentation.\n */\nfunction googleImageTokens(width: number, height: number): number {\n if (width <= 384 && height <= 384) return 258\n return 258 * Math.ceil(width / 768) * Math.ceil(height / 768)\n}\n\n/** 14-px patches, merged 3x3 into one token cell. */\nconst DEEPSEEK_PATCH_SIZE = 14\nconst DEEPSEEK_DOWNSAMPLE_RATIO = 3\n/** The provider's cap on tokens for one request image. */\nconst DEEPSEEK_MAX_IMAGE_TOKENS = 1024\n/** Total-pixel floor; a smaller image is enlarged before grid projection. */\nconst DEEPSEEK_MIN_PIXELS = 544 * 544\n\n/**\n * DeepSeek: pad to 14-px patches, merge each 3x3 patch block into one token\n * cell, charge one token per cell plus one separator per row plus two framing\n * tokens, and cap one image at 1024 tokens by downscaling it aspect-preserving\n * (images below 544x544 are enlarged first).\n *\n * Mirrors `deepSeekImageTokens` in the official `dsh-llm-deepseek` adapter\n * (its `PATCH_SIZE`, `DOWNSAMPLE_RATIO`, `MAX_IMAGE_TOKENS` and `MIN_PIXELS`).\n * The official solver picks the largest grid that fits the cap; this restates\n * that as a bounded search over the scale factor, which lands on the same grid\n * without vendoring the closed-form solver.\n */\nfunction deepSeekImageTokens(width: number, height: number): number {\n let scaled = { width: Math.max(1, width), height: Math.max(1, height) }\n const pixels = scaled.width * scaled.height\n if (pixels < DEEPSEEK_MIN_PIXELS) scaled = scaleBy(scaled, Math.sqrt(DEEPSEEK_MIN_PIXELS / pixels))\n\n const direct = deepSeekGridTokens(scaled.width, scaled.height)\n if (direct <= DEEPSEEK_MAX_IMAGE_TOKENS) return direct\n\n // Over the cap: the provider keeps the aspect ratio and downsamples until the\n // grid fits, so the charge is the largest fitting grid — never above the cap.\n let low = 0\n let high = 1\n let best = direct\n for (let step = 0; step < 24; step += 1) {\n const mid = (low + high) / 2\n const tokens = deepSeekGridTokens(\n Math.max(1, Math.round(scaled.width * mid)),\n Math.max(1, Math.round(scaled.height * mid)),\n )\n if (tokens <= DEEPSEEK_MAX_IMAGE_TOKENS) {\n low = mid\n best = tokens\n } else {\n high = mid\n }\n }\n return best\n}\n\n/** One token grid's charge: every row carries a separator, plus two framing tokens. */\nfunction deepSeekGridTokens(width: number, height: number): number {\n const cellsWide = cellCount(width)\n const cellsHigh = cellCount(height)\n return cellsHigh * (cellsWide + 1) + 2\n}\n\n/** Token cells along one padded pixel axis. */\nfunction cellCount(length: number): number {\n const patches = Math.ceil(length / DEEPSEEK_PATCH_SIZE)\n return Math.ceil(patches / DEEPSEEK_DOWNSAMPLE_RATIO)\n}\n\n/**\n * The conservative fallback for a family we cannot price exactly: the MOST\n * expensive of the three simple published rules at these dimensions.\n *\n * Chosen deliberately. Under-reporting context is what lets a session walk into\n * its own context window, while over-reporting only makes the meter cautious;\n * for the real families this covers (Qwen's 28-px patches, MiniMax, xAI,\n * moonshot, sakana) the Anthropic rule is the close one, and it is the maximum\n * at every size except the sub-384-px band, where Gemini's flat 258 wins.\n */\nfunction genericImageTokens(width: number, height: number): number {\n return Math.max(\n anthropicImageTokens(width, height),\n openAiImageTokens(width, height),\n googleImageTokens(width, height),\n )\n}\n\n/** Scale one dimension pair by a positive factor, rounded to whole pixels. */\nfunction scaleBy(\n size: { width: number; height: number },\n factor: number,\n): { width: number; height: number } {\n return {\n width: Math.max(1, Math.round(size.width * factor)),\n height: Math.max(1, Math.round(size.height * factor)),\n }\n}\n","/**\n * DeepSeek Harness LLM adapter for the Command Code Provider API.\n *\n * Ported from pi-commandcode-provider@0.5.1 (MIT). This is an unofficial,\n * community-maintained integration; you need your own Command Code account\n * and API key or subscription, and Command Code's terms apply.\n *\n * Wire protocol (reverse-engineered by the pi plugin, command-code@1.28.4;\n * re-verified against command-code@1.54.0 — endpoints, request shape, and\n * stream events unchanged):\n * POST {apiBase}/alpha/generate\n * body: { config, memory, taste, skills, params: { model, messages, tools,\n * system, max_tokens, temperature, stream, reasoning_effort? }, threadId }\n * SSE-ish JSONL events: text-delta | reasoning-start/delta/end | tool-call\n * | tool-result | finish | error\n * Model catalog: GET {apiBase}/provider/v1/models -> { object: 'list', data: [...] }\n *\n * The adapter is deliberately free of cordis/schemastery: it receives a\n * per-request options thunk and an API-key resolver from the plugin entry\n * (src/index.ts), so a settings change reaches the very next request.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\n\nimport type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\nimport {\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n ToolCallId,\n errorChain,\n offloadedImageText,\n resolveRetryPolicy,\n textOnlyImageText,\n type ImageBlock,\n type LlmErrorOptions,\n type LlmImageRequestPrice,\n type LlmImageRequestPricing,\n type ResolvedRetryPolicy,\n type ContentBlock,\n type FinishReason,\n type GenerateOptions,\n type LlmModelInfo,\n type LlmProviderInfo,\n type LlmResolvedModelInfo,\n type Message,\n type StreamChunk,\n type TokenUsage,\n} from '@deepseek-ai/dsh-llm'\n// Namespace import, on purpose: the request-image policy is the ONE part of\n// dsh-llm's surface that changed shape between the supported engines (see\n// `CoreImagePolicy`). Every generation is reached through this object and\n// probed at runtime, because a static named import of an export the installed\n// engine does not have is an ESM link-time failure that takes the whole plugin\n// down — `offloadRequestImagesWithPolicy` was removed in 0.1.6, and\n// `requiredImageOffload`/`projectOffloadedImages` do not exist before it.\nimport * as dshLlm from '@deepseek-ai/dsh-llm'\nimport { RETRY_MAX_DELAY_MS } from './accounts.ts'\nimport { requestImageTarget } from './image-request.ts'\nimport { commandCodeImageTokens } from './image-tokens.ts'\n\nimport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n capabilityDescription,\n compareByPlan,\n modelVisibleInPlan,\n requiresMessagesEndpoint,\n subscriptionPlanInfo,\n type CommandCodeBillingAccess,\n} from './capabilities.ts'\n\n// ---------------------------------------------------------------------------\n// Request / connection defaults (protocol constants). The model/plan/deal\n// capability snapshot lives in ./capabilities.ts — the sync-only surface.\n// ---------------------------------------------------------------------------\nexport const COMMAND_CODE_CLI_VERSION = '1.54.0'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\nexport const DEFAULT_GENERATE_MAX_TOKENS = 64_000\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 65_536\nexport const MODELS_TIMEOUT_MS = 10_000\n/** How long the picker's plan-filter billing facts stay cached before refetching. */\nexport const BILLING_ACCESS_TTL_MS = 5 * 60_000\n/**\n * How long a learned CLI-only protocol preference stays cached per account.\n * After this TTL a request may probe Provider API again, so an upgraded Go\n * account can recover without a restart.\n */\nexport const PROTOCOL_CACHE_TTL_MS = 15 * 60_000\n/** Endpoint protocol selected for one generate call. */\ntype CommandCodeProtocol = 'cli' | 'openai'\n\n/** The entry-plan tier weight (`individual-go` in KNOWN_SUBSCRIPTION_PLANS). */\nconst GO_TIER_WEIGHT = 0\n\n/** Hard cap on account rotations within one request (one attempt per distinct key). */\nconst MAX_ACCOUNT_ROTATIONS = 16\n\n/**\n * Subscription statuses the CLI treats as live (`Mr` in command-code's\n * cli.mjs): the plan gate applies only under one of these.\n */\nconst ACTIVE_SUBSCRIPTION_STATUSES: ReadonlySet<string> = new Set(['active', 'trialing', 'past_due'])\n/** Head-of-request timeout: how long to wait for the first response byte. */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n/** Stream idle timeout: a generation that stalls this long is a dead connection. */\nexport const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000\nconst MODEL_CACHE_VERSION = 1\n\n// ---------------------------------------------------------------------------\n// Small helpers (ported from converters.ts / models.ts)\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\n/**\n * Thinking text carried by an OpenRouter-shaped `reasoning_details` array\n * (`[{ type: 'reasoning.text', text, format, index }]`), concatenated in the\n * order the gateway sent it.\n *\n * Entries are read by their `text` member alone rather than filtered on\n * `type === 'reasoning.text'`: the sibling shapes in that protocol carry\n * `summary` or an encrypted blob instead of `text`, so a plain read already\n * ignores them, while a type filter would silently drop a text-bearing variant\n * added later — and losing thinking is the failure this exists to prevent.\n * Returns undefined when the array yields nothing, so the caller's `??` chain\n * keeps falling through instead of treating \"no text\" as a reasoning delta.\n */\nfunction reasoningDetailsText(value: unknown): string | undefined {\n if (!Array.isArray(value)) return undefined\n let text = ''\n for (const entry of value) {\n if (!isRecord(entry)) continue\n text += stringValue(entry.text) ?? ''\n }\n return text === '' ? undefined : text\n}\n\n/** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */\nfunction periodEndValue(value: unknown): number {\n const asNumber = numberValue(value)\n if (asNumber !== undefined) return asNumber\n const asString = stringValue(value)\n if (asString === undefined) return 0\n const parsed = Date.parse(asString)\n return Number.isNaN(parsed) ? 0 : parsed\n}\n\n/**\n * Terminal stream-error markers from the official CLI (`Xw` in command-code's\n * cli.mjs): these always mean \"retrying cannot succeed\", so the adapter must\n * not classify them as transient server errors.\n */\nconst TERMINAL_STREAM_ERROR_MARKERS = [\n 'premium_credits_exhausted',\n 'model_not_in_plan',\n 'insufficient credits',\n]\n\nfunction hasTerminalStreamMarker(message: string): boolean {\n const lower = message.toLowerCase()\n return TERMINAL_STREAM_ERROR_MARKERS.some((marker) => lower.includes(marker))\n}\n\n/**\n * Context-window wording the provider uses to reject a request that outgrew\n * the model's window. `isContextWindowExceededError` is the harness's own\n * provider-neutral classifier — and the contract `CONTEXT_WINDOW_EXCEEDED`\n * exists for — so it decides; the official CLI's `truncated` pattern adds the\n * phrasings Command Code's upstreams emit that the harness helper does not\n * cover (a bare `prompt is too long`, or a complaint about `max_tokens`).\n * The CLI matches these first and answers them by compacting and retrying —\n * never by resending the request unchanged.\n */\nconst CLI_CONTEXT_OVERFLOW_PATTERN = /prompt is too long|context.*(length|window)|max_tokens|maximum.*tokens/i\n\nfunction isContextOverflowDetail(detail: string): boolean {\n return isContextWindowExceededError(detail) || CLI_CONTEXT_OVERFLOW_PATTERN.test(detail)\n}\n\n/**\n * Classify one in-band stream `error` payload into the failure the caller\n * throws. Shared by both transports — the CLI transport delivers it as an\n * `error` event (`{ type: 'error', error }`), the Provider API transport as a\n * top-level `error` member of an SSE chunk — so the two cannot drift apart.\n *\n * The wording decides before the status does, mirroring the official CLI's\n * `classifyKind` (which reads the message first) and the harness helpers\n * (which exist so thrown and in-band delivery share one classifier). Order is\n * load-bearing:\n *\n * - A context-window rejection is terminal for THIS request but recoverable by\n * the harness: `dsh-compaction-basic` listens on `agent/request-error` for\n * `CONTEXT_WINDOW_EXCEEDED` and answers it with a compaction + retry of the\n * reduced surface. That is what lets a long session survive a request that\n * outgrew the model's window, and it is what the official CLI does (its\n * non-retryable `truncated` kind). Reported as retryable `SERVER` — where\n * this wording landed before — the adapter resent the byte-identical\n * oversized request up to `maxRetries` times and the session could never\n * recover, which is exactly the endless-retry-at-long-context report\n * (issue #39).\n * - Credits/plan wording is terminal, so an exhausted balance or a model\n * outside the plan is not retried as if it were a transient rate limit.\n * - Only then does the status/`isRetryable` pair decide, as before.\n */\nfunction streamErrorToLlmError(value: unknown, fallbackMessage?: string): LlmError {\n const record = isRecord(value) ? value : undefined\n const message = record\n ? (stringValue(record.message) ?? JSON.stringify(record))\n : (stringValue(value) ?? fallbackMessage ?? 'Stream error')\n const statusCode = record === undefined\n ? undefined\n : (numberValue(record.statusCode) ?? numberValue(record.status))\n const isRetryable = record === undefined ? undefined : booleanValue(record.isRetryable)\n // Every available provider code/type/message goes to the classifiers: the\n // wording can live in any of them and both harness helpers document their\n // input as the joined detail.\n const detail = [stringValue(record?.code), stringValue(record?.type), message]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\n const statusOption = statusCode !== undefined ? { status: statusCode } : undefined\n\n if (isContextOverflowDetail(detail)) {\n // Bilingual — the harness renders this message verbatim in its retry\n // chrome — and it names the recovery the harness is already performing.\n return new LlmError(\n `Command Code stream error: ${message}`\n + ';Command Code API 拒绝了这次请求:内容超出模型上下文窗口。正在压缩上下文后重试;如仍失败,请新建会话或减少上下文',\n CONTEXT_WINDOW_EXCEEDED_CODE,\n statusOption,\n )\n }\n const terminal = hasTerminalStreamMarker(detail)\n const retryableStatus = statusCode !== undefined && (statusCode === 429 || statusCode >= 500)\n const retryable = isRetryable === true\n || (statusCode !== undefined ? retryableStatus : (isRetryable !== false && !terminal))\n if (!retryable) {\n return new LlmError(\n `Command Code stream error: ${message}`,\n 'PROVIDER_STREAM_ERROR',\n statusOption,\n )\n }\n return new LlmError(\n `Command Code stream error: ${message}`,\n 'SERVER',\n statusOption,\n )\n}\n\nfunction recordOrEmpty(value: unknown): Record<string, unknown> {\n if (isRecord(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed: unknown = JSON.parse(value)\n if (isRecord(parsed)) return parsed\n } catch {\n // Some providers stream incomplete JSON argument fragments.\n }\n }\n return {}\n}\n\n// ---------------------------------------------------------------------------\n// Tool-schema normalization (issue #35)\n// The gateway validates every function schema's ROOT as an object schema and\n// rejects the whole request otherwise (`schema must be a JSON Schema of\n// type: \"object\", got type: null`). Tool schemas do not always come from\n// the harness's own typed builder, which always declares `type: 'object'`: a\n// third-party plugin or an MCP bridge can register a hand-written schema, and\n// a generator can emit a root `$ref`. Neither is this plugin's to correct, but\n// the request is the plugin's to send, so every schema leaving here is\n// normalized to the object root the provider requires. Only the root is\n// touched, and every path returns a copy: the harness may deep-freeze the\n// caller's schema.\n// ---------------------------------------------------------------------------\n\n/** How deep a root `$ref` / combinator chain is followed while normalizing. */\nconst SCHEMA_NORMALIZE_MAX_DEPTH = 4\n\n/**\n * Whether a type-less node is object-shaped enough to be one with the type\n * declared: `properties`/`required`/`additionalProperties` only make sense on\n * an object, and a schema carrying them was meant to be one.\n */\nfunction isObjectShaped(node: Record<string, unknown>): boolean {\n return (\n isRecord(node.properties) ||\n isRecord(node.patternProperties) ||\n Array.isArray(node.required) ||\n node.additionalProperties !== undefined\n )\n}\n\n/** The `required` names of one schema node, ignoring malformed entries. */\nfunction requiredNames(node: Record<string, unknown>): string[] {\n return Array.isArray(node.required) ? node.required.filter((name): name is string => typeof name === 'string') : []\n}\n\n/** Resolve a local `#/...` pointer inside the schema that carried it. */\nfunction resolveLocalRef(root: Record<string, unknown>, ref: string): Record<string, unknown> | undefined {\n if (!ref.startsWith('#/')) return undefined\n let node: unknown = root\n for (const rawSegment of ref.slice(2).split('/')) {\n const segment = rawSegment.replace(/~1/g, '/').replace(/~0/g, '~')\n if (!isRecord(node)) return undefined\n node = node[segment]\n }\n return isRecord(node) ? node : undefined\n}\n\n/**\n * Flatten a type-less combinator node into one object schema, so the model\n * still sees the branch fields instead of an argument-free tool. `allOf`\n * branches must all hold, so their `required` entries are all kept; `anyOf` /\n * `oneOf` branches are alternatives, so only a name required by every branch\n * survives. Returns undefined when no branch describes an object.\n */\nfunction mergeCombinatorBranches(\n node: Record<string, unknown>,\n depth: number,\n): Record<string, unknown> | undefined {\n // A plugin can hand over a self-referential schema object; the bound keeps\n // the walk finite (JSON-parsed schemas are acyclic, JS ones need not be).\n if (depth >= SCHEMA_NORMALIZE_MAX_DEPTH) return undefined\n const properties: Record<string, unknown> = {}\n const required = new Set<string>()\n const alternatives: string[][] = []\n let sawBranch = false\n\n for (const key of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = node[key]\n if (!Array.isArray(branches)) continue\n const objectBranches: Record<string, unknown>[] = []\n for (const branch of branches) {\n if (!isRecord(branch)) continue\n objectBranches.push(toolParametersSchema(branch, depth + 1))\n }\n if (objectBranches.length === 0) continue\n sawBranch = true\n // An `anyOf`/`oneOf` group contributes the intersection of its branches;\n // an `allOf` group contributes the union.\n const names = objectBranches.map(requiredNames)\n if (key === 'allOf') for (const name of names.flat()) required.add(name)\n else if (names.length > 0) {\n alternatives.push(names[0]!.filter((name) => names.every((list) => list.includes(name))))\n }\n for (const branch of objectBranches) {\n const branchProperties = isRecord(branch.properties) ? branch.properties : {}\n for (const [name, schema] of Object.entries(branchProperties)) {\n if (!(name in properties)) properties[name] = schema\n }\n }\n }\n if (!sawBranch) return undefined\n // A name must satisfy every group, so each group's intersection joins the\n // union: an allOf-required field and an anyOf-common field are both required.\n for (const group of alternatives) for (const name of group) required.add(name)\n\n const merged: Record<string, unknown> = { type: 'object', properties }\n if (required.size > 0) merged.required = [...required]\n // The merged schema is a superset of the alternatives it replaced, so it\n // stays open unless the node itself closed it.\n if (node.additionalProperties !== undefined) merged.additionalProperties = node.additionalProperties\n for (const key of ['description', 'title'] as const) {\n if (node[key] !== undefined) merged[key] = node[key]\n }\n return merged\n}\n\n/**\n * Normalize one tool's parameters schema to an object-rooted JSON Schema.\n * A schema that already declares an object root is passed through untouched;\n * a type-less object-shaped one gains the type; a root `$ref` or combinator is\n * resolved/merged; anything else (an array/scalar root, or no schema at all)\n * degrades to a permissive free-form object, because a request the provider\n * refuses helps no one and the tool's own description is still in the prompt.\n */\nfunction toolParametersSchema(parameters: unknown, depth = 0): Record<string, unknown> {\n if (!isRecord(parameters)) return { type: 'object', properties: {}, additionalProperties: true }\n if (parameters.type === 'object') return parameters\n // `[\"object\", \"null\"]` is accepted by JSON Schema but not by the provider's\n // validator, which compares the root `type` against the string \"object\".\n if (Array.isArray(parameters.type) && parameters.type.includes('object')) {\n return { ...parameters, type: 'object' }\n }\n\n if (parameters.type === undefined || parameters.type === null) {\n if (typeof parameters.$ref === 'string' && depth < SCHEMA_NORMALIZE_MAX_DEPTH) {\n const target = resolveLocalRef(parameters, parameters.$ref)\n if (target !== undefined) {\n const { $ref: _ref, ...rest } = parameters\n return toolParametersSchema({ ...target, ...rest }, depth + 1)\n }\n }\n if (isObjectShaped(parameters)) return { ...parameters, type: 'object' }\n const merged = mergeCombinatorBranches(parameters, depth)\n if (merged !== undefined) return merged\n // A root `$ref` this plugin cannot resolve still gets the declared type:\n // that is what the provider validates for, and an object is what every\n // schema generator emits one for.\n if (typeof parameters.$ref === 'string') return { ...parameters, type: 'object' }\n }\n\n return { type: 'object', properties: {}, additionalProperties: true }\n}\n\nexport function projectSlugFromPath(pathName: string): string {\n const slug = pathName\n .toLowerCase()\n .replace(/^[a-z]:/i, '')\n .replace(/[^a-z0-9]+/g, '-')\n // Trim leading/trailing separators. This must stay linear: the classic\n // `/^-+|-+$/` form is ambiguous — on `a<200k dashes>b` the unanchored\n // `-+$` retries every start position, giving O(n^2) matching (CodeQL\n // js/polynomial-redos). The negative lookbehind `(?<!-)` restricts `-+$`\n // to the first dash of the trailing run, so only one start position is\n // tried. Verified empirically: ~14.5s -> ~0ms on a 200k-dash input.\n .replace(/^-+|(?<!-)-+$/g, '')\n return slug || 'project'\n}\n\nfunction parseStreamEventLine(line: string): unknown | undefined {\n let trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(':') || trimmed.startsWith('event:')) return undefined\n if (trimmed.startsWith('data:')) trimmed = trimmed.slice(5).trim()\n if (!trimmed || trimmed === '[DONE]') return undefined\n try {\n return JSON.parse(trimmed) as unknown\n } catch {\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential fallback from the official Command Code CLI auth file. Used as\n// the last fallback by the plugin entry, so a user who already logged in with\n// `command-code login` can reuse that credential. Only the official CLI's own\n// file is read — pi/OMP auth files are intentionally not scanned, so their\n// credentials and formats cannot surprise this adapter.\n// ---------------------------------------------------------------------------\n\n/** Extract the key from the CLI's nested credential records (`command-code`). */\nfunction apiKeyFromCredentialRecord(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined\n const type = stringValue(value.type)\n if (type === 'api') return stringValue(value.key)\n if (type === 'oauth') return stringValue(value.access)\n return stringValue(value.key) ?? stringValue(value.access)\n}\n\n/** Read a usable Command Code credential from the official CLI auth file. */\nexport function resolveAuthFileApiKey(): string | undefined {\n const authPath = join(homedir(), '.commandcode', 'auth.json')\n try {\n if (!existsSync(authPath)) return undefined\n const parsed: unknown = JSON.parse(readFileSync(authPath, 'utf-8'))\n if (!isRecord(parsed)) return undefined\n const direct = stringValue(parsed.apiKey) ?? stringValue(parsed.commandcode)\n if (direct) return direct\n const nested =\n apiKeyFromCredentialRecord(parsed.commandcode) ??\n apiKeyFromCredentialRecord(parsed['command-code'])\n return nested\n } catch {\n // Ignore malformed or unreadable auth file.\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog discovery with on-disk cache fallback (ported from models.ts)\n// ---------------------------------------------------------------------------\n\ninterface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n}\n\nfunction parseCatalogResponse(value: unknown): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) {\n throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n }\n const models: CommandCodeModel[] = []\n for (const entry of value.data) {\n if (!isRecord(entry)) continue\n const id = stringValue(entry.id)\n const name = stringValue(entry.name)\n const contextLength = numberValue(entry.context_length)\n if (!id || !name || !contextLength || contextLength <= 0) continue\n models.push({\n id,\n name,\n contextWindow: contextLength,\n maxTokens: Math.min(contextLength, DEFAULT_MAX_OUTPUT_TOKENS),\n })\n }\n if (models.length === 0) {\n throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n }\n return models\n}\n\nasync function readModelsCache(cachePath: string): Promise<CommandCodeModel[]> {\n const parsed: unknown = JSON.parse(await readFile(cachePath, 'utf-8'))\n if (!isRecord(parsed) || parsed.version !== MODEL_CACHE_VERSION || !Array.isArray(parsed.models)) {\n throw new Error(`Invalid model cache at ${cachePath}`)\n }\n return parsed.models as CommandCodeModel[]\n}\n\nasync function writeModelsCache(cachePath: string, models: CommandCodeModel[]): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true })\n const tmp = `${cachePath}.${process.pid}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, models }, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600,\n })\n await rename(tmp, cachePath)\n } finally {\n await rm(tmp, { force: true }).catch(() => undefined)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Message conversion: harness Message[] -> Command Code wire messages.\n// Both transports replay historical reasoning. The CLI transport carries it as\n// a `reasoning` block inside the assistant message (the shape the official\n// CLI's `toWireMessages` emits), the Provider API transport as the\n// `reasoning_content` field, because DeepSeek's thinking-mode contract\n// requires the previous chain of thought to be passed back whenever tool calls\n// are in play (issue #34). Only tool calls with a paired tool result are\n// replayed on both transports.\n// ---------------------------------------------------------------------------\n\n/**\n * Whether an inbound message is a tool RESULT — a `user`-role message the\n * producer tagged with `source: { kind: 'tool' }`.\n *\n * The tag is read defensively because it is PRODUCER-supplied and nothing\n * validates it: dsh-llm's `Message` type declares `source` required, but the\n * runtime never checks it and every adapter shipped before this one ignored the\n * field outright (`dsh-llm-deepseek` never reads it). A third-party plugin that\n * assembles its own history can therefore omit it and run correctly everywhere\n * else — dsh-mneme's memory pipeline did — which made this adapter, the first\n * to actually read the field, the first to crash on such a message with\n * `TypeError: Cannot read properties of undefined (reading 'kind')` in the\n * serialization phase, 0–8 ms in, before any request left the machine and with\n * nothing in the error naming the message or the producer (issue #47).\n *\n * Two rules keep an untagged message from costing the turn:\n *\n * - A PRESENT tag is authoritative. `kind: 'user'`, `'model'`, `'plugin'` or\n * any producer-added kind means \"not a tool result\", whatever the content\n * looks like — the tag answers *who produced this*.\n * - An ABSENT tag falls back to the content shape. A `user` message whose\n * first block is a `tool-result` is a tool result by the harness's own\n * definition (`ToolResultMessage` is exactly that shape with a\n * `ToolMessageSource`), and the fallback is not cosmetic: `pairedToolCalls()`\n * counts a `tool-result` block from ANY message, so classifying such a\n * message as a plain user message would drop it at emission while its call\n * still counted as paired — leaving the assistant's tool call unanswered on\n * the wire, which the gateway rejects outright. FIRST block, not \"any block\":\n * the tool-result branch reads `content[0]` and skips anything else, so\n * claiming a mixed message as a tool result would discard its other blocks\n * instead of sending them.\n */\nfunction isToolResultMessage(message: Message): boolean {\n if (message.role !== 'user') return false\n const kind: string | undefined = message.source?.kind\n if (kind !== undefined) return kind === 'tool'\n return message.content?.[0]?.type === 'tool-result'\n}\n\n/**\n * Collect the tool calls that have a paired tool result, plus each call's\n * name. The name map feeds the `toolName` of replayed tool results: some\n * backends (e.g. Google Gemini `functionResponse`) reject a result whose\n * function name is empty, so the real name must round-trip (the official\n * CLI does the same via its `tool_use_id -> toolName` map).\n */\nfunction pairedToolCalls(messages: readonly Message[]): {\n ids: Set<string>\n names: Map<string, string>\n} {\n const callIds = new Set<string>()\n const names = new Map<string, string>()\n const resultIds = new Set<string>()\n for (const message of messages) {\n for (const block of message.content) {\n if (message.role === 'assistant' && block.type === 'tool-call') {\n callIds.add(block.id)\n names.set(block.id, block.name)\n }\n if (block.type === 'tool-result') resultIds.add(block.toolCallId)\n }\n }\n return { ids: new Set([...callIds].filter((id) => resultIds.has(id))), names }\n}\n\n/**\n * The Command Code gateway rejects tool call ids longer than 64 characters\n * (`input[N].call_id` must be `<= 64`, issue #23). Cross-provider histories\n * can carry longer ids — e.g. switching to Command Code mid-session after\n * another provider issued the call — so overlong paired ids are remapped to\n * short per-request aliases. Correlation only needs to hold within one\n * request (each call travels with its result in the same body), so a\n * sequential alias is enough: no durable state, no cross-request stability,\n * and the harness log keeps the original ids.\n */\nconst MAX_WIRE_TOOL_CALL_ID_LENGTH = 64\n\n/**\n * Map each paired tool-call id to its wire id: ids within the gateway limit\n * pass through verbatim, overlong ids get a collision-free `cc-<n>` alias.\n * Callers must resolve BOTH the tool-call and its paired tool-result through\n * the returned map so the pair stays correlated.\n */\nfunction wireToolCallIds(paired: ReadonlySet<string>): Map<string, string> {\n const wire = new Map<string, string>()\n const taken = new Set<string>()\n for (const id of paired) {\n if (id.length <= MAX_WIRE_TOOL_CALL_ID_LENGTH) {\n wire.set(id, id)\n taken.add(id)\n }\n }\n let seq = 1\n for (const id of paired) {\n if (wire.has(id)) continue\n let alias = `cc-${seq++}`\n while (taken.has(alias)) alias = `cc-${seq++}`\n wire.set(id, alias)\n taken.add(alias)\n }\n return wire\n}\n\nfunction blockText(block: ContentBlock): string {\n return block.type === 'text' || block.type === 'reasoning' ? block.text : ''\n}\n\n/**\n * One paired tool result as the wire needs it: its text and the images the\n * tool returned. Neither wire transport can carry an image inside a tool\n * result (`/provider/v1/chat/completions` forbids non-text `role: 'tool'`\n * content, and the CLI transport's own `tool-result` output is text-only), so\n * those images travel in a user message emitted right after the tool message —\n * the same shape `@deepseek-ai/dsh-llm-deepseek` uses (issue #30).\n */\ninterface ToolResultMedia {\n /** Visible result text; `''` when the result carried images but no text. */\n text: string\n /** Nested image references, in block order, deduplicated by attachment id. */\n images: ImageAttachmentRef[]\n}\n\n/**\n * Collect text and nested images of one tool result. The harness `read_image`\n * tool returns both, so dropping the image half is what made a tool-read image\n * invisible to a Vision model (issue #30). Deduplication keeps a result that\n * repeats one attachment from paying for the same pixels twice.\n */\nfunction toolResultMedia(block: Extract<ContentBlock, { type: 'tool-result' }>): ToolResultMedia {\n const chunks: string[] = []\n const images: ImageAttachmentRef[] = []\n const seen = new Set<string>()\n const walk = (blocks: readonly ContentBlock[]): void => {\n for (const nested of blocks) {\n if (nested.type === 'text' || nested.type === 'reasoning') {\n if (nested.text) chunks.push(nested.text)\n continue\n }\n if (nested.type === 'image') {\n if (!seen.has(nested.attachment.attachmentId)) {\n seen.add(nested.attachment.attachmentId)\n images.push(nested.attachment)\n }\n continue\n }\n if (nested.type === 'tool-result') walk(nested.content)\n }\n }\n walk(block.content)\n return { text: chunks.join('\\n'), images }\n}\n\n/**\n * Result text for the wire's `role: 'tool'` message. A tool that returned only\n * an image (and possibly a nested image-only tool result) has no text at all,\n * and neither transport accepts an empty tool content string, so it gets a\n * descriptor pointing at the user message that follows with the pixels.\n */\nfunction toolResultTextForWire(media: ToolResultMedia): string {\n return media.text || (media.images.length > 0 ? '(image returned; see the attached image)' : '')\n}\n\n/** Leading line of the user message that carries a tool result's images. */\nconst TOOL_RESULT_IMAGE_TEXT = 'Attached image(s) from tool result'\n\n/**\n * The model-visible note introducing the images carried out of one tool\n * result. Neither transport merges them back into the tool result, so this\n * line is what tells the model the image it is about to see belongs to the\n * tool it just ran rather than to the user; it also leads the part list,\n * because an image-first content array is what some gateways reject.\n *\n * The note names the tool call the image came out of, because a turn's\n * carriers are emitted as a group after the whole tool group (issue #33):\n * position alone would have to carry the association, and every `read_image`\n * result renders the same envelope text, so two parallel calls would produce\n * two identical notes. The id is the WIRE id — the one the model saw on the\n * `tool-call` it issued and on the tool message just above — so an overlong\n * cross-provider id is named by the alias that replaced it, not by the\n * harness-side id the model never saw.\n *\n * Count and pixel dimensions are appended when the tool's own text does not\n * already state them (a result that returns the image and nothing else).\n */\nfunction toolResultImageNote(media: ToolResultMedia, toolCallId: string): string {\n const lead = `${TOOL_RESULT_IMAGE_TEXT} (${toolCallId}):`\n const first = media.images[0]\n if (first === undefined) return lead\n const dimensions = `${first.width}x${first.height} px`\n if (first.width <= 0 || first.height <= 0 || media.text.includes(dimensions)) {\n return lead\n }\n const count = media.images.length > 1 ? `${media.images.length} images, ` : ''\n return `${lead} ${count}${dimensions}`\n}\n\nfunction hasImageContent(message: Message): boolean {\n const check = (blocks: readonly ContentBlock[]): boolean =>\n blocks.some(\n (b) => b.type === 'image' || (b.type === 'tool-result' && check(b.content)),\n )\n return check(message.content)\n}\n\n// ---------------------------------------------------------------------------\n// Request image budget (issue #37)\n//\n// Both transports inline EVERY historical image as base64, so a long session\n// — a vision self-check loop reading back dozens of screenshots — keeps\n// growing the body until it crosses the gateway's request cap (measured at\n// ~50.17 MB, undocumented). From that point on every request on this route\n// fails with HTTP 413 for the rest of the session, because history is never\n// reclaimed, even though the same conversation works on another provider.\n//\n// The budget, the two rungs, and the byte accounting below are unchanged. What\n// changed is WHO performs the eviction, because the harness moved it from the\n// adapter to the session surface (issue #43):\n//\n// ≤ 0.1.5 — the adapter projects its own history with\n// `offloadRequestImagesWithPolicy`: the oldest images beyond the\n// budget become placeholder text for THIS request only. The\n// harness never learns that they were omitted.\n// ≥ 0.1.6 — the offload set is a DURABLE surface fact. The adapter renders\n// the surface's `offloaded` marks with `projectOffloadedImages`,\n// and when the history still exceeds the budget it does NOT evict:\n// it fails with `IMAGE_OFFLOAD_REQUIRED` + `offloadImages`, which\n// the default `dsh-compaction-image-offload` plugin turns into one\n// `image/offload` session event and a retry. Every later request on\n// the session then carries the same placeholder text, across\n// restore and fork, and the token meter stops counting the evicted\n// images as context.\n//\n// Both halves are reached through the `dshLlm` namespace and picked at runtime,\n// so one build serves both engine generations. The budget is accounted in the\n// encoded form, because it is the base64 the wire actually carries that has to\n// fit. Nothing anywhere may statically import either generation's helper names.\n// ---------------------------------------------------------------------------\n\n/**\n * Primary image budget for one request body. 32 MiB of base64 images leaves a\n * wide margin under the measured ~50 MB cap for text, tool schemas, and JSON\n * overhead, and the 16 MiB byte quantum means one eviction frees a real block\n * of the budget instead of one image per request.\n */\nconst REQUEST_IMAGE_MAX_BASE64_BYTES = 32 * 1024 * 1024\n/** Primary image-count budget; a long screenshot loop stays well under it. */\nconst REQUEST_IMAGE_MAX_COUNT = 60\n/** Byte step one eviction removes; keeps the removed prefix stable per request. */\nconst REQUEST_IMAGE_BYTE_QUANTUM = 16 * 1024 * 1024\n/** Count step one eviction removes, so the prefix does not creep per request. */\nconst REQUEST_IMAGE_COUNT_QUANTUM = 30\n\n/**\n * The retry rung, used only after the gateway actually answered 413. The cap\n * covers text and tool bytes too, so it cannot be budgeted exactly from here;\n * this rung is aggressive on purpose — the alternative to a smaller request is\n * a session that cannot continue at all.\n */\nconst REQUEST_IMAGE_RETRY_MAX_BASE64_BYTES = 8 * 1024 * 1024\nconst REQUEST_IMAGE_RETRY_MAX_COUNT = 12\nconst REQUEST_IMAGE_RETRY_BYTE_QUANTUM = 8 * 1024 * 1024\nconst REQUEST_IMAGE_RETRY_COUNT_QUANTUM = 12\n\n/** One rung of the image budget ladder: what a request may keep, and in what steps. */\ninterface RequestImageBudget {\n maxBytes: number\n maxImages: number\n byteQuantum: number\n countQuantum: number\n}\n\n/** The budget ladder: the primary rung first, the 413 eviction rung second. */\nconst REQUEST_IMAGE_BUDGETS: readonly RequestImageBudget[] = [\n {\n maxBytes: REQUEST_IMAGE_MAX_BASE64_BYTES,\n maxImages: REQUEST_IMAGE_MAX_COUNT,\n byteQuantum: REQUEST_IMAGE_BYTE_QUANTUM,\n countQuantum: REQUEST_IMAGE_COUNT_QUANTUM,\n },\n {\n maxBytes: REQUEST_IMAGE_RETRY_MAX_BASE64_BYTES,\n maxImages: REQUEST_IMAGE_RETRY_MAX_COUNT,\n byteQuantum: REQUEST_IMAGE_RETRY_BYTE_QUANTUM,\n countQuantum: REQUEST_IMAGE_RETRY_COUNT_QUANTUM,\n },\n]\n\n/**\n * Project request history under one image budget (≤0.1.5 engines only): the\n * oldest images past it become placeholder text in place, the newest keep their\n * bytes, and a history already inside the budget is returned as the SAME array\n * — the caller uses that identity to tell \"nothing evicted\" from \"evicted\".\n *\n * Nested tool-result images ride the same core walk, which is exactly right\n * for this adapter: an evicted `read_image` result surfaces its placeholder as\n * the tool message's own text, so no carrier user message is emitted for it.\n */\nfunction projectRequestImages(\n messages: readonly Message[],\n budget: RequestImageBudget,\n policy: CoreImagePolicy,\n): readonly Message[] {\n const offload = policy.offloadRequestImagesWithPolicy\n // Unreachable while `surfaceImagePolicy` gates this branch; kept so a future\n // engine that drops BOTH shapes surfaces as \"no budget\" rather than a\n // TypeError from calling undefined.\n if (typeof offload !== 'function') return messages\n return offload(messages, {\n representation: 'base64',\n maxBytes: budget.maxBytes,\n maxImages: budget.maxImages,\n byteQuantum: budget.byteQuantum,\n countQuantum: budget.countQuantum,\n // No execution-world path is resolvable from the adapter (it holds no\n // filesystem provider), so the placeholder carries attachment identity and\n // the re-attach advice, which is what the core helper emits for that case.\n placeholder: (ref: ImageAttachmentRef) => offloadedImageText(ref),\n })\n}\n\n/**\n * The request options one budget produced: the caller's own object when the\n * history was already inside the budget, else a copy carrying the projection.\n * The next rung of the ladder is applied to the CURRENT projection, never to\n * the raw history — otherwise a retry could reintroduce images the first rung\n * had already evicted.\n */\nfunction withImageBudget(\n options: GenerateOptions,\n budget: RequestImageBudget,\n policy: CoreImagePolicy,\n): GenerateOptions {\n const projected = projectRequestImages(options.messages, budget, policy)\n return projected === options.messages ? options : { ...options, messages: [...projected] }\n}\n\n// ---------------------------------------------------------------------------\n// The ≥0.1.6 durable-offload contract\n// ---------------------------------------------------------------------------\n\n/**\n * Stable provider-neutral code for \"a request still carries more images than\n * this route will send; offload N of them and retry\". Declared locally rather\n * than imported: the constant does not exist on the 0.1.2–0.1.5 peers this\n * plugin still supports, and importing it statically is the link-time failure\n * described above the budget constants.\n */\nconst IMAGE_OFFLOAD_REQUIRED_CODE = 'IMAGE_OFFLOAD_REQUIRED'\n\n/** One occurrence's exact request-version byte length, as the core counter wants it. */\ntype ImageVersionBytes = (block: { attachment: ImageAttachmentRef }) => number\n\n/**\n * The installed engine's request-image policy, whichever generation it is.\n *\n * Every member is optional because the two generations never coexist: a\n * ≤0.1.5 engine has only `offloadRequestImagesWithPolicy`, a ≥0.1.6 engine has\n * only the other two. `CORE_IMAGE_POLICY` is the namespace object viewed\n * through this shape, and `surfaceImagePolicy()` is the ONE place that decides\n * which contract this process speaks.\n */\nexport interface CoreImagePolicy {\n /** ≤0.1.5: project history under a byte/count budget, adapter-owned and transient. */\n offloadRequestImagesWithPolicy?: (\n messages: readonly Message[],\n policy: Record<string, unknown>,\n ) => readonly Message[]\n /** ≥0.1.6: render the surface's durable offload marks as placeholder text. */\n projectOffloadedImages?: (\n messages: readonly Message[],\n placeholder: (ref: ImageAttachmentRef) => string,\n ) => readonly Message[]\n /** ≥0.1.6: how many more leading retained occurrences must be offloaded. */\n requiredImageOffload?: (\n messages: readonly Message[],\n budget: Record<string, unknown>,\n versionBytes: ImageVersionBytes,\n ) => number\n}\n\n/** The installed engine's image policy; see {@link CoreImagePolicy}. */\nconst CORE_IMAGE_POLICY = dshLlm as unknown as CoreImagePolicy\n\n/** The ≥0.1.6 half, once both members are known to be functions. */\ninterface SurfaceImagePolicy {\n projectOffloadedImages: NonNullable<CoreImagePolicy['projectOffloadedImages']>\n requiredImageOffload: NonNullable<CoreImagePolicy['requiredImageOffload']>\n}\n\n/**\n * The durable-offload contract this engine speaks, or undefined on ≤0.1.5.\n *\n * Both members are required together: a half-populated engine would either\n * lose the surface's marks (re-sending evicted images as pixels) or lose the\n * count (silently sending an over-budget body), and neither is worth a partial\n * opt-in. Absent, the adapter keeps its own transient projection instead.\n */\nexport function surfaceImagePolicy(api: CoreImagePolicy = CORE_IMAGE_POLICY): SurfaceImagePolicy | undefined {\n return typeof api.projectOffloadedImages === 'function' && typeof api.requiredImageOffload === 'function'\n ? { projectOffloadedImages: api.projectOffloadedImages, requiredImageOffload: api.requiredImageOffload }\n : undefined\n}\n\n/**\n * The failure a route raises instead of evicting on its own (≥0.1.6). The\n * count is the ONE thing the harness needs: `dsh-compaction-image-offload`\n * records it as an `image/offload` event, marks that many oldest retained\n * occurrences, and retries the step.\n *\n * Deliberately outside `providerRetryPolicy()`'s whitelist: a byte-identical\n * resend cannot succeed, so the retry belongs to the surface mutation, not to\n * dsh-llm-retry. On a profile that does not mount that plugin the failure is\n * terminal — every shipped profile reaches it through dsh-base.\n */\nfunction imageOffloadRequired(missing: number): LlmError {\n const options: LlmErrorOptions & { offloadImages: number } = { offloadImages: missing }\n return new LlmError(\n `commandcode request images exceed the route budget; ${missing} more oldest occurrence(s) must be offloaded.`,\n IMAGE_OFFLOAD_REQUIRED_CODE,\n options,\n )\n}\n\n/** The budget in the shape the core counter takes (representation + the rung). */\nfunction coreBudget(budget: RequestImageBudget): Record<string, unknown> {\n return { representation: 'base64', ...budget }\n}\n\n/**\n * Exact request-version bytes of one retained occurrence. The declared\n * normalized size IS what this adapter inlines (the body is built from\n * `attachments.readImage`, base64-encoded), so the accounting matches the wire\n * byte for byte, and the core helper expands it for `base64` on its own.\n */\nconst imageVersionBytes: ImageVersionBytes = (block) => block.attachment.bytes\n\n/**\n * ≥0.1.6 request options: the surface's durable marks become placeholder text,\n * and an over-budget history FAILS with the count to offload instead of being\n * evicted here. Throws rather than returning, so no caller can accidentally\n * send a body this route already knows is too large.\n */\nfunction withSurfaceOffload(\n options: GenerateOptions,\n policy: SurfaceImagePolicy,\n budget: RequestImageBudget,\n): GenerateOptions {\n const marked = policy.projectOffloadedImages(options.messages, (ref) => offloadedImageText(ref))\n const messages = marked === options.messages ? options.messages : [...marked]\n const missing = policy.requiredImageOffload(messages, coreBudget(budget), imageVersionBytes)\n if (missing > 0) throw imageOffloadRequired(missing)\n return messages === options.messages ? options : { ...options, messages }\n}\n\n/**\n * One image's bytes for the wire: the attachment service's REQUEST VERSION when\n * it can produce one, else the normalized original.\n *\n * `readImage()` answers the stored original, which is what admission accepted —\n * not what a provider request should carry. `readImageRequest()` re-encodes to\n * the route target in `./image-request.ts` and caches the result under it, so\n * the same attachment costs one encode per target instead of one per occurrence,\n * and the base64 the wire expands is bounded (both the pixel budget and, more to\n * the point here, the encoded bytes). The fallback is for a backend that does\n * not implement the abstract method; every engine this plugin declares support\n * for does.\n */\nasync function readRequestImage(\n attachments: AttachmentStore,\n ref: ImageAttachmentRef,\n): Promise<Uint8Array> {\n if (typeof attachments.readImageRequest === 'function') {\n return (await attachments.readImageRequest(ref, requestImageTarget(ref))).data\n }\n return (await attachments.readImage(ref)).data\n}\n\n/**\n * One occurrence as the token meter hands it over, in either generation's\n * shape: a bare reference (≤0.1.5) or an image block that may also be marked\n * `offloaded` (≥0.1.6).\n */\ntype PricedOccurrence = ImageAttachmentRef | ImageBlock\n\n/**\n * Price one request occurrence.\n *\n * Two cases cost no vision tokens at all, and both are priced as their\n * model-visible TEXT so the caller's estimator can charge that instead: a model\n * that accepts text only (the harness projects those images to placeholder text\n * before the request), and an occurrence the session surface has already\n * offloaded (≥0.1.6 renders the same placeholder text in every later request).\n * A retained occurrence on this route contributes no text at all — the pixels\n * are inlined — so its price is the family's visual-token count and nothing else.\n */\nfunction priceRequestImage(\n occurrence: PricedOccurrence,\n model: string,\n imageCapable: boolean,\n): LlmImageRequestPrice {\n const block = occurrence as { attachment?: ImageAttachmentRef; offloaded?: true }\n const ref = block.attachment ?? (occurrence as ImageAttachmentRef)\n if (!imageCapable) return { visualTokens: 0, text: textOnlyImageText(ref) }\n if (block.offloaded === true) return { visualTokens: 0, text: offloadedImageText(ref) }\n const target = requestImageTarget(ref)\n return { visualTokens: commandCodeImageTokens(model, target.width, target.height), text: '' }\n}\n\n/**\n * Convert one image reference to the Command Code wire format, as the official\n * CLI does: `{ type: 'image', source: { type: 'base64', media_type, data } }`.\n * Bytes come from the durable attachment service; the media type is the one\n * verified at save time.\n */\nasync function imageToCommandCode(\n ref: ImageAttachmentRef,\n readImage: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<{ type: 'image'; source: { type: 'base64'; media_type: string; data: string } }> {\n const data = await readImage(ref)\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: ref.mediaType,\n data: Buffer.from(data).toString('base64'),\n },\n }\n}\n\nasync function messagesToCC(\n messages: readonly Message[],\n readImage?: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired, names: toolNames } = pairedToolCalls(messages)\n // Remap cross-provider ids the gateway would reject (issue #23); the\n // result side resolves through the same map so each pair stays correlated.\n const wireIds = wireToolCallIds(paired)\n\n // Tool-returned images ride as user messages after their tool result. The\n // harness can emit several tool calls in one assistant turn, and the\n // gateway expects an assistant's tool blocks to be answered consecutively:\n // a user message interleaved between tool results breaks the pairing and\n // the request is rejected. So image carriers are buffered and flushed only\n // once the whole tool group (or the next non-tool message) has been emitted.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n\n for (const message of messages) {\n if (message.role === 'system') continue // folded into params.system by the caller\n\n if (message.role === 'user' && !isToolResultMessage(message)) {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n // The caller (stream) has already gated image input on model\n // capability and attachment-service availability, so reaching this\n // branch with no resolver is an internal contract violation.\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n parts.push(await imageToCommandCode(block.attachment, readImage))\n }\n }\n // A user message that converted to nothing carries no information, and\n // an empty content array is a needless gateway-compat risk, so it is\n // dropped — the same rule the Provider API converter applies below.\n // (`dsh-llm-deepseek` instead pushes `content: ''`; skipping is the\n // safer half of that divergence to keep.) The flush above has already\n // run, so a pending image carrier is never dropped with it.\n if (parts.length === 0) continue\n out.push({ role: 'user', content: parts })\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n } else if (block.type === 'reasoning') {\n // Replay the thinking block, exactly as the official CLI's\n // `toWireMessages` does (command-code@1.54.0: a `thinking` block\n // becomes `{ type: 'reasoning', text }`). This is not optional\n // politeness: the gateway rebuilds the provider request from these\n // blocks, and a DeepSeek thinking-mode assistant turn whose tool\n // calls arrive without its reasoning is rejected with \"The\n // `reasoning_content` in the thinking mode must be passed back to\n // the API\" — which failed every tool-loop turn (issue #34).\n parts.push({ type: 'reasoning', text: block.text })\n } else if (block.type === 'tool-call' && paired.has(block.id)) {\n parts.push({\n type: 'tool-call',\n toolCallId: wireIds.get(block.id) ?? block.id,\n toolName: block.name,\n input: recordOrEmpty(block.arguments),\n })\n }\n }\n if (parts.length > 0) out.push({ role: 'assistant', content: parts })\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (isToolResultMessage(message)) {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n const media = toolResultMedia(block)\n // Resolved once: the tool message and the carrier note below must name\n // the same call, or the model cannot tie an image back to its result.\n const wireToolCallId = wireIds.get(block.toolCallId) ?? block.toolCallId\n out.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: wireToolCallId,\n // `paired` guarantees a call with this id exists, so the map\n // always hits; `|| 'unknown'` also guards an empty call name\n // (matches the official CLI's `?? \"unknown\"` fallback).\n toolName: toolNames.get(block.toolCallId) || 'unknown',\n output: block.isError\n ? { type: 'error-text', value: toolResultTextForWire(media) }\n : { type: 'text', value: toolResultTextForWire(media) },\n },\n ],\n })\n // Images a tool returned (e.g. `read_image`) cannot ride inside the\n // tool result on this wire, so they follow it as a user message —\n // otherwise a Vision model receives the metadata text and no pixels.\n if (media.images.length > 0) {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireToolCallId) }]\n for (const attachment of media.images) {\n carried.push(await imageToCommandCode(attachment, readImage))\n }\n pendingImages.push({ role: 'user', content: carried })\n }\n }\n }\n flushPendingImages()\n return out\n}\n\n/**\n * Convert one image reference to the OpenAI Chat Completions wire format:\n * `{ type: 'image_url', image_url: { url: 'data:...;base64,...' } }`.\n */\nasync function imageToOpenAI(\n ref: ImageAttachmentRef,\n readImage: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<{ type: 'image_url'; image_url: { url: string } }> {\n const data = await readImage(ref)\n return {\n type: 'image_url',\n image_url: {\n url: `data:${ref.mediaType};base64,${Buffer.from(data).toString('base64')}`,\n },\n }\n}\n\n/**\n * Convert harness messages to the OpenAI Chat Completions request shape.\n *\n * Unlike the Command Code CLI transport, this transport is the documented\n * Provider API surface. DeepSeek's thinking-mode contract requires historical\n * `reasoning_content` to be passed back whenever tools are in play, so this\n * converter intentionally DOES replay reasoning blocks as `reasoning_content`\n * on assistant messages. Only tool calls with a paired tool result are\n * replayed (same policy as the CLI path).\n */\nasync function messagesToOpenAI(\n messages: readonly Message[],\n readImage?: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired } = pairedToolCalls(messages)\n // Same overlong-id remap as the CLI transport (issue #23): OpenAI\n // `tool_call_id` fields accept longer values, but the remap keeps both\n // transports consistent and correlation only needs to hold per request.\n const wireIds = wireToolCallIds(paired)\n\n // Tool-returned images ride as user messages after their tool result. The\n // harness can emit several tool calls in one assistant turn, and the\n // gateway expects an assistant's tool blocks to be answered consecutively:\n // a user message interleaved between tool results breaks the pairing and\n // the request is rejected. So image carriers are buffered and flushed only\n // once the whole tool group (or the next non-tool message) has been emitted.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n\n for (const message of messages) {\n // System messages are folded into the single top-level system message by\n // the caller, matching the existing adapter's conversation folding.\n if (message.role === 'system') continue\n\n if (message.role === 'user' && !isToolResultMessage(message)) {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n parts.push(await imageToOpenAI(block.attachment, readImage))\n }\n }\n // Same rule as the CLI converter: a converted-to-nothing user message is\n // dropped rather than sent as an empty content array. The flush above\n // already ran, so a pending image carrier survives this skip.\n if (parts.length === 0) continue\n const hasImage = parts.some((part) => (part as { type?: string }).type === 'image_url')\n if (!hasImage && parts.length === 1) {\n out.push({ role: 'user', content: (parts[0] as { text: string }).text })\n } else {\n // Preserve separate text/image parts rather than silently joining\n // text blocks together.\n out.push({ role: 'user', content: parts })\n }\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const text = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\n .map((block) => block.text)\n .join('')\n const reasoning = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'reasoning' }> => block.type === 'reasoning')\n .map((block) => block.text)\n .join('')\n const toolCalls = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'tool-call' }> => block.type === 'tool-call' && paired.has(block.id))\n .map((block) => ({\n id: wireIds.get(block.id) ?? block.id,\n type: 'function' as const,\n function: {\n name: block.name,\n arguments: block.arguments,\n },\n }))\n\n if (text === '' && reasoning === '' && toolCalls.length === 0) continue\n const assistant: Record<string, unknown> = {\n role: 'assistant',\n content: text === '' ? null : text,\n }\n // Chat Completions / DeepSeek thinking mode: replay historical reasoning\n // so tool-calling loops can continue from the previous chain of thought.\n if (reasoning !== '') assistant.reasoning_content = reasoning\n if (toolCalls.length > 0) assistant.tool_calls = toolCalls\n out.push(assistant)\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (isToolResultMessage(message)) {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n const media = toolResultMedia(block)\n // Resolved once: the tool message and the carrier note below must name\n // the same call, or the model cannot tie an image back to its result.\n const wireToolCallId = wireIds.get(block.toolCallId) ?? block.toolCallId\n out.push({\n role: 'tool',\n tool_call_id: wireToolCallId,\n content: toolResultTextForWire(media),\n })\n // Chat Completions allows no image part under `role: 'tool'`, so a\n // tool-returned image (e.g. `read_image`) follows as a user message.\n if (media.images.length > 0) {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireToolCallId) }]\n for (const attachment of media.images) {\n carried.push(await imageToOpenAI(attachment, readImage))\n }\n pendingImages.push({ role: 'user', content: carried })\n }\n }\n }\n flushPendingImages()\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Adapter\n// ---------------------------------------------------------------------------\n/** Connection facts resolved fresh per request by the plugin entry. */\nexport interface CommandCodeConnectionOptions {\n /** API base; the Provider API lives under it (`/alpha/generate`, `/provider/v1/chat/completions`, `/provider/v1/models`). */\n apiBase: string\n /** Working directory reported to the API (project slug, config block). */\n workingDir: string\n /** Model catalog cache path. */\n modelsCachePath: string\n /**\n * Milliseconds to wait for generate response headers / first byte (default 60s).\n * Must not bound the subsequent body stream — long generations are gated by\n * {@link streamIdleTimeoutMs} and the caller AbortSignal instead.\n */\n requestTimeoutMs: number\n /** Milliseconds a stream may stall before it is treated as a dead connection (default 300s). */\n streamIdleTimeoutMs: number\n /**\n * Whether the picker hides models above the account's subscription tier\n * (default true). The filter fails open: unknown plan, billing-endpoint\n * failure, a positive on-demand credit balance, or an unmapped model all\n * keep the full catalog visible. Set false to always list every model.\n */\n filterModelsByPlan?: boolean\n /**\n * Visible-model allowlist: catalog model ids shown in pickers. Empty or\n * unset means \"show everything\"; applies after the subscription-tier filter.\n * The settings page persists it; the catalog endpoint serves the full\n * catalog regardless so the page can always offer every model.\n */\n visibleModels?: string[] | undefined\n /**\n * Per-model visibility overrides, keyed by catalog id. Written by the\n * terminal settings page, whose checkbox list gives every model its own\n * boolean field: a field writes one value at one path, so membership in\n * {@link visibleModels} cannot be expressed from there, while a flag can.\n * An id present here decides that model on its own (true = listed, false =\n * hidden); an id absent here follows {@link visibleModels} exactly as it did\n * before, so composition configs and the web page are unaffected.\n */\n modelVisibility?: Readonly<Record<string, boolean>> | undefined\n /**\n * Optional protocol hint. `'auto'` (default) uses billing/cache plus\n * Provider API fallback; `'cli'` forces `/alpha/generate`; `'openai'`\n * prefers `/provider/v1/chat/completions` but still falls back to the CLI\n * transport on `upgrade_required` (Go-plan keys have no Provider API\n * access — failing outright would strand them). This is a\n * connection-level test/operator seam and is intentionally not part of\n * the plugin's user settings schema.\n */\n protocol?: 'auto' | CommandCodeProtocol\n}\n\n/**\n * Resolve the durable attachment service, or undefined when the host does not\n * provide one. Called lazily only when a request actually carries images, so a\n * text-only request never depends on the attachment seam.\n */\nexport type ResolveAttachments = () => AttachmentStore | undefined\n\n/** Everything the adapter needs beyond the request itself. */\nexport interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** Resolve the current connection facts (fresh per request, settings-aware). */\n options: () => C\n /**\n * Resolve a usable API key for the given connection facts and the request's\n * model id, or throw `MISSING_CREDENTIAL`. The model is optional: hosts\n * without model-aware routing ignore it.\n */\n resolveApiKey: (connection: C, model?: string) => Promise<string>\n /**\n * Multi-account rotation hook: the request sent with `rejectedKey` was\n * refused with 429 (`rate-limit`) or 401 (`invalid-credential`) before\n * any response body streamed. The host marks that key and returns the next\n * account's key to retry with, or `undefined` to surface the failure.\n * Only pre-stream rejections rotate — a mid-stream failure never replays a\n * partially consumed generation against another account.\n */\n rotateApiKey?: (rejectedKey: string, rejection: 'rate-limit' | 'invalid-credential', connection: C, model?: string) => Promise<string | undefined>\n /** HTTP transport override (tests); defaults to the global `fetch`. */\n fetchImpl?: typeof fetch\n /** Resolve the optional durable attachment service for image input (tests); defaults to none. */\n resolveAttachments?: ResolveAttachments\n /**\n * Request-image policy override (tests); defaults to the installed engine's\n * own helpers, whichever generation they belong to. Injecting it is the only\n * way to exercise the ≥0.1.6 durable-offload contract while this checkout\n * still compiles against the 0.1.2 peers.\n */\n imageOffload?: CoreImagePolicy\n}\n\n/** Account identity from `/alpha/whoami`. */\nexport interface CommandCodeAccount {\n id: string\n name: string\n userName: string\n}\n\n/** Usage summary from `/alpha/usage/summary`. */\nexport interface CommandCodeUsage {\n totalCount: number\n totalCost: number\n successRate: number\n completedCount: number\n failedCount: number\n totalTokensIn: number\n totalTokensOut: number\n totalCredits: number\n periodBasis: string\n}\n\n/** Credit/limit state from `/alpha/billing/credits`. */\nexport interface CommandCodeCredits {\n monthlyCredits: number\n purchasedCredits: number\n freeCredits: number\n /**\n * Whether the endpoint actually published a monthly balance. The scalar\n * above defaults to 0 for shape stability, which is a LIE about an omitted\n * field — and a false \"0 left, fully consumed\" on the dashboard. Consumers\n * that render the figure must check this first: an explicit `false` means\n * \"not reported\", not \"nothing left\".\n *\n * Optional on purpose. `undefined` means the flag itself was never recorded —\n * an older Host half, or a frame from before this field existed — and is read\n * as \"assume reported\", which is the behavior that shipped. Only an explicit\n * `false` from a Host that knows the balance was omitted suppresses the\n * figure, so a cross-version pair does not lose a real balance.\n */\n monthlyReported?: boolean\n purchasedReported?: boolean\n freeReported?: boolean\n /**\n * Five-hour rolling window limits, absent when the endpoint reported no such\n * window. Absence is NOT \"a window with no cap\": a reported window with\n * `cap === 0` is uncapped spend, while an absent one was never reported at\n * all, and only the un-reported case must keep a figure off the dashboard.\n */\n fiveHour?: { used: number; cap: number; exceeded: boolean; resetAt: number }\n /** Weekly window limits; absent under the same rule as {@link fiveHour}. */\n weekly?: { used: number; cap: number; exceeded: boolean; resetAt: number }\n}\n\n/** Subscription plan state from `/alpha/billing/subscriptions`. */\nexport interface CommandCodePlan {\n /** Raw subscription plan id (e.g. `individual-pro`); empty when unreported. */\n planId: string\n /** Display name (e.g. `Pro`); falls back to the raw id for unknown plans. */\n name: string\n /** Raw subscription status (`active`, `trialing`, `past_due`, …); empty when unreported. */\n status: string\n /** The plan's monthly credit total per {@link KNOWN_SUBSCRIPTION_PLANS}; null for unknown plans. */\n monthlyCredits: number | null\n /** Billing period end in millis; 0 when the endpoint did not report one. */\n currentPeriodEnd: number\n}\n\n/**\n * Why every account endpoint failed at once (the report then carries no data\n * at all, so the degraded per-endpoint view would hide the root cause behind\n * a generic \"partial data\" note). Undefined for partial failures.\n */\nexport type UsageBlockReason = 'invalid-key' | 'service-unavailable' | 'network'\n\n/** Account endpoints fetched by one `getUsage()` run (see the classification there). */\nconst USAGE_ENDPOINT_COUNT = 4\n\n/** Everything the usage endpoints report, fetched together. */\nexport interface CommandCodeUsageReport {\n account?: CommandCodeAccount\n usage?: CommandCodeUsage\n credits?: CommandCodeCredits\n plan?: CommandCodePlan\n /** Endpoint failures degrade the report instead of failing it. */\n failures: string[]\n /**\n * The single reason every endpoint failed, when they all did: `invalid-key`\n * (every call rejected with 401 — the stored key is wrong or expired),\n * `service-unavailable` (every call answered 5xx), or `network` (no HTTP\n * response at all). Undefined when any endpoint succeeded.\n */\n blocked?: UsageBlockReason\n}\n\n/**\n * Parse one usage/summary payload into the report's usage section.\n * Returns undefined when the endpoint answered nothing usable.\n */\nfunction parseUsageTotals(usage: Record<string, unknown> | undefined): CommandCodeUsage | undefined {\n // Note: `getUsage` always answers `usage` (200 with `{}` parses to zeros)\n // — undefined here means the endpoint failed or answered non-JSON, which\n // the caller already booked into `failures`.\n if (usage === undefined) return undefined\n return {\n totalCount: numberValue(usage.totalCount) ?? 0,\n totalCost: numberValue(usage.totalCost) ?? 0,\n successRate: numberValue(usage.successRate) ?? 0,\n completedCount: numberValue(usage.completedCount) ?? 0,\n failedCount: numberValue(usage.failedCount) ?? 0,\n totalTokensIn: numberValue(usage.totalTokensIn) ?? 0,\n totalTokensOut: numberValue(usage.totalTokensOut) ?? 0,\n totalCredits: numberValue(usage.totalCredits) ?? 0,\n periodBasis: stringValue(usage.periodBasis) ?? 'billing-period',\n }\n}\n\n/** Parse one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one window block into a window limit, or undefined when the endpoint\n * reported no such window.\n *\n * Returning undefined (rather than a zeroed window) is load-bearing: the panel\n * must not draw a quota row for a window the account never reported, and a\n * zeroed window is indistinguishable from a genuinely uncapped one.\n */\nfunction parseWindowLimit(value: unknown): CommandCodeCredits['fiveHour'] {\n const block = isRecord(value) ? value : undefined\n if (block === undefined) return undefined\n return {\n used: numberValue(block.used) ?? 0,\n cap: numberValue(block.cap) ?? 0,\n exceeded: block.exceeded === true,\n resetAt: numberValue(block.resetAt) ?? 0,\n }\n}\n\n/**\n * Parse one billing/credits payload into the report's credits section.\n * Returns undefined when the endpoint answered nothing usable.\n */\nfunction parseCreditLimits(credits: Record<string, unknown> | undefined): CommandCodeCredits | undefined {\n if (credits === undefined) return undefined\n const creditsData = isRecord(credits.credits) ? credits.credits : undefined\n const windowLimits = isRecord(credits.windowLimits) ? credits.windowLimits : undefined\n const fiveHour = windowLimits !== undefined && isRecord(windowLimits.fiveHour) ? windowLimits.fiveHour : undefined\n const weekly = windowLimits !== undefined && isRecord(windowLimits.weekly) ? windowLimits.weekly : undefined\n if (creditsData === undefined && fiveHour === undefined && weekly === undefined) return undefined\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberValue(creditsData?.monthlyCredits) ?? 0,\n purchasedCredits: numberValue(creditsData?.purchasedCredits) ?? 0,\n freeCredits: numberValue(creditsData?.freeCredits) ?? 0,\n // Recorded separately from the scalar: the panel must not report an\n // omitted balance as a consumed one.\n monthlyReported: numberValue(creditsData?.monthlyCredits) !== undefined,\n purchasedReported: numberValue(creditsData?.purchasedCredits) !== undefined,\n freeReported: numberValue(creditsData?.freeCredits) !== undefined,\n }\n // Optional members are only present when reported, never present-but-undefined\n // (`exactOptionalPropertyTypes`), so an absent window cannot be mistaken for a\n // parsed one with zeroed numbers.\n const fiveHourLimit = parseWindowLimit(fiveHour)\n const weeklyLimit = parseWindowLimit(weekly)\n if (fiveHourLimit !== undefined) parsed.fiveHour = fiveHourLimit\n if (weeklyLimit !== undefined) parsed.weekly = weeklyLimit\n return parsed\n}\n\n/**\n * Parse the account identity from whoami plus the plan identity from the\n * subscriptions/credits payloads. Returns the org id for the subscriptions\n * query alongside, so getUsage fetches whoami first and the rest in parallel.\n */\nfunction parseAccountIdentity(whoami: Record<string, unknown> | undefined): {\n account: CommandCodeAccount | undefined\n orgId: string | undefined\n} {\n const whoamiData = whoami !== undefined && isRecord(whoami.user) ? whoami.user : undefined\n const orgData = whoami !== undefined && isRecord(whoami.org) ? whoami.org : undefined\n return {\n account: whoamiData === undefined ? undefined : {\n id: stringValue(whoamiData.id) ?? '',\n name: stringValue(whoamiData.name) ?? '',\n userName: stringValue(whoamiData.userName) ?? '',\n },\n orgId: orgData === undefined ? undefined : stringValue(orgData.id),\n }\n}\n\n/**\n * Classify a TOTAL failure: when every endpoint failed with one class of\n * error, the degraded per-endpoint view would hide the root cause behind\n * a generic \"partial data\" note — name it instead.\n */\nfunction classifyTotalFailure(\n failures: readonly string[],\n failedStatuses: ReadonlyArray<number | undefined>,\n): UsageBlockReason | undefined {\n // Four endpoints are fetched (whoami, usage/summary, billing/credits,\n // billing/subscriptions; the last may carry an orgId query, so the\n // classification counts endpoints, not paths).\n if (failures.length !== USAGE_ENDPOINT_COUNT) return undefined\n const codes = failedStatuses.filter((status): status is number => status !== undefined)\n if (codes.length === USAGE_ENDPOINT_COUNT && codes.every((code) => code === 401)) {\n return 'invalid-key'\n }\n if (codes.length === USAGE_ENDPOINT_COUNT && codes.every((code) => code >= 500)) {\n return 'service-unavailable'\n }\n if (codes.length === 0) return 'network'\n return undefined\n}\n\n/**\n * The shared facts one generate call needs, computed once up front so the\n * body builders, the connect loop, and the stream pump below all read the\n * same snapshot instead of closing over `stream()` locals.\n */\ninterface GenerateCallFacts {\n /** Resolved API key for the first attempt (rotation may replace it). */\n apiKey: string\n /** maxTokens cap for the request model (in-memory catalog, else default). */\n maxTokens: number\n /** Validated reasoning effort, or undefined when unset/unsupported. */\n reasoningEffort: string | undefined\n /** Folded system text (top-level system + system-role messages). */\n systemText: string\n /** Per-call image byte resolver; set only when the request carries images. */\n readImage: ((ref: ImageAttachmentRef) => Promise<Uint8Array>) | undefined\n}\n\n/** Build the legacy CLI (`/alpha/generate`) request body for one call. */\nasync function buildCliBody(\n options: GenerateOptions,\n connection: CommandCodeConnectionOptions,\n facts: Pick<GenerateCallFacts, 'maxTokens' | 'reasoningEffort' | 'systemText' | 'readImage'>,\n): Promise<Record<string, unknown>> {\n return {\n config: {\n workingDir: connection.workingDir,\n date: new Date().toISOString().split('T')[0],\n environment: `${process.platform}-${process.arch}, Node.js ${process.version}`,\n structure: [],\n isGitRepo: false,\n currentBranch: '',\n mainBranch: '',\n gitStatus: '',\n recentCommits: [],\n },\n memory: null,\n taste: null,\n skills: null,\n params: {\n model: options.model,\n messages: await messagesToCC(options.messages, facts.readImage),\n tools: (options.tools ?? []).map((tool) => ({\n type: 'function',\n name: tool.name,\n description: tool.description,\n input_schema: toolParametersSchema(tool.parameters),\n })),\n system: facts.systemText,\n max_tokens: facts.maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(facts.reasoningEffort ? { reasoning_effort: facts.reasoningEffort } : {}),\n },\n threadId: randomUUID(),\n }\n}\n\n/** Build the documented Provider Chat Completions request body for one call. */\nasync function buildOpenAIBody(\n options: GenerateOptions,\n facts: Pick<GenerateCallFacts, 'maxTokens' | 'reasoningEffort' | 'systemText' | 'readImage'>,\n): Promise<Record<string, unknown>> {\n const openAiMessages = [\n ...(facts.systemText ? [{ role: 'system', content: facts.systemText }] : []),\n ...(await messagesToOpenAI(options.messages, facts.readImage)),\n ]\n const openAiTools = (options.tools ?? []).map((tool) => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: toolParametersSchema(tool.parameters),\n },\n }))\n return {\n model: options.model,\n messages: openAiMessages,\n ...(openAiTools.length > 0 ? { tools: openAiTools } : {}),\n max_tokens: facts.maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(facts.reasoningEffort ? { reasoning_effort: facts.reasoningEffort } : {}),\n }\n}\n\n/**\n * One connect attempt's inputs: everything `connectGenerate` needs beyond\n * the per-attempt key and protocol. Passed explicitly (not closed over) so\n * the rotation loop's mutation of `protocol`/`body` stays visible at the\n * call site.\n */\ninterface GenerateConnectDeps {\n options: GenerateOptions\n connection: CommandCodeConnectionOptions\n fetchImpl: typeof fetch\n}\n\n/**\n * One pre-stream connect attempt: POST the body and wait for response\n * headers only (`requestTimeoutMs` must never bound the body stream — see\n * the caller). Returns the live response plus its cleanup, or the rejection\n * facts for the rotation loop to classify. Every failure path cleans up\n * before returning or throwing; on success the caller-abort listener\n * outlives the connect phase (it aborts a stalled body read), so the\n * streaming tail calls cleanup.\n */\nasync function connectGenerate(\n deps: GenerateConnectDeps,\n key: string,\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n): Promise<{ response: Response; cleanup: () => void } | { status: number; errText: string; retryAfterMs?: number }> {\n const { options, connection, fetchImpl } = deps\n const connectAbort = new AbortController()\n let connectTimedOut = false\n const endpoint = protocol === 'cli'\n ? `${connection.apiBase}/alpha/generate`\n : `${connection.apiBase}/provider/v1/chat/completions`\n const connectTimer = setTimeout(() => {\n connectTimedOut = true\n connectAbort.abort(\n new DOMException(\n `Command Code API request to ${endpoint} did not respond within ${connection.requestTimeoutMs}ms`,\n 'TimeoutError',\n ),\n )\n }, connection.requestTimeoutMs)\n const onCallerAbort = () => {\n connectAbort.abort(options.signal?.reason)\n }\n if (options.signal) {\n if (options.signal.aborted) {\n onCallerAbort()\n } else {\n options.signal.addEventListener('abort', onCallerAbort, { once: true })\n }\n }\n const cleanup = () => {\n clearTimeout(connectTimer)\n if (options.signal) {\n options.signal.removeEventListener('abort', onCallerAbort)\n }\n }\n\n let response: Response\n const headers = protocol === 'cli'\n ? {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n 'x-project-slug': projectSlugFromPath(connection.workingDir),\n 'x-taste-learning': 'true',\n 'x-co-flag': 'false',\n ...attributionHeaders(),\n }\n : {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n Accept: 'text/event-stream',\n // Deliberately no x-command-code-version / x-cli-environment:\n // this is the documented OpenAI-format surface, not the CLI\n // transport — do not \"fix\" these in.\n ...attributionHeaders(),\n }\n try {\n response = await fetchImpl(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: connectAbort.signal,\n })\n clearTimeout(connectTimer)\n } catch (error: unknown) {\n cleanup()\n if (options.signal?.aborted) {\n throw error\n }\n if (connectTimedOut || (error instanceof DOMException && error.name === 'TimeoutError')) {\n throw new LlmError(\n `Command Code API request to ${endpoint} did not respond within ${connection.requestTimeoutMs}ms`\n + `: ${errorChain(error)}`\n + `;Command Code API 请求在 ${connection.requestTimeoutMs} 毫秒内未收到响应——通常是网络或代理问题,请检查后重试`,\n 'TIMEOUT',\n { cause: error },\n )\n }\n // fetch wraps every transport failure (DNS, refused connection, TLS,\n // proxy, reset) in a bare `TypeError: fetch failed` whose actionable\n // detail lives on `cause`. Include the full chain so the failure reason\n // shown in the web UI (which renders only the message, not `cause`)\n // names the real root cause instead of a generic wrapper.\n throw new LlmError(\n `Command Code API request to ${endpoint} failed: ${errorChain(error)}`\n + ';Command Code API 请求连接失败——通常是网络或代理问题,请检查网络或代理设置后重试',\n 'TRANSPORT',\n { cause: error },\n )\n }\n\n if (!response.ok) {\n const errText = await response.text().catch(() => '')\n cleanup()\n const retryAfterMs = parseRetryAfterMs(response.headers.get('retry-after'))\n // exactOptionalPropertyTypes: the key must be absent, not undefined.\n return retryAfterMs === undefined\n ? { status: response.status, errText }\n : { status: response.status, errText, retryAfterMs }\n }\n return { response, cleanup }\n}\n\n/**\n * The StreamChunk block-assembly state shared by both transport handlers:\n * at most one text block and one reasoning block are open at a time (same\n * assumption as the pi plugin).\n */\ninterface BlockAssembler {\n nextIndex: number\n textIndex: number\n textContent: string\n reasoningIndex: number\n reasoningContent: string\n sawContent: boolean\n /** Buffered OpenAI tool-call fragments, flushed at finish. */\n openAiToolCalls: Array<{ index: number; id?: string; name: string; arguments: string }>\n}\n\n/** Fresh block-assembly state for one stream. */\nfunction createBlockAssembler(): BlockAssembler {\n return {\n nextIndex: 0,\n textIndex: -1,\n textContent: '',\n reasoningIndex: -1,\n reasoningContent: '',\n sawContent: false,\n openAiToolCalls: [],\n }\n}\n\nfunction* closeText(asm: BlockAssembler): Generator<StreamChunk> {\n if (asm.textIndex < 0) return\n yield {\n type: 'block-end',\n index: asm.textIndex,\n block: { type: 'text', text: asm.textContent },\n }\n asm.textIndex = -1\n asm.textContent = ''\n}\n\nfunction* closeReasoning(asm: BlockAssembler): Generator<StreamChunk> {\n if (asm.reasoningIndex < 0) return\n yield {\n type: 'block-end',\n index: asm.reasoningIndex,\n block: { type: 'reasoning', text: asm.reasoningContent },\n }\n asm.reasoningIndex = -1\n asm.reasoningContent = ''\n}\n\nfunction* emitOpenAiToolCalls(asm: BlockAssembler): Generator<StreamChunk> {\n for (const call of asm.openAiToolCalls) {\n const id = call.id ?? randomUUID()\n const name = call.name ?? ''\n const args = call.arguments || '{}'\n const index = asm.nextIndex++\n asm.sawContent = true\n yield { type: 'block-start', index, blockType: 'tool-call' }\n yield { type: 'tool-call-delta', index, id: ToolCallId(id), name, argumentsDelta: args }\n yield {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: ToolCallId(id), name, arguments: args },\n }\n }\n asm.openAiToolCalls.length = 0\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private catalog: CommandCodeModel[] = []\n private readonly fetchImpl: typeof fetch\n private readonly resolveAttachments: ResolveAttachments | undefined\n /** The engine's request-image policy, resolved once (tests may inject one). */\n private readonly imagePolicy: CoreImagePolicy\n /**\n * The ≥0.1.6 durable contract, or `undefined` on a ≤0.1.5 engine — where the\n * adapter must evict its own history. Resolved once: the contract a process\n * speaks cannot change while it runs, and resolving here keeps every request\n * on the same branch (see {@link surfaceImagePolicy}).\n */\n private readonly surfaceOffload: SurfaceImagePolicy | undefined\n // Billing facts are per account: with a multi-account pool each key has its\n // own subscription tier, so the cache and the in-flight dedupe are keyed by\n // the resolved API key (process-local only, never logged). Entries are\n // small and bounded by the account count in practice; a changed key simply\n // starts a fresh entry while the orphaned one goes cold (no eviction —\n // transience is intentional, persistence would serve stale tiers).\n private readonly billingAccess = new Map<string, { value: CommandCodeBillingAccess | undefined; at: number }>()\n private readonly billingAccessInflight = new Map<string, Promise<CommandCodeBillingAccess | undefined>>()\n // Protocol preference is per account: the Go plan is the only plan without\n // Provider API access, and that fact is independent of model. A negative\n // result (provider API rejected this key with upgrade_required) is cached so\n // every request does not pay the double TTFT of probing then falling back.\n // Same bounded-by-account-count note as above: no eviction by design.\n private readonly protocolCache = new Map<string, { useCli: boolean; at: number }>()\n\n constructor(private readonly deps: CommandCodeAdapterDeps<C>) {\n super()\n this.fetchImpl = deps.fetchImpl ?? fetch\n this.resolveAttachments = deps.resolveAttachments\n this.imagePolicy = deps.imageOffload ?? CORE_IMAGE_POLICY\n this.surfaceOffload = surfaceImagePolicy(this.imagePolicy)\n }\n\n /**\n * Display metadata for the picker's provider group header. The base class\n * returns the raw route id (`commandcode`, all lowercase) as the name, which\n * is what the model selector shows as this group's sticky title; return the\n * proper display name instead, matching the Models settings page card (the\n * configurable-provider `displayName`). The id must stay equal to the route.\n */\n override providerInfo(provider: string): LlmProviderInfo {\n return { id: provider, name: 'Command Code' }\n }\n\n /**\n * Near-unbounded retry for transient failures only (`mode: 'normal'` with\n * an explicit 1000-attempt cap — opencode-style persistence without the\n * unbounded loop): `RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`/\n * `EMPTY_RESPONSE` retry up to 1000 times with waits doubling from 500 ms\n * and capping at 15 minutes (±10% jitter), so an exhausted 5-hour window\n * recovers in-session instead of failing after two tries. Permanent\n * failures (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`,\n * plan rejections) are absent from the whitelist and surface immediately\n * instead of looping. Waits the pool/adapter attach as\n * `providerRetryAfterMs` are honored verbatim at or below the 15-minute\n * cap and never attached above it (in normal mode a longer attached wait\n * makes the executor abandon the retry outright — see RETRY_MAX_DELAY_MS).\n *\n * Captured once at route registration (dsh-llm snapshots this value), so a\n * future config knob for it would apply on profile restart, not per request.\n */\n override providerRetryPolicy(_provider: string): ResolvedRetryPolicy {\n return resolveRetryPolicy(\n {\n mode: 'normal',\n maxRetries: 1000,\n retryableCodes: ['EMPTY_RESPONSE', 'RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT'],\n backoff: { initialDelayMs: 500, maxDelayMs: RETRY_MAX_DELAY_MS, jitterRatio: 0.1 },\n },\n 'llm-commandcode: retryPolicy',\n )\n }\n\n /**\n * Visual-token pricing for one exact model route (see `./image-tokens.ts`).\n *\n * Without this the token meter prices EVERY image with its structural\n * heuristic — a handful of tokens for a full screenshot — so an image-heavy\n * session reports far less context than it is actually carrying. The price is\n * computed at the dimensions this route would send (the same request target\n * `readImageRequest` encodes to), so the estimate tracks the wire rather than\n * the stored original.\n *\n * Both payload generations are handled, because they disagree: ≤0.1.5 hands\n * over bare `ImageAttachmentRef`s, ≥0.1.6 hands over `ImageBlock`s that also\n * carry the surface's `offloaded` mark. Returning a price per occurrence, in\n * order, is a hard requirement — the meter throws when the counts differ.\n */\n override imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined {\n const imageCapable = KNOWN_IMAGE_MODELS.has(model)\n return {\n priceImages: (images: readonly PricedOccurrence[]) =>\n images.map((image) => priceRequestImage(image, model, imageCapable)),\n }\n }\n\n /** Refresh the catalog (live fetch, cache fallback) and return it. */\n private async loadCatalog(signal?: AbortSignal): Promise<CommandCodeModel[]> {\n const { apiBase, modelsCachePath } = this.deps.options()\n try {\n const response = await this.fetchImpl(`${apiBase}/provider/v1/models`, {\n headers: { accept: 'application/json', ...attributionHeaders() },\n signal: signal ?? AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) {\n throw new Error(`models endpoint returned ${response.status}`)\n }\n this.catalog = parseCatalogResponse(await response.json())\n await writeModelsCache(modelsCachePath, this.catalog).catch(() => undefined)\n } catch (error) {\n if (signal?.aborted) throw error\n // A catalog refresh failure is a degradation, not a request failure:\n // fall back to the last successful catalog on disk (or the in-memory\n // one from an earlier successful load). The adapter still serves any\n // model the user names; only the advisory selector loses entries.\n this.catalog = await readModelsCache(modelsCachePath).catch(() => this.catalog)\n }\n return this.catalog\n }\n\n override async listModels(\n provider: string,\n opts?: { unfiltered?: boolean },\n ): Promise<readonly LlmModelInfo[]> {\n const catalog = await this.loadCatalog()\n const toInfo = (model: (typeof catalog)[number]) => {\n const vision = KNOWN_IMAGE_MODELS.has(model.id)\n return {\n provider,\n id: model.id,\n name: `${model.name} (CC)`,\n // The picker renders `description` under the model name: plan tier,\n // active deal, Image marker for Vision models, and context window.\n description: capabilityDescription(model.id, model.contextWindow),\n inputModalities: vision ? (['text', 'image'] as const) : (['text'] as const),\n }\n }\n // Unfiltered: the settings page's catalog endpoint serves the full catalog\n // so the filter editor can always offer every model.\n if (opts?.unfiltered === true) return catalog.map(toInfo).sort(compareByPlan)\n // Plan filter: hide models above the account's subscription tier. Fails\n // open — a billing-fetch problem, an unknown plan, or a positive\n // on-demand balance all keep the full catalog visible, and the server\n // remains the final gate (403 MODEL_NOT_IN_PLAN). The catalog itself is\n // never filtered: resolveModel still serves every model.\n const access = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadBillingAccess()\n // Visible-model allowlist: empty/unset means \"show everything\".\n const visible = this.deps.options().visibleModels\n const allow = Array.isArray(visible) && visible.length > 0\n ? new Set(visible.filter((id) => typeof id === 'string' && id !== ''))\n : undefined\n // Per-model overrides, written by the terminal settings page's checkboxes\n // (its seam can only give each model its own boolean field, and a boolean\n // cannot express \"this id is in the list\"). An explicit flag decides the\n // model on its own; everything unflagged still follows the array above, so\n // a composition-config allowlist and the web page keep working untouched.\n const overrides = this.deps.options().modelVisibility\n return catalog\n .filter((model) => modelVisibleInPlan(model.id, access))\n .filter((model) => {\n const override = overrides?.[model.id]\n if (typeof override === 'boolean') return override\n return allow === undefined || allow.has(model.id)\n })\n .map(toInfo)\n // The picker renders rows in the order returned: sort by plan tier\n // (Go first, … Provider last) so the models a Go-plan user can actually\n // use lead the list, then alphabetically within each tier.\n .sort(compareByPlan)\n }\n\n override async resolveModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<LlmResolvedModelInfo> {\n const entry =\n this.catalog.find((m) => m.id === model) ??\n (await this.loadCatalog(signal)).find((m) => m.id === model)\n\n const efforts = KNOWN_EFFORTS[model]\n const vision = KNOWN_IMAGE_MODELS.has(model)\n return {\n provider,\n id: model,\n name: entry ? `${entry.name} (CC)` : model,\n description: capabilityDescription(model, entry?.contextWindow),\n inputModalities: vision ? (['text', 'image'] as const) : (['text'] as const),\n ...(entry\n ? {\n context: { contextWindow: entry.contextWindow },\n defaultMaxTokens: Math.min(entry.maxTokens, DEFAULT_GENERATE_MAX_TOKENS),\n }\n : {}),\n // Omit `reasoning` entirely for models without known effort support:\n // the harness then treats the model as having no selectable efforts.\n ...(efforts\n ? {\n reasoning: {\n efforts: efforts.map((effort) => ({\n id: ReasoningEffortId(effort),\n name: effort,\n })),\n },\n }\n : {}),\n }\n }\n\n /** The headers every authenticated account endpoint shares. */\n private async accountHeaders(apiKey?: string): Promise<Record<string, string>> {\n const connection = this.deps.options()\n const key = apiKey ?? (await this.deps.resolveApiKey(connection))\n return {\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n ...attributionHeaders(),\n }\n }\n\n /**\n * Fetch one account endpoint and parse its JSON body. Returns the HTTP\n * status alongside the parsed record so each caller applies its own\n * failure accounting: the billing probe fails open silently, the usage\n * report books failures per endpoint. Non-2xx and non-record bodies come\n * back without a record; only a transport throw propagates to the caller.\n */\n private async fetchEndpointJson(\n url: string,\n headers: Record<string, string>,\n ): Promise<{ status: number; record?: Record<string, unknown> }> {\n const response = await this.fetchImpl(url, {\n headers,\n // A hung account endpoint must not stall the picker / usage card forever.\n signal: AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) return { status: response.status }\n const parsed: unknown = await response.json()\n return { status: response.status, ...(isRecord(parsed) ? { record: parsed } : {}) }\n }\n\n /**\n * The billing facts behind the picker's plan filter, cached for\n * {@link BILLING_ACCESS_TTL_MS} and shared across concurrent callers.\n * `undefined` means \"unknown — show everything\" (fail-open).\n */\n private async loadBillingAccess(): Promise<CommandCodeBillingAccess | undefined> {\n let apiKey: string\n try {\n apiKey = await this.deps.resolveApiKey(this.deps.options())\n } catch {\n return undefined\n }\n const cached = this.billingAccess.get(apiKey)\n if (cached !== undefined && Date.now() - cached.at < BILLING_ACCESS_TTL_MS) return cached.value\n const existing = this.billingAccessInflight.get(apiKey)\n if (existing !== undefined) return existing\n const inflight = this.fetchBillingAccess(apiKey)\n .then((value) => {\n this.billingAccess.set(apiKey, { value, at: Date.now() })\n return value\n })\n .finally(() => {\n this.billingAccessInflight.delete(apiKey)\n })\n this.billingAccessInflight.set(apiKey, inflight)\n return inflight\n }\n\n /**\n * The billing facts behind the picker's plan filter, mirroring the CLI's\n * `createBilling` flow: whoami yields the org id, then the subscriptions\n * and credits endpoints answer in parallel. The plan id is honored only\n * when the subscription reports an active-ish status (the CLI's rule); when\n * the subscriptions endpoint fails entirely, `credits.planId` is the\n * fallback (the CLI stamps plan identity from it too). Any failure resolves\n * to `undefined` (fail-open) rather than breaking the picker.\n */\n private async fetchBillingAccess(apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\n try {\n const connection = this.deps.options()\n const headers = await this.accountHeaders(apiKey)\n const base = connection.apiBase\n // Billing probe fails open silently: any non-record is \"unknown\".\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> =>\n (await this.fetchEndpointJson(`${base}${path}`, headers)).record\n const whoami = await getJson('/alpha/whoami')\n const orgData = whoami && isRecord(whoami.org) ? whoami.org : undefined\n const orgId = orgData === undefined ? undefined : stringValue(orgData.id)\n const [subscription, credits] = await Promise.all([\n getJson(orgId === undefined\n ? '/alpha/billing/subscriptions'\n : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`),\n getJson('/alpha/billing/credits'),\n ])\n const subData = subscription && isRecord(subscription.data) ? subscription.data : undefined\n const creditsData = credits && isRecord(credits.credits) ? credits.credits : undefined\n if (subData === undefined && creditsData === undefined) return undefined\n let planId: string | undefined\n if (subData !== undefined) {\n const status = stringValue(subData.status)\n if (status !== undefined && ACTIVE_SUBSCRIPTION_STATUSES.has(status)) planId = stringValue(subData.planId)\n } else {\n planId = stringValue(creditsData?.planId)\n }\n return {\n tierWeight: planId === undefined ? undefined : subscriptionPlanInfo(planId)?.tierWeight,\n onDemandCredits: (numberValue(creditsData?.purchasedCredits) ?? 0) + (numberValue(creditsData?.freeCredits) ?? 0),\n }\n } catch {\n return undefined\n }\n }\n\n /** Fresh cached billing tier weight for a key, or undefined when not known. */\n private cachedBillingTierWeight(apiKey: string): number | undefined {\n const hit = this.billingAccess.get(apiKey)\n if (hit === undefined || Date.now() - hit.at >= BILLING_ACCESS_TTL_MS) return undefined\n return hit.value?.tierWeight\n }\n\n /** Cached protocol decision for a key, or undefined when expired/unknown. */\n private cachedProtocolUseCli(apiKey: string): boolean | undefined {\n const hit = this.protocolCache.get(apiKey)\n if (hit === undefined || Date.now() - hit.at >= PROTOCOL_CACHE_TTL_MS) return undefined\n return hit.useCli\n }\n\n private rememberProtocol(apiKey: string, useCli: boolean): void {\n this.protocolCache.set(apiKey, { useCli, at: Date.now() })\n }\n\n /**\n * Choose the initial protocol for one request. A fresh protocol cache entry\n * wins; otherwise a cached (not network-fetched) billing tier of Go is\n * treated as CLI-only. Unknown accounts default to Provider API and fall\n * back only after an `upgrade_required` rejection.\n *\n * Models the Provider API serves ONLY through `/provider/v1/messages` (the\n * Claude family — `requiresMessagesEndpoint()`) always take the CLI\n * transport, on any tier and even under a forced `'openai'` preference:\n * that option is documented as \"prefer the Provider API, still fall back\",\n * and the 400 these models answer with is not a preference to be honoured\n * but a hard refusal. `/alpha/generate` routes every one of them, so this\n * costs nothing.\n *\n * That decision is deliberately NOT written to `protocolCache`. The cache is\n * keyed by API key alone, so remembering it would pin the whole ACCOUNT to\n * the CLI transport and drag every other model — DeepSeek, GLM, Qwen, all of\n * which the Provider API serves correctly — off it until the entry expired.\n */\n private resolveProtocol(apiKey: string, model: string): CommandCodeProtocol {\n const forced = this.deps.options().protocol\n if (forced === 'cli') return forced\n if (requiresMessagesEndpoint(model)) return 'cli'\n if (forced === 'openai') return forced\n const cached = this.cachedProtocolUseCli(apiKey)\n if (cached !== undefined) return cached ? 'cli' : 'openai'\n if (this.cachedBillingTierWeight(apiKey) === GO_TIER_WEIGHT) {\n this.rememberProtocol(apiKey, true)\n return 'cli'\n }\n return 'openai'\n }\n\n\n /**\n * Fetch account, usage, credit, and subscription state from the Command\n * Code account endpoints (`/alpha/whoami`, `/alpha/usage/summary`,\n * `/alpha/billing/credits`, `/alpha/billing/subscriptions`).\n * Each endpoint degrades independently: a failed one lands in `failures`\n * while the rest still report, so a transient outage never blanks the whole\n * view. Requires a usable API key (throws `MISSING_CREDENTIAL` otherwise).\n * Pass `apiKey` to report on a specific account of a multi-account pool;\n * the default resolves the currently active account.\n */\n async getUsage(apiKey?: string): Promise<CommandCodeUsageReport> {\n const connection = this.deps.options()\n const base = connection.apiBase\n const headers = await this.accountHeaders(apiKey)\n const failures: string[] = []\n // HTTP status per failed endpoint (undefined for transport failures), in\n // failure order — the all-failed classification below reads it.\n const failedStatuses: Array<number | undefined> = []\n\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> => {\n try {\n const { status, record } = await this.fetchEndpointJson(`${base}${path}`, headers)\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}`)\n failedStatuses.push(status)\n return undefined\n }\n return record\n } catch (error: unknown) {\n failures.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n failedStatuses.push(undefined)\n return undefined\n }\n }\n\n const report: CommandCodeUsageReport = { failures }\n\n // whoami first (account identity + the org id the subscriptions query\n // needs); the other three endpoints are independent once headers exist,\n // so they run in parallel instead of paying 4x the timeout serially.\n const whoami = await getJson('/alpha/whoami')\n const { account, orgId } = parseAccountIdentity(whoami)\n if (account !== undefined) report.account = account\n const [usage, credits, subscription] = await Promise.all([\n getJson('/alpha/usage/summary'),\n getJson('/alpha/billing/credits'),\n getJson(orgId === undefined\n ? '/alpha/billing/subscriptions'\n : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`),\n ])\n\n // usage/summary -> totals.\n const totals = parseUsageTotals(usage)\n if (totals !== undefined) report.usage = totals\n\n // billing/credits -> credit + window limits.\n const limits = parseCreditLimits(credits)\n if (limits !== undefined) report.credits = limits\n\n // billing/subscriptions -> plan identity + billing period. The credits\n // response may also carry a planId; it is the fallback when the\n // subscriptions endpoint fails.\n const subData = subscription !== undefined && isRecord(subscription.data) ? subscription.data : undefined\n const creditsData = credits !== undefined && isRecord(credits.credits) ? credits.credits : undefined\n const planId = stringValue(subData?.planId) ?? stringValue(creditsData?.planId)\n if (subData !== undefined || planId !== undefined) {\n const info = planId === undefined ? undefined : subscriptionPlanInfo(planId)\n report.plan = {\n planId: planId ?? '',\n name: info?.name ?? planId ?? '',\n status: stringValue(subData?.status) ?? '',\n monthlyCredits: info?.monthlyCredits ?? null,\n currentPeriodEnd: periodEndValue(subData?.currentPeriodEnd),\n }\n }\n\n const blocked = classifyTotalFailure(failures, failedStatuses)\n if (blocked !== undefined) report.blocked = blocked\n\n return report\n }\n\n /**\n * Probe one account's five-hour window from `/alpha/billing/credits`. The\n * multi-account pool calls this when every account is marked exhausted: an\n * account whose window no longer reports `exceeded` is revived, and the\n * `resetAt` values feed the \"earliest reset\" error message. Returns\n * `undefined` when the probe itself failed (transport, non-200, or a\n * payload without window limits) — a failed probe never changes pool state.\n */\n async probeFiveHourWindow(apiKey: string): Promise<{ exceeded: boolean; resetAt: number } | undefined> {\n try {\n const connection = this.deps.options()\n const response = await this.fetchImpl(`${connection.apiBase}/alpha/billing/credits`, {\n headers: await this.accountHeaders(apiKey),\n signal: AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) return undefined\n const parsed: unknown = await response.json()\n if (!isRecord(parsed)) return undefined\n const windowLimits = isRecord(parsed.windowLimits) ? parsed.windowLimits : undefined\n const fiveHour = windowLimits && isRecord(windowLimits.fiveHour) ? windowLimits.fiveHour : undefined\n if (fiveHour === undefined) return undefined\n return { exceeded: fiveHour.exceeded === true, resetAt: numberValue(fiveHour.resetAt) ?? 0 }\n } catch {\n return undefined\n }\n }\n\n async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n if (options.stop?.length) {\n // The Command Code wire format has no documented stop field; refuse\n // loudly instead of silently dropping a request field.\n throw new LlmError('Command Code adapter does not support stop sequences', 'UNSUPPORTED_OPTION')\n }\n const hasImages = options.messages.some(hasImageContent)\n // Per-call image byte resolver, set only when this request carries images.\n // Local, not an instance field: concurrent streams must never read each\n // other's resolver.\n let readImage: ((ref: ImageAttachmentRef) => Promise<Uint8Array>) | undefined\n if (hasImages) {\n // Model-capability gate: only models the official registry lists with\n // Vision accept images natively. Command Code's own CLI falls back to a\n // client-side VISION side-call for text-only models; this adapter does\n // not reproduce that interactive feature, so it refuses loudly instead\n // of sending bytes to a model that cannot read them.\n if (!KNOWN_IMAGE_MODELS.has(options.model)) {\n throw new LlmError(\n `Command Code model \"${options.model}\" does not support image input;`\n + ' switch to a Vision-capable model (see the model registry)',\n 'UNSUPPORTED_CONTENT',\n )\n }\n // Attachment seam: images arrive as durable references; resolving them\n // requires the host's attachment service.\n const attachments = this.resolveAttachments?.()\n if (attachments === undefined) {\n throw new LlmError(\n 'Command Code image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n readImage = (ref) => readRequestImage(attachments, ref)\n }\n\n const connection = this.deps.options()\n // The model id reaches key resolution so hosts with model→account routing\n // rules can pick the account that covers this model.\n let apiKey = await this.deps.resolveApiKey(connection, options.model)\n // Cap maxTokens from the in-memory catalog: it warms via listModels /\n // resolveModel on picker paths, and a fresh-process catalog must not add\n // a models fetch (and its failure modes) in front of every generate.\n const modelMax = this.catalog.find((m) => m.id === options.model)?.maxTokens\n ?? DEFAULT_MAX_OUTPUT_TOKENS\n const maxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n const reasoningEffort =\n effort && effort !== 'off' && supported?.includes(effort) ? effort : undefined\n\n const systemText = [\n options.system ?? '',\n ...options.messages\n .filter((m) => m.role === 'system')\n .map((m) => m.content.map(blockText).filter(Boolean).join('\\n')),\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n // Endpoint protocol: billing/cache may know Go plan -> CLI; unknown\n // accounts default to the documented Provider Chat Completions surface.\n // A Messages-only model (Claude) forces the CLI transport regardless —\n // see `resolveProtocol()`.\n let protocol: CommandCodeProtocol = this.resolveProtocol(apiKey, options.model)\n // Image budget (issue #37): the body is built from the PROJECTED history,\n // never the raw one, so the oldest images past the cap travel as\n // placeholder text instead of a body the gateway refuses outright. Rung 0\n // is the standing budget; a 413 below steps down the ladder.\n //\n // Which projection that is depends on the engine: a ≥0.1.6 harness owns the\n // offload set (this throws `IMAGE_OFFLOAD_REQUIRED` when more must go, and\n // the retry arrives with the surface already updated), while a ≤0.1.5 one\n // has no such ledger and gets the adapter's own transient eviction.\n let requestOptions = this.surfaceOffload === undefined\n ? withImageBudget(options, REQUEST_IMAGE_BUDGETS[0]!, this.imagePolicy)\n : withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!)\n let imageBudgetIndex = 0\n const buildBody = async (target: CommandCodeProtocol): Promise<Record<string, unknown>> =>\n target === 'cli'\n ? buildCliBody(requestOptions, connection, { maxTokens, reasoningEffort, systemText, readImage })\n : buildOpenAIBody(requestOptions, { maxTokens, reasoningEffort, systemText, readImage })\n let body: Record<string, unknown> = await buildBody(protocol)\n\n\n // Account rotation loop: the first attempt uses the pool's active key; a\n // pre-stream 429/401 rotates to the next account (at most one attempt per\n // distinct key, hard-capped so a misbehaving hook cannot loop forever).\n // requestTimeoutMs bounds the headers wait of EACH attempt (see\n // connectGenerate); the body is account-independent, nothing has\n // streamed yet, so the switch is invisible to the caller.\n const tried = new Set<string>()\n const connectDeps: GenerateConnectDeps = { options, connection, fetchImpl: this.fetchImpl }\n let connected: { response: Response; cleanup: () => void } | undefined\n for (;;) {\n tried.add(apiKey)\n const attempt = await connectGenerate(connectDeps, apiKey, protocol, body)\n if ('response' in attempt) {\n connected = attempt\n break\n }\n // Provider API is the preferred surface for non-Go accounts. If the\n // gateway says the key is on the Go plan (the only plan without API\n // access), remember that and retry the same key through /alpha/generate\n // without burning the double TTFT on every later request.\n if (\n protocol === 'openai'\n && isUpgradeRequiredError(attempt.status, attempt.errText)\n ) {\n protocol = 'cli'\n this.rememberProtocol(apiKey, true)\n body = await buildBody('cli')\n continue\n }\n // Request too large (issue #37): the standing budget is only an\n // estimate — the cap also covers text and tool bytes — so one 413 steps\n // the image budget down and resends. Safe like the rotation below:\n // nothing streamed, the same key stays in use, and a request with no\n // images left to evict is not resent (the stricter rung reports nothing\n // more to drop, so this branch cannot loop).\n if (attempt.status === 413 && imageBudgetIndex + 1 < REQUEST_IMAGE_BUDGETS.length) {\n if (this.surfaceOffload !== undefined) {\n // ≥0.1.6: the stricter rung becomes another offload request rather\n // than a local edit, so the extra omissions are recorded on the\n // session and survive the retry. Zero here means the images are\n // already gone and the body is simply too big — fall through to the\n // 413 diagnosis instead of asking for an offload that cannot happen.\n const missing = this.surfaceOffload.requiredImageOffload(\n requestOptions.messages,\n coreBudget(REQUEST_IMAGE_BUDGETS[imageBudgetIndex + 1]!),\n imageVersionBytes,\n )\n if (missing > 0) throw imageOffloadRequired(missing)\n } else {\n const tightened = withImageBudget(requestOptions, REQUEST_IMAGE_BUDGETS[imageBudgetIndex + 1]!, this.imagePolicy)\n if (tightened !== requestOptions) {\n imageBudgetIndex += 1\n requestOptions = tightened\n body = await buildBody(protocol)\n continue\n }\n }\n }\n const rotate = this.deps.rotateApiKey\n if (\n (attempt.status === 429 || attempt.status === 401)\n && rotate !== undefined\n && options.signal?.aborted !== true\n && tried.size < MAX_ACCOUNT_ROTATIONS\n ) {\n const next = await rotate(apiKey, attempt.status === 429 ? 'rate-limit' : 'invalid-credential', connection, options.model)\n if (next !== undefined && !tried.has(next)) {\n apiKey = next\n continue\n }\n }\n throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs)\n }\n if (connected === undefined) {\n // Unreachable: the loop only exits via `break` (connected set) or\n // `throw` above. The guard keeps the narrowing explicit.\n throw new LlmError('Command Code API connection failed without a response', 'TRANSPORT')\n }\n const { response, cleanup } = connected\n if (!response.body) {\n cleanup()\n throw new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR')\n }\n\n // --- SSE/JSONL event stream -> harness StreamChunk protocol ---\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n // Stream idle watchdog: a generation that stalls this long has a dead\n // connection (the API keeps the socket open between reasoning/text\n // bursts). The default (300s) is deliberately generous: frontier\n // reasoning models (xhigh/max effort) can legitimately stay silent for\n // minutes while thinking, and the official CLI sets no idle cap at all —\n // an aggressive cap turns long thinking into spurious TIMEOUTs and\n // retries. reader.cancel() unblocks a pending read(), which the loop then\n // turns into a TIMEOUT failure instead of hanging forever.\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n let idleFired = false\n const armIdle = () => {\n if (idleTimer !== undefined) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleFired = true\n void reader.cancel().catch(() => undefined)\n }, connection.streamIdleTimeoutMs)\n }\n const clearIdle = () => {\n if (idleTimer !== undefined) {\n clearTimeout(idleTimer)\n idleTimer = undefined\n }\n }\n\n const asm = createBlockAssembler()\n const handle = (event: unknown): StreamChunk[] => handleEvent(asm, protocol, event)\n try {\n let finished = false\n for (;;) {\n let read: ReadableStreamReadResult<Uint8Array>\n armIdle()\n try {\n read = await reader.read()\n } catch (error: unknown) {\n // A mid-stream transport failure (connection reset, TLS teardown)\n // surfaces here. Caller cancellation propagates as-is.\n if (options.signal?.aborted) throw error\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} failed while reading: ${errorChain(error)}`\n + ';Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\n 'TRANSPORT',\n { cause: error },\n )\n } finally {\n clearIdle()\n }\n const { done, value } = read\n if (done) {\n // The idle watchdog cancels the reader to unblock a stalled read;\n // cancel() resolves a pending read() as done, so a done here after\n // the watchdog fired is a timeout, not a normal stream end.\n if (idleFired) {\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} was idle for ${connection.streamIdleTimeoutMs}ms`\n + ' (no events) and was treated as a dead connection'\n + `;Command Code API 流式响应已 ${connection.streamIdleTimeoutMs} 毫秒无任何事件,被判定为死连接——长思考模型可在设置中调大流空闲超时`,\n 'TIMEOUT',\n )\n }\n if (buffer.trim()) {\n // The final line may lack its trailing newline: account its\n // chunks exactly like the line loop (a trailing `finish` must\n // set `finished`, or the tail below would emit a second one).\n for (const chunk of handle(parseStreamEventLine(buffer))) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n const chunks = handle(parseStreamEventLine(line))\n for (const chunk of chunks) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n if (finished) break\n }\n if (!finished) {\n // Stream ended without a finish event: close open blocks and\n // terminate according to the adapter contract (usage, then finish).\n yield* closeText(asm)\n yield* closeReasoning(asm)\n if (protocol === 'openai') yield* emitOpenAiToolCalls(asm)\n if (!asm.sawContent) {\n throw new LlmError('Command Code returned an empty response;Command Code 返回了空响应,重试通常可恢复', 'EMPTY_RESPONSE')\n }\n yield { type: 'finish', reason: { kind: 'stop' } }\n }\n } finally {\n clearIdle()\n cleanup()\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n}\n\n/**\n * Map a pre-stream generate HTTP failure onto a stable LlmError. Command\n * Code folds several business rejections into 403 (plan limits, CLI version,\n * model access): prefer the machine-readable `error.code` when present; the\n * status alone cannot distinguish them. The status also decides the failure\n * CODE via {@link httpErrorCode}, which is what the retry policy routes on —\n * a transient 5xx must not be reported as a permanent provider rejection. A\n * 429's `Retry-After` header rides along as\n * `providerRetryAfterMs` so dsh-llm-retry can wait exactly that long instead\n * of guessing at the backoff cadence — capped at RETRY_MAX_DELAY_MS, because\n * in normal mode a longer attached wait makes the executor abandon the retry\n * outright instead of falling back to local backoff.\n *\n * One body is read, not just its status: a client-side rejection whose\n * `error.code`/`type`/`message` names the model context window is reported as\n * `CONTEXT_WINDOW_EXCEEDED` (see the branch below), because that failure has a\n * recovery the harness performs and a generic provider error does not.\n */\nfunction generateHttpError(status: number, errText: string, retryAfterMs?: number): LlmError {\n let providerCode: string | undefined\n let providerDetail = ''\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed) && isRecord(parsed.error)) {\n providerCode = stringValue(parsed.error.code)\n providerDetail = [stringValue(parsed.error.code), stringValue(parsed.error.type), stringValue(parsed.error.message)]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\n }\n } catch {\n // Plain-text bodies: rely on the status mapping below.\n }\n const detail = providerCode ?? `HTTP ${status}`\n // A context-window rejection is not a generic provider failure: the request\n // is well-formed but larger than the model's window, and the harness knows\n // how to recover — dsh-compaction-basic answers CONTEXT_WINDOW_EXCEEDED on\n // `agent/request-error` with a compaction plus a retry of the reduced\n // surface. Reported as a plain provider rejection it failed the turn with no\n // way back but a manual /compact, and the same wording delivered in-band was\n // retried unchanged (issue #39). Checked before the 413 branch so an\n // over-context rejection that happens to carry that status gets the recovery\n // rather than the body-size advice. Only client-side rejections (`status <\n // 500`) are inspected, and the parsed provider fields are preferred over the\n // raw body, so an HTML error page cannot mention its way into a compaction.\n // Bilingual — the harness renders this message verbatim.\n const overflowDetail = providerDetail !== '' ? providerDetail : errText.slice(0, 500)\n if (status < 500 && isContextOverflowDetail(overflowDetail)) {\n return new LlmError(\n `Command Code API error ${status}: the request exceeds the model's context window`\n + ' — this session is being compacted and the request retried'\n + `;Command Code API 返回 ${status}:请求内容超出模型上下文窗口——正在压缩上下文后重试;如仍失败,请新建会话或减少上下文`,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n { status },\n )\n }\n if (status === 401) {\n // An invalid or missing credential is a config problem, not a\n // transport failure: retrying it identically cannot succeed. Bilingual —\n // the harness UI renders this message verbatim in its retry chrome.\n return new LlmError(\n `Command Code API error 401 (${detail}): the API key is missing or invalid — check the`\n + ' key stored for COMMANDCODE_API_KEY (Models page) or the auth file'\n + ';Command Code API 返回 401:API 密钥缺失或无效——请在设置页检查 COMMANDCODE_API_KEY 存储的密钥,或检查 auth 文件',\n 'INVALID_CREDENTIAL',\n { status: 401 },\n )\n }\n if (status === 413) {\n // Request-body cap (issue #37). Command Code documents no 413 at all, so\n // without this branch the reader sees a bare \"HTTP 413\" and no way to tell\n // it apart from a generic provider failure. Reaching here means the\n // adapter already dropped this request's oldest images as far as its\n // budget ladder allows, or the body is large without images at all, so\n // the advice is the only remaining lever the user has. Bilingual — the\n // harness UI renders this message verbatim in its retry chrome.\n return new LlmError(\n 'Command Code API error 413: the request body exceeds the provider\\'s size limit'\n + ' (the cap is undocumented, measured at about 50 MB) — the session history is too large'\n + ' to send, usually because of accumulated image attachments. Start a new session, or'\n + ' drop the image-heavy part of this one, and retry'\n + ';Command Code API 返回 413:请求体超过服务端的体积上限(官方未公开,实测约 50 MB)'\n + '——会话历史过大,通常是历史图片累积所致。请新建会话,或移除本会话中图片较多的部分后重试',\n 'PROVIDER_HTTP_ERROR',\n { status: 413 },\n )\n }\n return new LlmError(\n `Command Code API error ${status}${detail === `HTTP ${status}` ? '' : ` (${detail})`}: ${errText.slice(0, 500)}`,\n httpErrorCode(status),\n {\n status,\n ...(retryAfterMs !== undefined && retryAfterMs > 0 && retryAfterMs <= RETRY_MAX_DELAY_MS\n ? { providerRetryAfterMs: retryAfterMs }\n : {}),\n },\n )\n}\n\n/**\n * Classify a pre-stream HTTP status into the failure code the route's retry\n * policy keys on. dsh-llm-retry matches `retryableCodes` only — never the\n * status, never the provider's `error.type` — so a status that arrives here as\n * a permanent code is never retried, whatever it says about itself.\n *\n * 5xx is the provider's own \"we are temporarily unavailable\" class (Cloudflare's\n * 520-527 included; a 520 body says exactly that in words) and the only sane\n * answer to it is the byte-identical resend the retry policy exists to make.\n * Keeping it on `PROVIDER_HTTP_ERROR` — absent from the whitelist by design, so\n * that a 403 plan rejection or a 400 shape error fails fast — made the one\n * failure that asks to be retried the only one that never was, while the same\n * status arriving as an in-band stream `error` event was classified retryable\n * `SERVER` (see the `error` case of {@link handleCliEvent}). 408 is the same\n * story for the request itself. Everything else stays permanent: a 400/403/404/\n * 409/422 rejection repeats identically on every attempt.\n */\nfunction httpErrorCode(status: number): string {\n if (status === 429) return 'RATE_LIMIT'\n if (status === 408) return 'TIMEOUT'\n if (status >= 500) return 'SERVER'\n return 'PROVIDER_HTTP_ERROR'\n}\n\n\n/**\n * Handle one CLI-transport (`/alpha/generate`) stream event, appending\n * harness StreamChunks. Pure over the passed assembler — no stream() locals.\n */\nfunction handleCliEvent(asm: BlockAssembler, event: unknown): StreamChunk[] {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n\n switch (event.type) {\n case 'text-delta': {\n chunks.push(...closeReasoning(asm))\n if (asm.textIndex < 0) {\n asm.textIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.textIndex, blockType: 'text' })\n }\n const delta = stringValue(event.text) ?? ''\n asm.textContent += delta\n asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: delta })\n break\n }\n case 'reasoning-delta': {\n chunks.push(...closeText(asm))\n if (asm.reasoningIndex < 0) {\n asm.reasoningIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.reasoningIndex, blockType: 'reasoning' })\n }\n const delta = stringValue(event.text) ?? ''\n asm.reasoningContent += delta\n chunks.push({ type: 'reasoning-delta', index: asm.reasoningIndex, text: delta })\n break\n }\n case 'reasoning-start':\n chunks.push(...closeText(asm))\n break\n case 'reasoning-end':\n chunks.push(...closeReasoning(asm))\n break\n case 'tool-call': {\n chunks.push(...closeText(asm), ...closeReasoning(asm))\n const id = stringValue(event.toolCallId) ?? randomUUID()\n const name = stringValue(event.toolName) ?? ''\n const args = JSON.stringify(recordOrEmpty(event.input ?? event.args ?? event.arguments))\n const index = asm.nextIndex++\n asm.sawContent = true\n chunks.push(\n { type: 'block-start', index, blockType: 'tool-call' },\n { type: 'tool-call-delta', index, id: ToolCallId(id), name, argumentsDelta: args },\n {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: ToolCallId(id), name, arguments: args },\n },\n )\n break\n }\n case 'finish': {\n chunks.push(...closeText(asm), ...closeReasoning(asm))\n const usage = isRecord(event.totalUsage) ? event.totalUsage : undefined\n if (usage) {\n const details = isRecord(usage.inputTokenDetails) ? usage.inputTokenDetails : undefined\n const totalInput = numberValue(usage.inputTokens) ?? 0\n const cacheRead = numberValue(details?.cacheReadTokens) ?? 0\n const cacheWrite = numberValue(details?.cacheWriteTokens) ?? 0\n // Harness TokenUsage counts are disjoint: uncached input only.\n const tokenUsage: TokenUsage = {\n inputTokens:\n numberValue(details?.noCacheTokens) ?? Math.max(0, totalInput - cacheRead - cacheWrite),\n outputTokens: numberValue(usage.outputTokens) ?? 0,\n cacheReadTokens: cacheRead,\n cacheWriteTokens: cacheWrite,\n }\n chunks.push({ type: 'usage', usage: tokenUsage })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(event.finishReason) })\n break\n }\n case 'error': {\n // Classification lives in streamErrorToLlmError, shared with the\n // Provider API transport's own in-band error member so the two cannot\n // drift: a stream error that is explicitly non-retryable, carries a\n // terminal marker (quota/plan/credits), or reports a non-retryable HTTP\n // status is a hard failure, and a context-window rejection is the\n // harness's CONTEXT_WINDOW_EXCEEDED (compact and retry). Anything else\n // is a transient mid-stream drop the retry policy should repeat.\n throw streamErrorToLlmError(event.error, stringValue(event.message))\n }\n }\n return chunks\n}\n\n/**\n * Handle one OpenAI-transport (`/provider/v1/chat/completions`) SSE event.\n * Same assembler contract as {@link handleCliEvent}; tool-call fragments\n * buffer on the assembler and flush at finish.\n */\nfunction handleOpenAIEvent(asm: BlockAssembler, event: unknown): StreamChunk[] {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n // The Provider API transport reports a mid-stream failure as an `error`\n // member of an SSE chunk rather than as an event type of its own. Ignoring\n // it — as this handler used to — let the stream end with no finish event, so\n // a context-window or quota rejection surfaced only as a generic\n // EMPTY_RESPONSE (which the retry policy repeats) and the real cause was\n // lost. Route it through the classifier the CLI transport uses.\n if (event.error !== undefined) throw streamErrorToLlmError(event.error, stringValue(event.message))\n const choices = event.choices\n if (!Array.isArray(choices) || choices.length === 0) {\n // A standalone usage chunk (some OpenAI-compatible servers send it\n // before [DONE]) still carries usage.\n if (event.usage !== undefined) {\n chunks.push({ type: 'usage', usage: mapOpenAIUsage(event.usage) })\n }\n return chunks\n }\n const choice = isRecord(choices[0]) ? choices[0] : {}\n const delta = isRecord(choice.delta) ? choice.delta : {}\n\n // Thinking text arrives under a different field per model family, and the\n // gateway does not normalize the spelling: DeepSeek answers with the scalar\n // `reasoning` PLUS an OpenRouter-shaped `reasoning_details` array, while\n // GLM/Qwen/Kimi answer with the DeepSeek-native `reasoning_content`. All\n // three are read here, in that order, so no family's thinking is dropped —\n // measured against the live API 2026-09-16 (see `MESSAGES_ONLY_MODELS` for\n // the same sweep's other finding). The `reasoning_details` branch is a\n // forward guard rather than a live path today: DeepSeek always sends the\n // scalar alongside it, so it only carries the text if that ever stops.\n const reasoningDelta =\n stringValue(delta.reasoning)\n ?? stringValue(delta.reasoning_content)\n ?? reasoningDetailsText(delta.reasoning_details)\n ?? ''\n if (reasoningDelta !== '') {\n chunks.push(...closeText(asm))\n if (asm.reasoningIndex < 0) {\n asm.reasoningIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.reasoningIndex, blockType: 'reasoning' })\n }\n asm.reasoningContent += reasoningDelta\n chunks.push({ type: 'reasoning-delta', index: asm.reasoningIndex, text: reasoningDelta })\n }\n\n const contentDelta = stringValue(delta.content) ?? ''\n if (contentDelta !== '') {\n chunks.push(...closeReasoning(asm))\n if (asm.textIndex < 0) {\n asm.textIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.textIndex, blockType: 'text' })\n }\n asm.textContent += contentDelta\n asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: contentDelta })\n }\n\n if (Array.isArray(delta.tool_calls)) {\n asm.sawContent = true\n for (const rawCall of delta.tool_calls) {\n if (!isRecord(rawCall)) continue\n const callIndex = numberValue(rawCall.index) ?? 0\n let existing = asm.openAiToolCalls.find((call) => call.index === callIndex)\n const fn = isRecord(rawCall.function) ? rawCall.function : undefined\n const id = stringValue(rawCall.id)\n const name = fn === undefined ? undefined : stringValue(fn.name)\n const argDelta = fn === undefined\n ? undefined\n : (stringValue(fn.arguments) ?? (fn.arguments === undefined ? '' : JSON.stringify(fn.arguments)))\n if (!existing) {\n existing = {\n index: callIndex,\n name: name ?? '',\n arguments: argDelta ?? '',\n }\n if (id !== undefined) existing.id = id\n asm.openAiToolCalls.push(existing)\n } else {\n if (id !== undefined && existing.id === undefined) existing.id = id\n if (name !== undefined && existing.name === '') existing.name = name\n if (argDelta !== undefined) existing.arguments += argDelta\n }\n }\n }\n\n if (choice.finish_reason !== undefined && choice.finish_reason !== null) {\n chunks.push(...closeText(asm), ...closeReasoning(asm), ...emitOpenAiToolCalls(asm))\n if (event.usage !== undefined) {\n chunks.push({ type: 'usage', usage: mapOpenAIUsage(event.usage) })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(choice.finish_reason) })\n }\n return chunks\n}\n\n/** Dispatch one parsed stream event to the active transport's handler. */\nfunction handleEvent(asm: BlockAssembler, protocol: CommandCodeProtocol, event: unknown): StreamChunk[] {\n return protocol === 'openai' ? handleOpenAIEvent(asm, event) : handleCliEvent(asm, event)\n}\n\n\n/**\n * Parse an HTTP `Retry-After` value (delay-seconds or an HTTP-date) into\n * milliseconds; undefined when absent or unparseable. An HTTP-date in the\n * past yields 0, which the caller drops (LlmError wants a positive delay).\n * A delay-seconds value whose millisecond product is not finite (e.g. `1e308`)\n * also yields undefined: LlmError validates its options and would otherwise\n * replace the provider failure with an internal construction error.\n */\nfunction parseRetryAfterMs(value: string | null | undefined, now = Date.now()): number | undefined {\n if (value === undefined || value === null) return undefined\n const trimmed = value.trim()\n if (trimmed === '') return undefined\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n const ms = seconds * 1000\n return Number.isFinite(ms) ? Math.round(ms) : undefined\n }\n const date = Date.parse(trimmed)\n if (!Number.isNaN(date)) return Math.max(0, date - now)\n return undefined\n}\n\n/**\n * Map a stream finish reason onto the harness taxonomy. The two transports\n * spell tool-calls differently (`tool-calls` on the CLI transport,\n * `tool_calls` on the OpenAI transport) but share every other reason, so\n * one function serves both — a new reason cannot drift between them.\n */\nfunction mapFinishReason(reason: unknown): FinishReason {\n if (reason === 'tool-calls' || reason === 'tool_calls') return { kind: 'tool-calls' }\n if (\n reason === 'length' ||\n reason === 'max_tokens' ||\n reason === 'max-tokens' ||\n reason === 'max_output_tokens'\n ) {\n return { kind: 'max-tokens' }\n }\n return { kind: 'stop' }\n}\n\n/**\n * True when a Provider API pre-stream rejection is Command Code's Go-plan\n * gate (`upgrade_required`). Only this exact class of rejection should fall\n * back to the CLI /alpha/generate transport; other 4xx/5xx must surface as\n * ordinary errors so real account/model problems are not masked.\n */\nfunction isUpgradeRequiredError(status: number, errText: string): boolean {\n if (status !== 403) return false\n const lower = errText.toLowerCase()\n if (lower.includes('upgrade_required')) return true\n if (lower.includes('go plan') && lower.includes('api access')) return true\n if (lower.includes('only plan without api access')) return true\n if (lower.includes('upgrade to goat or higher')) return true\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed)) {\n const error = isRecord(parsed.error) ? parsed.error : parsed\n const code = stringValue(error.code) ?? stringValue(error.type)\n if (code?.toLowerCase() === 'upgrade_required') return true\n const message = stringValue(error.message) ?? ''\n if (message.toLowerCase().includes('go plan') && message.toLowerCase().includes('api access')) return true\n }\n } catch {\n // Already handled via the plain-text substring checks above.\n }\n return false\n}\n\n/** Map an OpenAI Chat Completions usage payload to harness disjoint counts. */\nfunction mapOpenAIUsage(usage: unknown): TokenUsage {\n const source = isRecord(usage) ? usage : {}\n const promptTokens = numberValue(source.prompt_tokens) ?? 0\n const outputTokens = numberValue(source.completion_tokens) ?? 0\n const totalTokens = numberValue(source.total_tokens)\n const promptDetails = isRecord(source.prompt_tokens_details) ? source.prompt_tokens_details : undefined\n const cacheRead = numberValue(promptDetails?.cached_tokens) ?? 0\n const cacheWrite = numberValue(promptDetails?.cache_creation_input_tokens) ?? 0\n const completionDetails = isRecord(source.completion_tokens_details) ? source.completion_tokens_details : undefined\n const reasoningTokens = numberValue(completionDetails?.reasoning_tokens)\n const usageOut: TokenUsage = {\n inputTokens: Math.max(0, promptTokens - cacheRead - cacheWrite),\n outputTokens,\n cacheReadTokens: cacheRead,\n }\n if (cacheWrite > 0) usageOut.cacheWriteTokens = cacheWrite\n if (reasoningTokens !== undefined) usageOut.reasoningTokens = reasoningTokens\n if (totalTokens !== undefined) usageOut.totalTokens = totalTokens\n return usageOut\n}\n","/**\n * Locale copy for the `/commandcode` usage command and the friendly\n * image-gate error rewrite. Distinct from `./client/locales.ts` (the\n * settings-page namespace `settings.commandcode`): the command runs on the\n * Host and has no access to the client's `ctx.locale`, so the dictionaries\n * are exposed as plain constants for direct lookup; the resolver lives in\n * `pickCommandLocale()`. The image-gate wrapper also lives on the client\n * but is reached from a non-React path that has no `t` in scope, so the\n * same dictionaries serve both surfaces.\n *\n * zh is the source of truth for the key set; en must carry the exact same\n * keys — a mismatch is a compile error at the lookup site.\n */\n\n/** Active locale id recognized by the command and the image-gate wrapper. */\nexport type LocaleId = 'zh' | 'en'\n\n/** Dictionary keys used by the `/commandcode` command and the image-gate wrapper. */\nexport type CommandCodeCommandKey =\n | 'title' // top heading of a single-account report\n | 'accountTitle' // per-account heading in the multi-account view\n | 'accountSeparator' // rule between accounts in the multi-account view\n | 'activeBadge' // \"currently serving\" badge\n | 'invalidCredentialBadge' // mark for an account whose key is invalid\n | 'cooldownBadge' // mark for an account in rate-limit cooldown\n | 'rateLimitBadge' // mark when the pool has marked a key rate-limited\n | 'unconfigured' // one-account row when the slot has no key\n | 'blockedInvalidKey' // top-of-report block when the whole account is 401\n | 'blockedServiceUnavailable' // 5xx\n | 'blockedNetwork' // network unreachable\n | 'planLine' // \" 📦 套餐 {name}{status}{period}\"\n | 'planPeriodSuffix' // \" · 账期截止 {date}\" / \" · period ends {date}\"\n | 'usageHeader' // \"── 请求 ─────...\"\n | 'requestsLine' // \" 💬 请求 {n} 次 / 失败 {f} 成功率 {r}%\"\n | 'costLine' // \" 💰 花费 {money} ({credits} credits)\"\n | 'tokensLine' // \" 🔤 Token {in} 入 / {out} 出\"\n | 'creditsHeader' // \"── 信用 ─────...\"\n | 'monthlyLine' // \" 💳 月额度 {monthly} (已购 {purchased} / 赠送 {free})\"\n | 'barLine' // \" └ {bar} {pct}%\"\n | 'windowsHeader' // \"── 窗口用量 ─────...\"\n | 'fiveHourLine' // \" ⏱ 5 小时 {used} / {cap}{warn}\"\n | 'weeklyLine' // \" 📅 每周 {used} / {cap}{warn}\"\n | 'windowBarLine' // \" └ {bar} 重置 {when}\"\n | 'exceededWarning' // the trailing \" ⚠️ 超限!\" / \" ⚠️ exceeded!\"\n | 'resetSuffix' // \"重置 {when}\" (the suffix after the bar)\n | 'partialFailures' // \"⚠️ 部分端点失败: {list}\"\n | 'noData' // \"(no data — check your API key)\"\n | 'errorText' // \"Could not fetch Command Code usage: {message}\"\n\nexport const commandcodeCommand: Record<LocaleId, Record<CommandCodeCommandKey, string>> = {\n zh: {\n title: '📊 Command Code 用量{account}',\n accountTitle: '📊 {label}{badges}',\n accountSeparator: '────────────────────',\n activeBadge: ' ✅ 当前使用',\n invalidCredentialBadge: ' ⛔ 密钥无效',\n cooldownBadge: ' ⏳ 限额冷却中,重置 {when}',\n rateLimitBadge: ' ⏳ 已达限额(等待窗口探测)',\n unconfigured: ' (未配置 API 密钥)',\n blockedInvalidKey:\n '⛔ API 密钥无效或已过期 — 服务端拒绝了全部请求(401),请检查该账户的密钥配置',\n blockedServiceUnavailable:\n '⚠️ Command Code 服务暂时不可用(5xx),稍后重试',\n blockedNetwork:\n '⚠️ 无法连接 Command Code 服务 — 请检查网络或 API 地址',\n planLine: ' 📦 套餐 {name}{status}{period}',\n planPeriodSuffix: ' · 账期截止 {date}',\n usageHeader: '── 请求 ──────────────────────────────',\n requestsLine: ' 💬 请求 {n} 次 / 失败 {f} 成功率 {r}%',\n costLine: ' 💰 花费 {money} ({credits} credits)',\n tokensLine: ' 🔤 Token {in} 入 / {out} 出',\n creditsHeader: '── 信用 ──────────────────────────────',\n monthlyLine: ' 💳 月额度 {monthly} (已购 {purchased} / 赠送 {free})',\n barLine: ' └ {bar} {pct}%',\n windowsHeader: '── 窗口用量 ──────────────────────────',\n fiveHourLine: ' ⏱ 5 小时 {used} / {cap}{warn}',\n weeklyLine: ' 📅 每周 {used} / {cap}{warn}',\n windowBarLine: ' └ {bar} 重置 {when}',\n exceededWarning: ' ⚠️ 超限!',\n resetSuffix: '重置 {when}',\n partialFailures: '⚠️ 部分端点失败: {list}',\n noData: '(无数据 — 请检查 API 密钥)',\n errorText: '获取 Command Code 用量失败:{message}',\n },\n en: {\n title: '📊 Command Code usage{account}',\n accountTitle: '📊 {label}{badges}',\n accountSeparator: '────────────────────',\n activeBadge: ' ✅ active',\n invalidCredentialBadge: ' ⛔ invalid key',\n cooldownBadge: ' ⏳ cooling down, resets {when}',\n rateLimitBadge: ' ⏳ rate-limited (waiting for window probe)',\n unconfigured: ' (no API key configured)',\n blockedInvalidKey:\n '⛔ API key invalid or expired — the server rejected every request (401); check the key configured for this account',\n blockedServiceUnavailable:\n '⚠️ Command Code service temporarily unavailable (5xx); try again later',\n blockedNetwork:\n '⚠️ could not reach the Command Code service — check your network or the API base setting',\n planLine: ' 📦 Plan {name}{status}{period}',\n planPeriodSuffix: ' · period ends {date}',\n usageHeader: '── Requests ──────────────────────────',\n requestsLine: ' 💬 Requests {n} / failed {f} success rate {r}%',\n costLine: ' 💰 Spend {money} ({credits} credits)',\n tokensLine: ' 🔤 Tokens {in} in / {out} out',\n creditsHeader: '── Credits ───────────────────────────',\n monthlyLine: ' 💳 Monthly {monthly} (purchased {purchased} / free {free})',\n barLine: ' └ {bar} {pct}%',\n windowsHeader: '── Window usage ──────────────────────',\n fiveHourLine: ' ⏱ 5-hour {used} / {cap}{warn}',\n weeklyLine: ' 📅 Weekly {used} / {cap}{warn}',\n windowBarLine: ' └ {bar} resets {when}',\n exceededWarning: ' ⚠️ exceeded!',\n resetSuffix: 'resets {when}',\n partialFailures: '⚠️ some endpoints failed: {list}',\n noData: '(no data — check your API key)',\n errorText: 'Could not fetch Command Code usage: {message}',\n },\n}\n\n/**\n * Resolve the active locale for a Host-side command run.\n *\n * Priority: explicit `override` (from `Config.lang`) → `LC_ALL` → `LANG` →\n * the conventional fallback (`'zh'`, matching the existing single-language\n * behavior so unconfigured deployments keep their current output).\n *\n * The values are matched on the leading tag only — `zh_CN.UTF-8`,\n * `zh-Hans`, `zh` all map to `'zh'`; everything starting with `en` maps to\n * `'en'`; anything else falls back to `'zh'` (a non-`en` shell that\n * already has Chinese in the terminal is the closest sensible default;\n * a Western shell that happens to be neither keeps the existing Chinese\n * output rather than swapping to half-translated English).\n */\nexport function pickCommandLocale(\n override: string | undefined,\n env: Readonly<Record<string, string | undefined>> = process.env as Record<string, string | undefined>,\n): LocaleId {\n if (override === 'zh' || override === 'en') return override\n const raw = env.LC_ALL ?? env.LANG ?? ''\n const tag = raw.toLowerCase().split(/[._-]/)[0] ?? ''\n if (tag === 'en') return 'en'\n return 'zh'\n}\n\n/** Look up a key in the active locale, with an internal en fallback. */\nexport function commandCopy(locale: LocaleId, key: CommandCodeCommandKey): string {\n return commandcodeCommand[locale][key] ?? commandcodeCommand.en[key] ?? key\n}\n","/**\n * `/commandcode` slash command — account usage dashboard.\n *\n * /commandcode show account, usage, and credit state\n * /commandcode status same as bare `/commandcode`\n *\n * Backed by the Command Code account endpoints the official CLI uses\n * (`/alpha/whoami`, `/alpha/usage/summary`, `/alpha/billing/credits`),\n * exposed through `CommandCodeAdapter.getUsage()`.\n *\n * The command is Host-side and has no access to the client's `ctx.locale`;\n * the active locale is resolved through `deps.getLocale()` (supplied by the\n * plugin entry from `Config.lang` and the shell's `LC_ALL`/`LANG`, defaulting\n * to `zh`). All user-facing copy lives in `./command-locales.ts`; a missing\n * key in one dictionary falls back to the `en` copy rather than dropping\n * text.\n *\n * @module dsh-commandcode-provider/commands\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only import that loads the module augmentation (`ctx.commands`).\nimport type { CommandDefinition } from '@deepseek-ai/dsh-commands'\nimport { CommandCodeAdapter } from './adapter.ts'\nimport type { CommandCodeConnectionOptions, CommandCodeUsageReport } from './adapter.ts'\nimport type { CommandCodeAccountUsage, CommandCodeAccountsReport } from './usage-wire.ts'\nimport { commandCopy, type LocaleId } from './command-locales.ts'\n\n/** Everything the command needs beyond the adapter itself. */\nexport interface CommandCodeCommandDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** The registered adapter (for getUsage / listModels). */\n adapter: CommandCodeAdapter<C>\n /**\n * Multi-account report source (wired by the plugin entry). Absent in\n * programmatic setups, the command falls back to a single\n * `adapter.getUsage()` report.\n */\n reports?: () => Promise<CommandCodeAccountsReport>\n /**\n * Resolve the active locale for one command run. The plugin entry wires\n * this from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent in\n * programmatic setups (notably the existing test), the command renders\n * with the default locale (`'zh'`) — historically the only language the\n * command ever shipped in.\n */\n getLocale?: () => LocaleId\n}\n\n// ---------------------------------------------------------------------------\n// Number / time formatting (locale-independent; the locale only changes\n// the surrounding labels)\n// ---------------------------------------------------------------------------\n\n/** Format a dollar amount. */\nfunction money(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\n/** Format a dollar amount compactly (2 decimals). */\nfunction moneyShort(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\n/** Format a large token count compactly (1.9M style). */\nfunction tokensCompact(value: number): string {\n if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`\n if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`\n if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`\n return String(value)\n}\n\n/**\n * Format a success-rate percentage (already in percent units): at most two\n * decimals, trailing zeros trimmed — mirrors `formatSuccessRate` in\n * `./client/usage.ts`, which the settings card uses.\n */\nfunction successRateText(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** Format a millis timestamp as a local date; `n/a` when unset. */\nfunction resetLabel(ms: number): string {\n if (ms <= 0) return 'n/a'\n return new Date(ms).toLocaleString()\n}\n\n/**\n * A 10-cell horizontal bar: `██████████` for 100%, `███░░░░░░░` for ~33%.\n * Handles caps of 0 (no limit) and out-of-range values.\n */\nfunction bar(used: number, cap: number): string {\n if (cap <= 0) return '—'\n const ratio = Math.max(0, Math.min(1, used / cap))\n const filled = Math.round(ratio * 10)\n return '█'.repeat(filled) + '░'.repeat(10 - filled)\n}\n\n// ---------------------------------------------------------------------------\n// Report rendering\n// ---------------------------------------------------------------------------\n\n/** Render one account's rotation mark / cooldown as a short badge. */\nfunction markLabel(entry: CommandCodeAccountUsage, locale: LocaleId): string {\n if (entry.mark === 'invalid-credential') return commandCopy(locale, 'invalidCredentialBadge')\n if (entry.cooldownUntil > 0) {\n return commandCopy(locale, 'cooldownBadge').replace('{when}', resetLabel(entry.cooldownUntil))\n }\n if (entry.mark === 'rate-limit') return commandCopy(locale, 'rateLimitBadge')\n return ''\n}\n\n/** Render the usage report as a structured, aligned, bar-chart text view. */\nfunction renderReport(report: CommandCodeUsageReport, locale: LocaleId, title?: string): string {\n const lines: string[] = []\n const account = report.account ? ` (${report.account.userName || report.account.name})` : ''\n\n lines.push(\n title ?? commandCopy(locale, 'title').replace('{account}', account),\n '',\n )\n\n // A total failure names its cause up front; the per-endpoint failure list\n // at the bottom would bury it.\n if (report.blocked === 'invalid-key') {\n lines.push(commandCopy(locale, 'blockedInvalidKey'), '')\n } else if (report.blocked === 'service-unavailable') {\n lines.push(commandCopy(locale, 'blockedServiceUnavailable'), '')\n } else if (report.blocked === 'network') {\n lines.push(commandCopy(locale, 'blockedNetwork'), '')\n }\n\n if (report.plan && report.plan.name !== '') {\n const p = report.plan\n const status = p.status !== '' && p.status !== 'active' ? ` (${p.status})` : ''\n const period = p.currentPeriodEnd > 0\n ? commandCopy(locale, 'planPeriodSuffix').replace('{date}', new Date(p.currentPeriodEnd).toLocaleDateString())\n : ''\n lines.push(commandCopy(locale, 'planLine')\n .replace('{name}', p.name)\n .replace('{status}', status)\n .replace('{period}', period), '')\n }\n\n if (report.usage) {\n const u = report.usage\n lines.push(\n commandCopy(locale, 'usageHeader'),\n commandCopy(locale, 'requestsLine')\n .replace('{n}', String(u.completedCount))\n .replace('{f}', String(u.failedCount))\n .replace('{r}', successRateText(u.successRate)),\n commandCopy(locale, 'costLine')\n .replace('{money}', money(u.totalCost))\n .replace('{credits}', moneyShort(u.totalCredits)),\n commandCopy(locale, 'tokensLine')\n .replace('{in}', tokensCompact(u.totalTokensIn))\n .replace('{out}', tokensCompact(u.totalTokensOut)),\n '',\n )\n }\n\n if (report.credits) {\n const c = report.credits\n const balanceTotal = c.monthlyCredits + c.purchasedCredits\n const ratioKnown = c.monthlyReported !== false && c.purchasedReported !== false && balanceTotal > 0\n lines.push(\n commandCopy(locale, 'creditsHeader'),\n commandCopy(locale, 'monthlyLine')\n .replace('{monthly}', (c.monthlyReported === false ? '—' : moneyShort(c.monthlyCredits)))\n .replace('{purchased}', (c.purchasedReported === false ? '—' : moneyShort(c.purchasedCredits)))\n .replace('{free}', (c.freeReported === false ? '—' : moneyShort(c.freeCredits))),\n ...(ratioKnown ? [commandCopy(locale, 'barLine')\n .replace('{bar}', bar(c.monthlyCredits, balanceTotal))\n .replace('{pct}', ((c.monthlyCredits / balanceTotal) * 100).toFixed(0))] : []),\n '',\n )\n // Only the windows the endpoint actually reported: an unlimited account\n // reports none, and printing two zeroed rows for it would invent limits.\n const windowLines: string[] = []\n if (c.fiveHour !== undefined) {\n windowLines.push(\n commandCopy(locale, 'fiveHourLine')\n .replace('{used}', moneyShort(c.fiveHour.used))\n .replace('{cap}', moneyShort(c.fiveHour.cap))\n .replace('{warn}', c.fiveHour.exceeded ? commandCopy(locale, 'exceededWarning') : ''),\n commandCopy(locale, 'windowBarLine')\n .replace('{bar}', bar(c.fiveHour.used, c.fiveHour.cap))\n .replace('{when}', resetLabel(c.fiveHour.resetAt)),\n )\n }\n if (c.weekly !== undefined) {\n windowLines.push(\n commandCopy(locale, 'weeklyLine')\n .replace('{used}', moneyShort(c.weekly.used))\n .replace('{cap}', moneyShort(c.weekly.cap))\n .replace('{warn}', c.weekly.exceeded ? commandCopy(locale, 'exceededWarning') : ''),\n commandCopy(locale, 'windowBarLine')\n .replace('{bar}', bar(c.weekly.used, c.weekly.cap))\n .replace('{when}', resetLabel(c.weekly.resetAt)),\n )\n }\n if (windowLines.length > 0) lines.push(commandCopy(locale, 'windowsHeader'), ...windowLines, '')\n }\n\n if (report.failures.length > 0) {\n lines.push(commandCopy(locale, 'partialFailures').replace('{list}', report.failures.join('; ')), '')\n }\n if (!report.account && !report.usage && !report.credits) {\n lines.push(commandCopy(locale, 'noData'), '')\n }\n\n return lines.join('\\n').trimEnd()\n}\n\n/** The one registered `/commandcode` command. */\nexport function commandDefinition<C extends CommandCodeConnectionOptions>(\n deps: CommandCodeCommandDeps<C>,\n): CommandDefinition {\n const { adapter } = deps\n return {\n name: 'commandcode',\n description: 'Command Code account usage dashboard',\n input: { hint: '[status]' },\n handler: async () => {\n const locale: LocaleId = deps.getLocale?.() ?? 'zh'\n try {\n if (deps.reports !== undefined) {\n const { accounts } = await deps.reports()\n const sections = accounts.map((entry) => {\n const badges = `${entry.active ? commandCopy(locale, 'activeBadge') : ''}${markLabel(entry, locale)}`\n const title = commandCopy(locale, 'accountTitle')\n .replace('{label}', entry.label)\n .replace('{badges}', badges)\n if (!entry.configured) return `${title}\\n\\n${commandCopy(locale, 'unconfigured')}`\n return renderReport(entry.report, locale, title)\n })\n return { kind: 'success', text: sections.join(`\\n\\n${commandCopy(locale, 'accountSeparator')}\\n\\n`) }\n }\n const report = await adapter.getUsage()\n return { kind: 'success', text: renderReport(report, locale) }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n kind: 'error',\n text: commandCopy(locale, 'errorText').replace('{message}', message),\n }\n }\n },\n }\n}\n\n/** Register the command on `ctx.commands` (called from the plugin entry). */\nexport function applyCommands<C extends CommandCodeConnectionOptions>(\n ctx: Context,\n deps: CommandCodeCommandDeps<C>,\n): void {\n ctx.commands.register(commandDefinition(deps))\n}\n","/**\n * Shared boundary-validation and Remote-descriptor plumbing for the plugin's\n * hand-rolled Typert wire contracts (`commandcode/report`, `commandcode/models`,\n * `commandcode/login*`).\n *\n * Every Remote this plugin serves crosses the Typert Gateway with a strict\n * result schema: the Host half registers a descriptor against a Cordis service\n * (`src/usage-remote.ts`) and the browser half mounts the matching contribution\n * on `ctx.remote` (`src/client/index.ts`). The wire contract is deliberately\n * dependency-free so the client bundle can inline it — a pure-TS helper module\n * imported by the wire files keeps it that way while removing the schema\n * helpers and descriptor boilerplate they used to duplicate.\n *\n * @module dsh-commandcode-provider/wire-shared\n */\n\nimport type { InvocationDescriptor, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\n\n/** The npm package identity every contribution and descriptor claims. */\nexport const REMOTE_PACKAGE = '@mars-sea/dsh-commandcode-provider'\n\n/** The Cordis service key the Gateway resolves every Command Code Remote from. */\nexport const REMOTE_SERVICE = 'commandcodeUsage'\n\n/** The wire namespace all Command Code endpoints share. */\nexport const REMOTE_NAMESPACE = 'commandcode'\n\n/** The read/validate helpers one boundary codec needs. */\nexport interface BoundaryValidator {\n /** Reject one boundary value with a field-naming error. */\n reject(field: string): never\n /** Narrow an unknown value to a plain record, or reject. */\n record(value: unknown, field: string): Record<string, unknown>\n /** Read one required string field (`field` is the dotted error label). */\n stringField(source: Record<string, unknown>, key: string, field: string): string\n /** Read one required finite number field (`field` is the dotted error label). */\n numberField(source: Record<string, unknown>, key: string, field: string): number\n /** Read one required boolean field (`field` is the dotted error label). */\n booleanField(source: Record<string, unknown>, key: string, field: string): boolean\n}\n\n/**\n * Build the validator helpers one endpoint uses. `prefix` names the\n * endpoint in the rejection message (e.g. `commandcode/report result:`), so\n * each wire file keeps its own diagnostic phrasing while sharing the helper\n * bodies.\n *\n * The helpers return the reject call directly in the failure branch: since\n * `reject` is typed `never`, the ternary's union collapses to the success type\n * without relying on TypeScript's control-flow analysis of a never-returning\n * call (which only recognizes function declarations, not the destructured\n * arrow `reject` callers receive from this factory).\n */\nexport function makeBoundaryValidator(prefix: string): BoundaryValidator {\n const reject = (field: string): never => {\n throw new TypeError(`${prefix} invalid ${field}`)\n }\n const record = (value: unknown, field: string): Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : reject(field)\n const stringField = (source: Record<string, unknown>, key: string, field: string): string =>\n typeof source[key] === 'string' ? source[key] as string : reject(field)\n const numberField = (source: Record<string, unknown>, key: string, field: string): number =>\n typeof source[key] === 'number' && Number.isFinite(source[key] as number)\n ? source[key] as number\n : reject(field)\n const booleanField = (source: Record<string, unknown>, key: string, field: string): boolean =>\n typeof source[key] === 'boolean' ? source[key] as boolean : reject(field)\n return { reject, record, stringField, numberField, booleanField }\n}\n\n/**\n * Build one strict invocation descriptor. Every Command Code Remote shares the\n * `commandcode` namespace, the `commandcodeUsage` service, and a strict\n * `mode: 'strict'` result — only the endpoint, method, result type symbol, and\n * schema differ — so the boilerplate lives here once and each endpoint supplies\n * only its own facts.\n */\nexport function makeRemoteDescriptor<Output>(\n endpoint: string,\n method: string,\n typeSymbol: string,\n schema: TypertSchema<Output>,\n): InvocationDescriptor {\n return {\n id: `${REMOTE_PACKAGE}#${endpoint}`,\n service: REMOTE_SERVICE,\n namespace: REMOTE_NAMESPACE,\n method,\n invocation: { kind: 'direct' },\n parameters: [],\n result: {\n mode: 'strict',\n typeSymbol,\n schema,\n },\n }\n}","/**\n * Wire contract for the Command Code account-usage Remote\n * (`commandcode/report`).\n *\n * The settings page renders the same account/usage/credit facts the\n * `/commandcode` command prints, but the browser never holds the API key —\n * the report must be produced Host-side and cross the Connection RPC carrier.\n * The harness exposes plugin-defined Host methods through the Typert Gateway:\n * the Host half registers a strict invocation descriptor against a Cordis\n * service (`src/usage-remote.ts`), and the browser half mounts the matching\n * Remote contribution on `ctx.remote` (`src/client/index.ts`).\n *\n * This module is the single source both halves share: the result validator\n * (a hand-rolled {@link TypertSchema}, so neither half needs a schema library)\n * and the exact descriptor object, so the endpoint can never drift apart.\n * It is deliberately dependency-free — the client bundle inlines it, and only\n * `import type` edges leave it (erased at build). The boundary-validator\n * helpers and the descriptor boilerplate live in `./wire-shared.ts`, shared\n * with the login wire contract.\n *\n * @module dsh-commandcode-provider/usage-wire\n */\n\nimport type { CommandCodeCredits, CommandCodeUsageReport, UsageBlockReason } from './adapter.ts'\n\nexport type { CommandCodeUsageReport, UsageBlockReason }\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** One account's usage entry in the multi-account report. */\nexport interface CommandCodeAccountUsage {\n /** Stable slot id (`default`, `account-2`, …). */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Whether an API key resolved for this account. */\n configured: boolean\n /** Whether this account currently serves requests (first usable slot). */\n active: boolean\n /** Rotation mark: `''` (usable), `'rate-limit'`, or `'invalid-credential'`. */\n mark: string\n /** Known cooldown end in millis; 0 when unknown or not cooling down. */\n cooldownUntil: number\n /** The per-account report; `failures`-only when the fetch itself failed. */\n report: CommandCodeUsageReport\n}\n\n/** The settings page's account card data: one entry per configured account. */\nexport interface CommandCodeAccountsReport {\n accounts: CommandCodeAccountUsage[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const USAGE_REMOTE_PACKAGE = REMOTE_PACKAGE\n\n/** Canonical `<namespace>/<method>` endpoint of the usage report Remote. */\nexport const USAGE_REPORT_ENDPOINT = 'commandcode/report'\n\n/**\n * The shared read/validate helpers for the usage report endpoint, prefixed\n * so rejection messages name the offending boundary.\n */\nconst { reject, record, stringField, numberField, booleanField } =\n makeBoundaryValidator('commandcode/report result:')\n\n/** Validate one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one quota window, or undefined when the frame carries no such window.\n *\n * The distinction is load-bearing at this boundary: an ABSENT window means the\n * billing endpoint reported none (an unlimited plan), while a present block with\n * `cap: 0` means uncapped spend that was really reported. Collapsing the two\n * would draw a zeroed quota row for an account that has no such limit.\n */\nfunction windowLimit(\n value: unknown,\n field: string,\n): { used: number; cap: number; exceeded: boolean; resetAt: number } | undefined {\n if (value === undefined) return undefined\n const source = record(value, field)\n return {\n used: numberField(source, 'used', `${field}.used`),\n cap: numberField(source, 'cap', `${field}.cap`),\n exceeded: booleanField(source, 'exceeded', `${field}.exceeded`),\n resetAt: numberField(source, 'resetAt', `${field}.resetAt`),\n }\n}\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeUsageReport}.\n * Optional sections stay optional; every present field is shape-checked so a\n * malformed frame fails the boundary instead of rendering garbage.\n */\nfunction parseUsageReport(value: unknown): CommandCodeUsageReport {\n const source = record(value, 'report')\n const failures = source.failures\n if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== 'string')) reject('failures')\n const report: CommandCodeUsageReport = { failures: failures as string[] }\n\n if (source.blocked !== undefined) {\n const blocked = source.blocked\n // Positive check: TS's never-return control-flow analysis only recognizes\n // function declarations, not the factory's destructured-arrow `reject`, so\n // narrow `blocked` in the positive branch instead.\n if (blocked === 'invalid-key' || blocked === 'service-unavailable' || blocked === 'network') {\n report.blocked = blocked\n } else {\n reject('blocked')\n }\n }\n\n if (source.account !== undefined) {\n const account = record(source.account, 'account')\n report.account = {\n id: stringField(account, 'id', 'account.id'),\n name: stringField(account, 'name', 'account.name'),\n userName: stringField(account, 'userName', 'account.userName'),\n }\n }\n\n if (source.usage !== undefined) {\n const usage = record(source.usage, 'usage')\n report.usage = {\n totalCount: numberField(usage, 'totalCount', 'usage.totalCount'),\n totalCost: numberField(usage, 'totalCost', 'usage.totalCost'),\n successRate: numberField(usage, 'successRate', 'usage.successRate'),\n completedCount: numberField(usage, 'completedCount', 'usage.completedCount'),\n failedCount: numberField(usage, 'failedCount', 'usage.failedCount'),\n totalTokensIn: numberField(usage, 'totalTokensIn', 'usage.totalTokensIn'),\n totalTokensOut: numberField(usage, 'totalTokensOut', 'usage.totalTokensOut'),\n totalCredits: numberField(usage, 'totalCredits', 'usage.totalCredits'),\n periodBasis: stringField(usage, 'periodBasis', 'usage.periodBasis'),\n }\n }\n\n if (source.credits !== undefined) {\n const credits = record(source.credits, 'credits')\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberField(credits, 'monthlyCredits', 'credits.monthlyCredits'),\n purchasedCredits: numberField(credits, 'purchasedCredits', 'credits.purchasedCredits'),\n freeCredits: numberField(credits, 'freeCredits', 'credits.freeCredits'),\n }\n // OPTIONAL on the wire: a Host half that predates this field serves the\n // scalar 0 for an omitted balance, which cannot be told from a real zero.\n // An explicit `false` therefore means \"not reported\" and the panel keeps the\n // figure off the dashboard; an absent flag (an older Host) stays unset and\n // is read as \"assume reported\", so a real balance is not lost cross-version.\n // A PRESENT value must still be a boolean, so a malformed frame is rejected\n // here rather than coerced.\n if (credits.monthlyReported !== undefined) {\n parsed.monthlyReported = booleanField(credits, 'monthlyReported', 'credits.monthlyReported')\n }\n for (const flag of ['purchasedReported', 'freeReported'] as const) {\n if (credits[flag] !== undefined) parsed[flag] = booleanField(credits, flag, `credits.${flag}`)\n }\n // Absent means the endpoint reported no such window. The window parsers\n // return undefined for an absent block, and an optional member is only set\n // when it was really there.\n const fiveHour = windowLimit(credits.fiveHour, 'credits.fiveHour')\n const weekly = windowLimit(credits.weekly, 'credits.weekly')\n if (fiveHour !== undefined) parsed.fiveHour = fiveHour\n if (weekly !== undefined) parsed.weekly = weekly\n report.credits = parsed\n }\n\n if (source.plan !== undefined) {\n const plan = record(source.plan, 'plan')\n const monthly = plan.monthlyCredits\n if (monthly !== null && (typeof monthly !== 'number' || !Number.isFinite(monthly))) reject('plan.monthlyCredits')\n report.plan = {\n planId: stringField(plan, 'planId', 'plan.planId'),\n name: stringField(plan, 'name', 'plan.name'),\n status: stringField(plan, 'status', 'plan.status'),\n monthlyCredits: monthly as number | null,\n currentPeriodEnd: numberField(plan, 'currentPeriodEnd', 'plan.currentPeriodEnd'),\n }\n }\n\n return report\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeAccountUsage}. */\nfunction parseAccountUsage(value: unknown): CommandCodeAccountUsage {\n const source = record(value, 'account')\n return {\n id: stringField(source, 'id', 'account.id'),\n label: stringField(source, 'label', 'account.label'),\n configured: booleanField(source, 'configured', 'account.configured'),\n active: booleanField(source, 'active', 'account.active'),\n mark: stringField(source, 'mark', 'account.mark'),\n cooldownUntil: numberField(source, 'cooldownUntil', 'account.cooldownUntil'),\n report: parseUsageReport(source.report),\n }\n}\n\n/** Parse the wire result into a {@link CommandCodeAccountsReport}. */\nfunction parseAccountsReport(value: unknown): CommandCodeAccountsReport {\n const source = record(value, 'result')\n const accounts = source.accounts\n if (Array.isArray(accounts)) {\n return { accounts: accounts.map(parseAccountUsage) }\n }\n return reject('accounts')\n}\n\n/**\n * The strict result codec both halves attach to the descriptor. Hand-rolled:\n * the client bundle may not require a schema library, and `TypertSchema` is\n * deliberately minimal so one `parse` function satisfies it.\n */\nexport const usageReportSchema: TypertSchema<CommandCodeAccountsReport> = {\n parse: parseAccountsReport,\n}\n\n/**\n * The one invocation descriptor, shared verbatim by the Host registration and\n * the Client mount. `service` names the Cordis key the Gateway resolves the\n * receiver from; `namespace`/`method` name the wire endpoint.\n */\nexport const USAGE_REPORT_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeAccountsReport>(\n USAGE_REPORT_ENDPOINT,\n 'report',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeAccountsReport`,\n usageReportSchema,\n )\n\n/** The Host-face contribution registered on `ctx.typert`. */\nexport const USAGE_HOST_CONTRIBUTION = {\n package: USAGE_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // 0.1.2's Typert registry requires every Host contribution to carry its\n // reflection model. This hand-written Remote deliberately has no generated\n // reflection exports, so use the official empty-model form rather than a\n // cast that leaves registry inspection with `model: undefined`.\n model: { services: [], events: [], objects: [] },\n invocations: [USAGE_REPORT_DESCRIPTOR],\n}\n\n/** The Client-face contribution mounted on `ctx.remote`. */\nexport const USAGE_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [USAGE_REPORT_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog Remote (`commandcode/models`)\n// ---------------------------------------------------------------------------\n\n/** One catalog entry the settings page's model editors offer. */\nexport interface CommandCodeCatalogModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n /**\n * Minimum plan-tier key for this model (a `KNOWN_PLANS` value: `go`,\n * `goat`, `pro`, `provider`, `max`), or undefined for models outside the\n * snapshot. The settings page groups the model-editor dropdowns under\n * tier headings from this — the browser cannot import the Host's\n * capability snapshot, so the Host stamps it per entry.\n */\n tier?: string\n}\n\n/** The model-catalog Remote result: the full catalog, sorted for picking. */\nexport interface CommandCodeCatalog {\n models: CommandCodeCatalogModel[]\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the model-catalog Remote. */\nexport const MODELS_ENDPOINT = 'commandcode/models'\n\n/**\n * The shared read/validate helpers for the model-catalog endpoint — a\n * separate instance so catalog boundary errors name `commandcode/models`,\n * not the report endpoint.\n */\nconst {\n record: catalogRecord,\n stringField: catalogString,\n} = makeBoundaryValidator('commandcode/models result:')\n\n/** Parse one untrusted boundary value into a {@link CommandCodeCatalogModel}. */\nfunction parseCatalogModel(value: unknown): CommandCodeCatalogModel {\n const source = catalogRecord(value, 'model')\n const model: CommandCodeCatalogModel = {\n id: catalogString(source, 'id', 'model.id'),\n name: catalogString(source, 'name', 'model.name'),\n }\n // Tier is optional on the wire (older Hosts predate it); a present\n // non-string is a contract violation, not a silent drop.\n if (source.tier !== undefined) {\n model.tier = catalogString(source, 'tier', 'model.tier')\n }\n return model\n}\n\n/** Parse the wire result into a {@link CommandCodeCatalog}. */\nfunction parseCatalog(value: unknown): CommandCodeCatalog {\n const source = catalogRecord(value, 'result')\n const models = source.models\n if (Array.isArray(models)) {\n return { models: models.map(parseCatalogModel) }\n }\n throw new TypeError('commandcode/models result: invalid models')\n}\n\n/** The strict result codec for the model-catalog Remote. */\nexport const modelsSchema: TypertSchema<CommandCodeCatalog> = {\n parse: parseCatalog,\n}\n\n/**\n * The model-catalog invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the usage report.\n */\nexport const MODELS_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeCatalog>(\n MODELS_ENDPOINT,\n 'models',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeCatalog`,\n modelsSchema,\n )\n\n/** The Client-face contribution for the model-catalog endpoint. */\nexport const MODELS_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [MODELS_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model price table Remote (`commandcode/prices`)\n// ---------------------------------------------------------------------------\n\n/**\n * One model's per-token rates, in USD per 1,000,000 tokens — the unit the\n * official pricing page publishes in.\n */\nexport interface CommandCodeModelRates {\n /** Uncached (billed) input tokens. */\n inputCost: number\n /** Completion tokens. */\n outputCost: number\n /** Input tokens served from the provider's cache. */\n cacheReadCost: number\n /**\n * Input tokens written into the provider's cache. Present for a minority of\n * models — the page publishes no cache-write rate for the rest, whose\n * cache-write tokens are therefore UNPRICED. Do not substitute a multiple of\n * the input rate for a missing value.\n */\n cacheWriteCost?: number\n}\n\n/** One whole-request context band; maxContext is inclusive, absent on the last band. */\nexport interface CommandCodeContextTier extends CommandCodeModelRates {\n maxContext?: number\n}\n\n/** One model's rates plus the peak-hour override for time-of-day models. */\nexport interface CommandCodeModelPrice extends CommandCodeModelRates {\n /**\n * Lookup key: the catalog model id when a catalog model maps to this row,\n * otherwise the pricing page's own slug. A session reports catalog ids, so\n * this is the primary key the browser looks up by.\n */\n id: string\n /** The pricing page's slug for this row — the secondary lookup key. */\n slug: string\n /**\n * Rates charged inside the peak windows. The row's own top-level rates are\n * the off-peak rates, so a row WITH this block is time-of-day priced and a\n * row without it is flat-priced.\n */\n peak?: CommandCodeModelRates\n contextTiers?: CommandCodeContextTier[]\n /**\n * Whether the model costs nothing on every plan right now (a free deal or a\n * `:free` catalog variant). Served explicitly at zero rates so a surface can\n * say \"free\" rather than showing nothing.\n */\n free?: boolean\n}\n\n/** The price-table Remote result: every known model's rates. */\nexport interface CommandCodePriceTable {\n /**\n * Every priced model, keyed by {@link CommandCodeModelPrice.id} (catalog id\n * first, pricing slug as the fallback) and carrying its slug as a second\n * lookup key. A model absent from this list has no known price and must\n * render no cost at all rather than a guess.\n */\n models: CommandCodeModelPrice[]\n /**\n * Peak-pricing windows as `[startHour, endHour)` in UTC, end-exclusive,\n * applying Monday–Friday only. Shipped with the table so the browser prices\n * against the Host snapshot's schedule instead of restating it.\n */\n peakHours: Array<[number, number]>\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the price-table Remote. */\nexport const PRICES_ENDPOINT = 'commandcode/prices'\n\n/**\n * The shared read/validate helpers for the price-table endpoint — its own\n * instance so price boundary errors name `commandcode/prices`.\n */\nconst {\n reject: priceReject,\n record: priceRecord,\n stringField: priceString,\n numberField: priceNumber,\n booleanField: priceBoolean,\n} = makeBoundaryValidator('commandcode/prices result:')\n\n/** Parse one rate block (`rates`, or a model's `peak` override). */\nfunction parseRates(source: Record<string, unknown>, field: string): CommandCodeModelRates {\n const rates: CommandCodeModelRates = {\n inputCost: priceNumber(source, 'inputCost', `${field}.inputCost`),\n outputCost: priceNumber(source, 'outputCost', `${field}.outputCost`),\n cacheReadCost: priceNumber(source, 'cacheReadCost', `${field}.cacheReadCost`),\n }\n // Optional on the wire: only a minority of models publish a cache-write\n // rate, and a present non-number is a contract violation rather than a\n // silent zero.\n if (source.cacheWriteCost !== undefined) {\n rates.cacheWriteCost = priceNumber(source, 'cacheWriteCost', `${field}.cacheWriteCost`)\n }\n return rates\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeModelPrice}. */\nfunction parseModelPrice(value: unknown): CommandCodeModelPrice {\n const source = priceRecord(value, 'model')\n const price: CommandCodeModelPrice = {\n id: priceString(source, 'id', 'model.id'),\n slug: priceString(source, 'slug', 'model.slug'),\n ...parseRates(source, 'model'),\n }\n if (source.peak !== undefined) price.peak = parseRates(priceRecord(source.peak, 'model.peak'), 'model.peak')\n if (source.contextTiers !== undefined) {\n if (!Array.isArray(source.contextTiers) || source.contextTiers.length === 0) priceReject('contextTiers')\n let previous = 0\n price.contextTiers = (source.contextTiers as unknown[]).map((value, index, tiers) => {\n const tier = priceRecord(value, 'contextTier')\n const out: CommandCodeContextTier = parseRates(tier, 'contextTier')\n if (tier.maxContext !== undefined) {\n const max = priceNumber(tier, 'maxContext', 'contextTier.maxContext')\n if (!Number.isSafeInteger(max) || max <= previous || index === tiers.length - 1) priceReject('contextTier.maxContext')\n previous = max\n out.maxContext = max\n } else if (index !== tiers.length - 1) priceReject('contextTier.maxContext')\n return out\n })\n }\n if (source.free !== undefined) price.free = priceBoolean(source, 'free', 'model.free')\n return price\n}\n\n/** Parse the wire result into a {@link CommandCodePriceTable}. */\nfunction parsePriceTable(value: unknown): CommandCodePriceTable {\n const source = priceRecord(value, 'result')\n const models = source.models\n if (!Array.isArray(models)) priceReject('models')\n const peakHours = source.peakHours\n if (!Array.isArray(peakHours)) priceReject('peakHours')\n return {\n models: (models as unknown[]).map(parseModelPrice),\n peakHours: (peakHours as unknown[]).map((window) => {\n if (!Array.isArray(window) || window.length !== 2) priceReject('peakHours[]')\n const [start, end] = window as [unknown, unknown]\n if (typeof start !== 'number' || typeof end !== 'number') priceReject('peakHours[]')\n return [start, end] as [number, number]\n }),\n }\n}\n\n/** The strict result codec for the price-table Remote. */\nexport const pricesSchema: TypertSchema<CommandCodePriceTable> = {\n parse: parsePriceTable,\n}\n\n/**\n * The price-table invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the report and catalog endpoints.\n */\nexport const PRICES_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodePriceTable>(\n PRICES_ENDPOINT,\n 'prices',\n `${USAGE_REMOTE_PACKAGE}#CommandCodePriceTable`,\n pricesSchema,\n )\n\n/** The Client-face contribution for the price-table endpoint. */\nexport const PRICES_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [PRICES_DESCRIPTOR],\n}","/**\n * Wire contract for the Command Code login Remote endpoints\n * (`commandcode/loginBegin`, `commandcode/loginStatus`,\n * `commandcode/loginCancel`).\n *\n * The settings page can start a browser login against the official Command\n * Code Studio (the same loopback flow `command-code login` performs) instead\n * of pasting an API key. The loopback server must live in the Host half — it\n * binds a local port and receives the key — so the page drives it through the\n * Typert Gateway exactly like the usage report.\n *\n * This module is the single source both halves share, deliberately\n * dependency-free (`import type` edges only): the strict status validator the\n * client trusts, the three descriptors both halves register, and the two\n * contribution objects. The state shape mirrors the Host-only flow machine in\n * `src/login.ts` as plain JSON.\n *\n * @module dsh-commandcode-provider/login-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** Why a login attempt ended in `failed` (stable across versions for copy). */\nexport type CommandCodeLoginFailureReason =\n /** The Studio page reported the authorization was denied by the user. */\n | 'denied'\n /** No callback arrived within the flow's timeout window. */\n | 'timeout'\n /** The delivered key failed `/alpha/whoami` validation (401). */\n | 'invalid-key'\n /** The validation request could not reach the API. */\n | 'network'\n /** The key could not be stored (credentials seam unavailable). */\n | 'unavailable'\n /** The attempt was cancelled by the user or torn down with the plugin. */\n | 'cancelled'\n /** Anything else. */\n | 'error'\n\n/** One login attempt's full state face, as carried over the wire. */\nexport interface CommandCodeLoginStatus {\n /**\n * `idle` — no attempt; `waiting` — the loopback server is up and the\n * Studio URL is live; `success` — the key validated and was stored;\n * `failed` — see `reason`/`message`.\n */\n state: 'idle' | 'waiting' | 'success' | 'failed'\n /** The Studio authorization URL while `waiting`. */\n authUrl?: string\n /** The account display name reported by the Studio, on `success`. */\n userName?: string\n /** The key's label from the Studio, on `success`. */\n keyName?: string\n /** Why the attempt failed, when `failed`. */\n reason?: CommandCodeLoginFailureReason\n /** Human-readable failure detail, when `failed` (secondary to `reason`). */\n message?: string\n}\n\n/** The canonical endpoint paths of the three login Remotes. */\nexport const LOGIN_BEGIN_ENDPOINT = 'commandcode/loginBegin'\nexport const LOGIN_STATUS_ENDPOINT = 'commandcode/loginStatus'\nexport const LOGIN_CANCEL_ENDPOINT = 'commandcode/loginCancel'\n\nconst REASONS: readonly CommandCodeLoginFailureReason[] = [\n 'denied', 'timeout', 'invalid-key', 'network', 'unavailable', 'cancelled', 'error',\n]\n\n/** The shared read/validate helpers, prefixed with the login endpoint so\n * rejection messages name the offending boundary. */\nconst { reject, record, stringField } =\n makeBoundaryValidator('commandcode/login result:')\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeLoginStatus}.\n * Every field is shape-checked so a malformed frame fails the boundary\n * instead of leaking into the page.\n */\nexport function parseLoginStatus(value: unknown): CommandCodeLoginStatus {\n const source = record(value, 'status')\n const state = source.state\n // The factory's destructured-arrow `reject` is typed never-returning but\n // TS narrows it only in the positive branch — assign inside the guard.\n if (state === 'idle' || state === 'waiting' || state === 'success' || state === 'failed') {\n const status: CommandCodeLoginStatus = { state }\n if (source.authUrl !== undefined) {\n status.authUrl = stringField(source, 'authUrl', 'authUrl')\n }\n if (source.userName !== undefined) {\n status.userName = stringField(source, 'userName', 'userName')\n }\n if (source.keyName !== undefined) {\n status.keyName = stringField(source, 'keyName', 'keyName')\n }\n if (source.reason !== undefined) {\n const reason = source.reason\n if (typeof reason === 'string' && REASONS.includes(reason as CommandCodeLoginFailureReason)) {\n status.reason = reason as CommandCodeLoginFailureReason\n } else {\n reject('reason')\n }\n }\n if (source.message !== undefined) {\n status.message = stringField(source, 'message', 'message')\n }\n return status\n }\n return reject('state')\n}\n\n/** The strict result codec shared by all three login endpoints. */\nexport const loginStatusSchema: TypertSchema<CommandCodeLoginStatus> = {\n parse: parseLoginStatus,\n}\n\n/** Build one login invocation descriptor (uniform result, no parameters). */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n return makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n}\n\n/** The three login descriptors, shared verbatim by Host registration and Client mount. */\nexport const LOGIN_DESCRIPTORS: readonly InvocationDescriptor[] = [\n loginDescriptor(LOGIN_BEGIN_ENDPOINT, 'loginBegin'),\n loginDescriptor(LOGIN_STATUS_ENDPOINT, 'loginStatus'),\n loginDescriptor(LOGIN_CANCEL_ENDPOINT, 'loginCancel'),\n]\n\n/** The Host-face contribution fragment registered on `ctx.typert`. */\nexport const LOGIN_HOST_CONTRIBUTION = {\n package: REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n invocations: LOGIN_DESCRIPTORS,\n}\n\n/** The Client-face contribution fragment mounted on `ctx.remote`. */\nexport const LOGIN_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REMOTE_PACKAGE,\n descriptors: LOGIN_DESCRIPTORS,\n}\n","/**\n * Host half of the account-usage Remote (`commandcode/report`).\n *\n * The settings page's account card needs the same report the `/commandcode`\n * command prints, but the browser never holds the API key — the fetch must\n * run Host-side. This module exposes `adapter.getUsage()` through the Typert\n * Gateway: a `TypertRemoteService` provides the receiver the Gateway resolves,\n * and the shared strict descriptor (`src/usage-wire.ts`) is registered on the\n * `typert` registry so the Gateway claims the `commandcode/report` endpoint.\n *\n * The whole wiring rides an optional `ctx.inject(['typert'], ...)` fiber: a\n * profile without the web stack (no Typert registry, no Gateway) simply never\n * activates it, exactly like the `/commandcode` command rides `commands`.\n *\n * @module dsh-commandcode-provider/usage-remote\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'\nimport type { CommandCodeAdapter, CommandCodeConnectionOptions } from './adapter.ts'\nimport { USAGE_HOST_CONTRIBUTION } from './usage-wire.ts'\nimport { MODELS_DESCRIPTOR } from './usage-wire.ts'\nimport { PRICES_DESCRIPTOR } from './usage-wire.ts'\nimport type { CommandCodeAccountsReport, CommandCodeCatalog, CommandCodePriceTable } from './usage-wire.ts'\nimport { modelPriceTable } from './model-prices.ts'\nimport { LOGIN_DESCRIPTORS } from './login-wire.ts'\nimport type { CommandCodeLoginStatus } from './login-wire.ts'\n\n/**\n * The browser-login face the usage service exposes (`commandcode/login*`).\n * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry\n * wired one; absent, `status`/`cancel` degrade to the idle status while\n * `begin` rejects with a plain message (so the page's manual paste path\n * stays the fallback instead of hanging).\n */\nexport interface LoginFlowFacade {\n /** Start (or rejoin) an attempt; rejects when it cannot start at all. */\n begin(): Promise<CommandCodeLoginStatus>\n /** The current attempt's status. */\n status(): CommandCodeLoginStatus\n /** Cancel a waiting attempt. */\n cancel(): void\n}\n\n/** Everything the usage service needs beyond its Cordis context. */\nexport interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** The registered adapter (for getUsage). */\n adapter: CommandCodeAdapter<C>\n /**\n * Multi-account report source (wired by the plugin entry). Absent in\n * programmatic setups, the service falls back to a single default-account\n * entry around `adapter.getUsage()`.\n */\n reports?: () => Promise<CommandCodeAccountsReport>\n /**\n * Model-catalog source for the settings page's model editors (the\n * routing-rule editor and the visible-models filter; wired by the plugin\n * entry). Absent, the `models` endpoint answers an empty list — the page's\n * editors degrade to the empty state.\n */\n listModels?: () => Promise<CommandCodeCatalog>\n /**\n * Price-table source for the composer's session-cost figure. Defaults to the\n * vendored snapshot, so the endpoint can never silently serve an empty table\n * — an unpriced cost is the failure this feature is meant to remove. Override\n * only to stub it in a test.\n */\n prices?: () => CommandCodePriceTable\n /**\n * The browser-login flow (wired by the plugin entry). Absent means the\n * login endpoints answer `idle` / reject with a plain message — the page's\n * manual paste path stays the fallback.\n */\n login?: LoginFlowFacade\n}\n\n/**\n * The registry method surface this module uses. `Context['typert']` is typed\n * as the read-only `TypertRegistryContract`; contribution registration lives\n * on the concrete registry service, so the cast is spelled out once here.\n * The contribution is the combined one built below (report + models + login\n * endpoints), so the type is structural rather than tied to the\n * single-endpoint `USAGE_HOST_CONTRIBUTION` shape.\n */\ninterface TypertContributionRegistry {\n register(contribution: {\n package: string\n face: 'host'\n schemas: unknown[]\n model: { services: unknown[]; events: unknown[]; objects: unknown[] }\n invocations: unknown[]\n }): () => void | Promise<void>\n}\n\n/**\n * The Remote receiver: a Cordis service the Gateway resolves by key\n * (`commandcodeUsage`) and binds to the wire namespace (`commandcode`). The\n * base class stamps the `typertRemote` binding the Gateway validates on every\n * dispatch; no decorators are needed because the descriptor is registered\n * explicitly (strict path) rather than discovered from source markers.\n */\nexport class CommandCodeUsageService<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions>\n extends TypertRemoteService {\n private readonly deps: CommandCodeUsageDeps<C>\n\n constructor(ctx: Context, deps: CommandCodeUsageDeps<C>) {\n super(ctx, 'commandcodeUsage', { namespace: 'commandcode' })\n this.deps = deps\n }\n\n /**\n * Account, usage, and credit state for the settings page's account card —\n * one entry per pool account when the plugin entry wired `reports`, a\n * single default-account entry otherwise. Degrades per endpoint like the\n * `/commandcode` command (failures land in `report.failures`); throws\n * `MISSING_CREDENTIAL` when no key resolves, which the Gateway folds into\n * the failure branch the page renders as a hint.\n */\n async report(): Promise<CommandCodeAccountsReport> {\n if (this.deps.reports !== undefined) return this.deps.reports()\n const report = await this.deps.adapter.getUsage()\n return {\n accounts: [{\n id: 'default',\n label: 'Default',\n configured: true,\n active: true,\n mark: '',\n cooldownUntil: 0,\n report,\n }],\n }\n }\n\n /**\n * The full model catalog for the settings page's model editors (the\n * routing-rule editor and the visible-models filter). The browser never\n * calls the Command Code API directly — the Host serves the catalog\n * (already fetched/cached by the adapter) so models can be picked from\n * the live list instead of typed by hand.\n */\n async models(): Promise<CommandCodeCatalog> {\n return this.deps.listModels?.() ?? { models: [] }\n }\n\n /**\n * The model price table the composer prices an in-progress session with.\n * Static vendored data (the official pricing page's rates), served Host-side\n * so the browser bundle never carries a copy that could drift from the\n * snapshot, and so a price update reaches an open page without a rebuild.\n */\n async prices(): Promise<CommandCodePriceTable> {\n return (this.deps.prices ?? modelPriceTable)()\n }\n\n /**\n * Start (or rejoin) a browser-login attempt and return its fresh status —\n * `waiting` carrying the Studio URL. Rejects when the flow cannot start\n * (no free loopback port, disposed plugin); the Gateway folds the throw\n * into the failure branch the page renders.\n */\n async loginBegin(): Promise<CommandCodeLoginStatus> {\n const login = this.requireLogin()\n return login.begin()\n }\n\n /** Poll a login attempt's status. */\n async loginStatus(): Promise<CommandCodeLoginStatus> {\n return this.deps.login?.status() ?? { state: 'idle' }\n }\n\n /** Cancel a waiting attempt; returns the post-cancel status. */\n async loginCancel(): Promise<CommandCodeLoginStatus> {\n this.deps.login?.cancel()\n return this.deps.login?.status() ?? { state: 'idle' }\n }\n\n private requireLogin(): LoginFlowFacade {\n const login = this.deps.login\n if (login === undefined) {\n throw new Error('login flow is not wired in this setup; paste the API key instead')\n }\n return login\n }\n}\n\n/**\n * Provide the usage service and register its Remote descriptor. The registry\n * contribution is tied to this fiber's lifetime: the registry's own\n * `register()` effect would otherwise outlive the plugin.\n */\nexport function applyUsageRemote<C extends CommandCodeConnectionOptions>(\n ctx: Context,\n deps: CommandCodeUsageDeps<C>,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new CommandCodeUsageService(remoteCtx, deps)\n const registry = remoteCtx.typert as unknown as TypertContributionRegistry\n // One registration carries the report endpoint, the models endpoint, and\n // the login endpoints: the descriptors are unique per endpoint, and a\n // single contribution keeps the Host's registry bookkeeping (and the\n // Client mount) 1:1.\n const unregister = registry.register({\n ...USAGE_HOST_CONTRIBUTION,\n invocations: [...USAGE_HOST_CONTRIBUTION.invocations, MODELS_DESCRIPTOR, PRICES_DESCRIPTOR, ...LOGIN_DESCRIPTORS],\n })\n // The registry's own effect would outlive this fiber; withdraw the\n // contribution when the plugin unloads.\n remoteCtx.effect(() => () => void unregister(), 'dsh-commandcode-provider: usage remote')\n })\n}\n","/**\n * Host half of the Command Code browser login (the loopback flow).\n *\n * Mirrors what the official `command-code login` CLI command performs\n * (reverse-engineered from `command-code@1.32.1`, `createAuthFlowController`\n * + `createAuthServer` in its bundle):\n *\n * 1. Bind a temporary HTTP server on `127.0.0.1`, first available port from\n * 5959 upward (10 attempts).\n * 2. Generate a random state token and open\n * `{studio}/studio/auth/cli?callback=http://localhost:{port}/callback&state={state}`.\n * 3. After the user signs in, the Studio page POSTs the credentials JSON\n * `{ apiKey, state, userId, userName, keyName }` to the loopback callback —\n * no OAuth code exchange, the page holds the final API key.\n * 4. The delivered key is validated against `GET {apiBase}/alpha/whoami`\n * before anything is stored.\n *\n * Server behaviour is mirrored exactly: POST-only `/callback`, a 10 KB body\n * cap, JSON responses (`{success:true}` / `{success:false,error}`), CORS for\n * the Studio origins only, and state-token equality as the anti-forgery\n * check. One deliberate hardening over the CLI build: the CORS origin is\n * echoed only when it is allowlisted (the CLI falls back to the first\n * origin), which browsers treat identically.\n *\n * Storage stays out of this module: the plugin entry supplies\n * {@link CommandCodeLoginFlowDeps.storeKey}, which writes through the dsh\n * credentials seam so the next request resolves the new key with no restart.\n * Everything external (fetch, ports, randomness, timing) is injectable for\n * node tests; the tests drive a real loopback server end to end.\n *\n * @module dsh-commandcode-provider/login\n */\n\nimport { createServer as createHttpServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createServer as createNetServer } from 'node:net'\nimport { randomBytes } from 'node:crypto'\nimport { DEFAULT_API_BASE } from './adapter.ts'\nimport type { CommandCodeLoginFailureReason, CommandCodeLoginStatus } from './login-wire.ts'\n\n/** Give up on the browser after this long without a callback (mirrors the CLI). */\nexport const LOGIN_TIMEOUT_MS = 120_000\n\n/** First local port the flow tries (mirrors the CLI). */\nexport const LOGIN_START_PORT = 5959\n\n/** How many consecutive ports to try from {@link LOGIN_START_PORT}. */\nexport const LOGIN_MAX_PORT_ATTEMPTS = 10\n\n/** Reject callback bodies larger than this (mirrors the CLI). */\nexport const LOGIN_BODY_LIMIT_BYTES = 10_000\n\n/** The Studio origins allowed to POST credentials to the loopback server. */\nexport const LOGIN_ALLOWED_ORIGINS: readonly string[] = [\n 'http://localhost:3000',\n 'https://staging.commandcode.ai',\n 'https://commandcode.ai',\n]\n\n/** The Studio route that performs the browser-side login. */\nconst STUDIO_AUTH_PATH = '/studio/auth/cli'\n\n/** Credentials as delivered by the Studio's callback POST. */\nexport interface CommandCodeLoginCredentials {\n apiKey: string\n userId: string\n userName: string\n keyName: string\n}\n\n/** Outcome of validating a delivered key against `/alpha/whoami`. */\nexport type ApiKeyValidation =\n | { valid: true }\n | { valid: false; error: 'invalid_key' | 'server_error' | 'network_error' }\n\nexport interface CommandCodeLoginFlowDeps {\n /**\n * The Provider API base used for `/alpha/whoami` validation; also selects\n * the matching Studio base (staging api → staging studio). A thunk is fine:\n * it is re-read when each attempt starts, so a settings change reaches the\n * next login. Defaults to the public API base.\n */\n apiBase?: string | (() => string | undefined)\n /** Attempt timeout in millis; defaults to {@link LOGIN_TIMEOUT_MS}. */\n timeoutMs?: number\n /** First port to try; defaults to {@link LOGIN_START_PORT}. */\n startPort?: number\n /** Consecutive-port attempts; defaults to {@link LOGIN_MAX_PORT_ATTEMPTS}. */\n maxPortAttempts?: number\n /** Validation fetch seam; defaults to global `fetch`. */\n fetchImpl?: typeof fetch\n /** Randomness seam; defaults to `node:crypto` randomBytes(32) base64url. */\n randomToken?: (byteLength: number) => string\n /**\n * Receives the validated credentials after a successful login. Rejecting\n * fails the attempt with `unavailable`.\n */\n storeKey(credentials: CommandCodeLoginCredentials): Promise<void>\n}\n\n/** Compose the Studio authorization URL (pure, exported for tests). */\nexport function buildCommandAuthUrl(options: { studioBase: string; port: number; state: string }): string {\n const callback = `http://localhost:${options.port}/callback`\n return `${options.studioBase}${STUDIO_AUTH_PATH}?callback=${encodeURIComponent(callback)}&state=${encodeURIComponent(options.state)}`\n}\n\n/** Map an API base onto the Studio base the CLI pairs it with. */\nexport function studioBaseForApiBase(apiBase: string): string {\n if (/^https:\\/\\/staging-api\\.commandcode\\.ai/i.test(apiBase)) return 'https://staging.commandcode.ai'\n if (/^http:\\/\\/localhost(:\\d+)?$/i.test(apiBase)) return 'http://localhost:3000'\n return 'https://commandcode.ai'\n}\n\n/**\n * Validate one candidate key against `/alpha/whoami` (pure, exported for\n * tests). Mirrors the CLI's verdicts: 401 → invalid_key, other non-OK →\n * server_error, transport failure → network_error.\n */\nexport async function validateCommandApiKey(\n fetchImpl: typeof fetch,\n apiBase: string,\n apiKey: string,\n): Promise<ApiKeyValidation> {\n try {\n const response = await fetchImpl(`${apiBase}/alpha/whoami`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },\n })\n if (response.status === 401) return { valid: false, error: 'invalid_key' }\n if (response.ok) return { valid: true }\n return { valid: false, error: 'server_error' }\n } catch {\n return { valid: false, error: 'network_error' }\n }\n}\n\n/** Whether one loopback port is free right now. */\nfunction checkPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const probe = createNetServer()\n probe.once('error', () => resolve(false))\n probe.once('listening', () => probe.close(() => resolve(true)))\n probe.listen(port, '127.0.0.1')\n })\n}\n\n/** Whether a callback body carries every credential field the CLI requires. */\nfunction isCallbackCredentials(value: unknown): value is CommandCodeLoginCredentials & Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n return typeof record.apiKey === 'string' && record.apiKey !== ''\n && typeof record.state === 'string'\n && typeof record.userId === 'string'\n && typeof record.userName === 'string'\n && typeof record.keyName === 'string'\n}\n\n/**\n * One browser-login attempt machine. Single-flight by design: `begin()` while\n * waiting returns the live attempt's status instead of starting a second one;\n * a terminal state makes the next `begin()` start fresh.\n */\nexport class CommandCodeLoginFlow {\n private readonly deps: CommandCodeLoginFlowDeps\n private readonly listeners = new Set<() => void>()\n\n private statusValue: CommandCodeLoginStatus = { state: 'idle' }\n private server: Server | undefined\n private timer: ReturnType<typeof setTimeout> | undefined\n /** Settle hooks of the live attempt's callback promise. */\n private settle: {\n resolve(credentials: CommandCodeLoginCredentials): void\n reject(failure: LoginSettleError): void\n } | undefined\n /**\n * Attempt generation. A delivered callback keeps validating the key\n * asynchronously (`complete()`), and that window is open to a cancel or a\n * fresh `begin()`; the generation lets a late completion recognize that it\n * no longer owns the status face and stop instead of storing a credential\n * the user cancelled and flipping the page back to success.\n */\n private attemptSeq = 0\n private disposed = false\n\n constructor(deps: CommandCodeLoginFlowDeps) {\n this.deps = deps\n }\n\n /** Subscribe to state transitions. @returns the disposer. */\n onChange(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current attempt's status face. */\n status(): CommandCodeLoginStatus {\n return this.statusValue\n }\n\n /**\n * Start an attempt (or rejoin the live one) and resolve with its status —\n * `waiting` carrying the Studio URL once the loopback server is up.\n * Rejects only when the flow cannot start at all (no free port, disposed).\n */\n async begin(): Promise<CommandCodeLoginStatus> {\n if (this.disposed) throw new Error('login flow has been disposed')\n // Rejoin only a live attempt. A `waiting` status whose server is already\n // torn down means the callback was consumed and the key is being\n // validated: that attempt can no longer receive anything, so handing its\n // dead authUrl back would give the user a link to a closed port. Starting\n // fresh retires it (the generation check below drops its late completion).\n if (this.statusValue.state === 'waiting' && this.server !== undefined) return this.statusValue\n this.teardown()\n const attempt = ++this.attemptSeq\n\n const port = await this.findPort()\n const expectedState = this.deps.randomToken?.(32) ?? randomBytes(32).toString('base64url')\n\n // The attempt settles exactly once: fulfilled with delivered credentials,\n // rejected with a tagged failure the mapping below turns into copy.\n const settled = new Promise<CommandCodeLoginCredentials>((resolve, reject) => {\n this.settle = { resolve, reject }\n })\n // A bind failure must surface before the attempt reports `waiting`.\n await this.bindServer(port, expectedState)\n\n const apiBase = this.readApiBase()\n this.setStatus({\n state: 'waiting',\n authUrl: buildCommandAuthUrl({ studioBase: studioBaseForApiBase(apiBase), port, state: expectedState }),\n })\n\n // Watchdog mirrors the CLI's 2-minute window.\n this.timer = setTimeout(() => {\n this.teardown()\n this.setStatus({\n state: 'failed',\n reason: 'timeout',\n message: 'No browser callback arrived within the login window.',\n })\n }, this.deps.timeoutMs ?? LOGIN_TIMEOUT_MS)\n this.timer.unref?.()\n\n void settled.then(\n (credentials) => this.complete(attempt, credentials),\n (failure) => this.failFrom(attempt, failure),\n )\n return this.statusValue\n }\n\n /** Cancel a waiting attempt; terminal states are untouched. */\n cancel(): void {\n if (this.disposed || this.statusValue.state !== 'waiting') return\n this.teardown()\n this.setStatus({ state: 'failed', reason: 'cancelled' })\n }\n\n /** Stop everything; a waiting attempt ends cancelled. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n const wasWaiting = this.statusValue.state === 'waiting'\n this.teardown()\n if (wasWaiting) this.setStatus({ state: 'failed', reason: 'cancelled' })\n }\n\n // -----------------------------------------------------------------------\n // Internals\n // -----------------------------------------------------------------------\n\n private readApiBase(): string {\n const raw = typeof this.deps.apiBase === 'function' ? this.deps.apiBase() : this.deps.apiBase\n return raw ?? DEFAULT_API_BASE\n }\n\n private setStatus(next: CommandCodeLoginStatus): void {\n this.statusValue = next\n for (const listener of [...this.listeners]) listener()\n }\n\n /** First free port among the consecutive candidates. */\n private async findPort(): Promise<number> {\n const startPort = this.deps.startPort ?? LOGIN_START_PORT\n const attempts = this.deps.maxPortAttempts ?? LOGIN_MAX_PORT_ATTEMPTS\n for (let index = 0; index < attempts; index += 1) {\n const candidate = startPort + index\n if (await checkPortAvailable(candidate)) return candidate\n }\n throw new Error(`No available port found after ${attempts} attempts starting from port ${startPort}`)\n }\n\n /**\n * Bind the attempt's loopback server, resolving when the port is live.\n * Pre-bind failures reject (surfacing from `begin()`); a later server error\n * settles the live attempt as a tagged failure instead.\n */\n private bindServer(port: number, expectedState: string): Promise<void> {\n return new Promise((resolve, reject) => {\n let binding = true\n const server = createHttpServer((request, response) => this.handleCallback(request, response, expectedState))\n this.server = server\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (this.server !== server) return\n this.server = undefined\n const tagged = new LoginSettleError(\n 'error',\n `Could not bind the login callback server on port ${port}: ${error.code ?? error.message}`,\n )\n if (binding) {\n binding = false\n reject(tagged)\n } else {\n this.settle?.reject(tagged)\n }\n })\n server.listen(port, '127.0.0.1', () => {\n if (!binding) return\n binding = false\n resolve()\n })\n })\n }\n\n /** One request against the attempt's callback endpoint (CLI-mirrored). */\n private handleCallback(request: IncomingMessage, response: ServerResponse, expectedState: string): void {\n // One-shot responses: the server dies with the attempt, and a client\n // pooling the connection would otherwise race its next request against\n // the close.\n response.setHeader('Connection', 'close')\n response.setHeader('Access-Control-Allow-Origin', corsOrigin(request.headers.origin))\n response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')\n response.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n response.setHeader('Content-Type', 'application/json')\n const json = (code: number, body: Record<string, unknown>) => {\n response.writeHead(code)\n response.end(JSON.stringify(body))\n }\n if (request.method === 'OPTIONS') {\n response.writeHead(204)\n response.end()\n return\n }\n const path = request.url?.split('?')[0] ?? '/'\n if (path !== '/callback') {\n json(404, { success: false, error: 'Not found' })\n return\n }\n if (request.method !== 'POST') {\n json(405, { success: false, error: 'Method not allowed. Use POST.' })\n return\n }\n // The cap is on wire bytes, not JS string length: multibyte bodies\n // (CJK/emoji) would otherwise pass ~1.5-2x the limit before tripping it.\n let bodyBytes = 0\n let body = ''\n request.on('data', (chunk: Buffer) => {\n bodyBytes += chunk.length\n body += chunk.toString()\n if (bodyBytes > LOGIN_BODY_LIMIT_BYTES) request.destroy()\n })\n request.on('end', () => {\n // A destroyed (over-limit) request never processes its partial body.\n if (request.destroyed) return\n let payload: unknown\n try {\n payload = JSON.parse(body)\n } catch {\n json(400, { success: false, error: 'Invalid JSON' })\n return\n }\n // The Studio reports a denied authorization as an error object. The\n // state token is checked FIRST, exactly as the CLI does: a denial is\n // terminal, so an unauthenticated caller that could reach this branch\n // without a state match could kill a live login from any web page (the\n // POST rides as a CORS simple request, which the browser sends\n // regardless of our origin allowlist). Only the holder of the state this\n // attempt generated may end it.\n if (typeof payload === 'object' && payload !== null && 'error' in payload) {\n const denial = payload as Record<string, unknown>\n if (denial.state !== expectedState) {\n json(403, { success: false, error: 'Invalid state token' })\n return\n }\n const description = denial.error_description ?? denial.error\n this.settleAttempt(json, 200, { success: true }, new LoginSettleError(\n denial.error === 'access_denied' ? 'denied' : 'error',\n typeof description === 'string' && description !== '' ? description : 'Authorization failed',\n ))\n return\n }\n if (!isCallbackCredentials(payload)) {\n json(400, { success: false, error: 'Missing required fields' })\n return\n }\n if (payload.state !== expectedState) {\n // Not terminal: a stale tab replaying an old state must not kill the\n // live attempt — answer 403 and keep waiting (the CLI does the same).\n json(403, { success: false, error: 'Invalid state token' })\n return\n }\n this.settleAttempt(json, 200, { success: true }, undefined, { ...payload })\n })\n request.on('error', () => {})\n }\n\n /** Answer a decisive callback, stop listening, and settle the attempt. */\n private settleAttempt(\n json: (code: number, body: Record<string, unknown>) => void,\n code: number,\n body: Record<string, unknown>,\n failure?: LoginSettleError,\n credentials?: CommandCodeLoginCredentials,\n ): void {\n json(code, body)\n // Capture the settle hooks BEFORE teardown clears them.\n const settle = this.settle\n this.teardown()\n if (settle === undefined) return\n if (failure !== undefined) settle.reject(failure)\n else if (credentials !== undefined) settle.resolve(credentials)\n }\n\n /**\n * Post-validation completion: whoami check, then hand-off to storage.\n *\n * Every step re-checks {@link ownsAttempt} first: the whoami round-trip and\n * the credential write are awaits, and the user may cancel (or start another\n * attempt) while one is in flight. A completion that no longer owns the\n * attempt must not write the key or publish a status — otherwise cancel\n * would report \"cancelled\" while the credential landed anyway, and the page\n * would silently flip to success.\n */\n private async complete(attempt: number, credentials: CommandCodeLoginCredentials): Promise<void> {\n if (!this.ownsAttempt(attempt)) return\n const validation = await validateCommandApiKey(\n this.deps.fetchImpl ?? fetch,\n this.readApiBase(),\n credentials.apiKey,\n )\n if (!this.ownsAttempt(attempt)) return\n if (!validation.valid) {\n const reason: CommandCodeLoginFailureReason = validation.error === 'invalid_key'\n ? 'invalid-key'\n : validation.error === 'network_error' ? 'network' : 'error'\n this.setStatus({\n state: 'failed',\n reason,\n message: `/alpha/whoami rejected the delivered key (${validation.error}).`,\n })\n return\n }\n // Last gate before the side effect: a cancel that arrived during the\n // whoami check must win over storing the key.\n if (!this.ownsAttempt(attempt)) return\n try {\n await this.deps.storeKey(credentials)\n } catch (error: unknown) {\n if (!this.ownsAttempt(attempt)) return\n this.setStatus({\n state: 'failed',\n reason: 'unavailable',\n message: error instanceof Error ? error.message : String(error),\n })\n return\n }\n if (!this.ownsAttempt(attempt)) return\n this.clearTimer()\n this.setStatus({ state: 'success', userName: credentials.userName, keyName: credentials.keyName })\n }\n\n /** Whether one attempt still owns the status face (not cancelled, replaced, or disposed). */\n private ownsAttempt(attempt: number): boolean {\n return !this.disposed && this.attemptSeq === attempt && this.statusValue.state === 'waiting'\n }\n\n /** Map a tagged settle rejection onto the status face. */\n private failFrom(attempt: number, failure: unknown): void {\n if (!(failure instanceof LoginSettleError)) return\n if (!this.ownsAttempt(attempt)) return\n this.setStatus({ state: 'failed', reason: failure.reason, message: failure.message })\n }\n\n private clearTimer(): void {\n if (this.timer !== undefined) {\n clearTimeout(this.timer)\n this.timer = undefined\n }\n }\n\n /** Close the server and watchdog without touching the published status. */\n private teardown(): void {\n this.clearTimer()\n this.server?.close()\n this.server = undefined\n this.settle = undefined\n }\n}\n\n/** A tagged settle failure carrying the stable copy reason. */\nclass LoginSettleError extends Error {\n constructor(public readonly reason: CommandCodeLoginFailureReason, message: string) {\n super(message)\n this.name = 'LoginSettleError'\n }\n}\n\n/** Echo the Origin header only when the Studio allowlist contains it. */\nfunction corsOrigin(origin: string | undefined): string {\n return origin !== undefined && LOGIN_ALLOWED_ORIGINS.includes(origin) ? origin : ''\n}\n","/**\n * dsh-commandcode-provider — Command Code web search provider over `ctx.web`.\n *\n * The official Command Code CLI ships a built-in `web_search` tool that POSTs\n * `{ query, numResults, allowedDomains?, blockedDomains? }` to\n * `{apiBase}/alpha/web-search` and reads `{ results: [{ title, url, snippet }] }`\n * back. It authenticates with the SAME `Authorization: Bearer <key>` header and\n * `x-command-code-version` the model adapter uses, so this provider reuses the\n * plugin's existing credential chain (`COMMANDCODE_API_KEY` → credentials seam →\n * `~/.commandcode/auth.json`) — no separate DeepSeek key, no extra endpoint.\n *\n * This mirrors the host-side `@deepseek-ai/dsh-web-search-deepseek` provider in\n * shape: a cordis-free class registered into the web seam, resolving its key per\n * search, mapping each server-side result to the harness's normalized\n * `WebSearchSource`. The web seam owns `maxResults` truncation.\n *\n * @module dsh-commandcode-provider/web-search\n */\n\nimport { WebError, type WebSearchProvider, type WebSearchRequest, type WebSearchResult, type WebSearchSource } from '@deepseek-ai/dsh-web'\nimport type { WebRuntime } from '@deepseek-ai/dsh-web'\nimport { attributionHeaders, type HarnessError } from '@deepseek-ai/dsh-llm'\nimport { COMMAND_CODE_CLI_VERSION } from './adapter.ts'\n\n/** Stable id this provider registers under in `ctx.web`. */\nexport const COMMANDCODE_SEARCH_PROVIDER_ID = 'commandcode'\n\n/**\n * The factory-declared search provider id dsh ships by default (from\n * `dsh-base`'s cordis patch `web.config.searchProvider`). Kept as a\n * documented reference only: disabling this plugin's `webSearch` toggle\n * restores the previously selected backend (see\n * {@link applyCommandCodeSearchSelection}) — it never forces this default,\n * because forcing it is what used to silence sibling search plugins such as\n * modsearch even with Command Code search turned off (issue #26).\n */\nexport const DEFAULT_WEB_SEARCH_PROVIDER_ID = 'deepseek-official'\n\n/**\n * A structurally-typed view of `WebRuntime`'s private selection field.\n *\n * `searchProviderId` is declared `private readonly` on the class, but the\n * compiled runtime property is a plain writable field read per search call\n * (`web.search()` reads `this.searchProviderId` on every invocation). dsh\n * offers no public API to change the selected search provider at runtime, so\n * this seam mutates the instance field directly. That is a deliberate, bounded\n * dependency on the runtime shape: if dsh ever makes the field `#private` or\n * caches it in a closure, this write silently stops applying and the plugin\n * falls back to its provider remaining registered-but-unselected (the boot-time\n * `searchProvider: commandcode` cordis patch is the durable alternative).\n */\ninterface WebRuntimeSearchField {\n /** The selected search provider id; read per call by `search()`. */\n searchProviderId: string | undefined\n}\n\n/**\n * Point the web seam's search selection at this plugin's provider (`commandcode`).\n * Sets the runtime field; the next search call honours it because `search()`\n * re-reads `searchProviderId` each time. Returns the prior id (or undefined).\n * Never throws: a hardened/frozen runtime shape must not break the\n * settings-save path that calls this — the provider simply stays\n * registered-but-unselected (the boot-time `searchProvider: commandcode`\n * cordis patch is the durable alternative).\n *\n * @deprecated Prefer {@link applyCommandCodeSearchSelection}: this overload\n * always overwrites the displaced backend with the factory default on\n * disable, so turning Command Code search off silences whichever provider\n * was selected before (e.g. modsearch) instead of restoring it (issue #26).\n */\nexport function selectCommandCodeSearchProvider(web: WebRuntime, enable: boolean): string | undefined {\n try {\n const field = web as unknown as WebRuntimeSearchField\n const prior = field.searchProviderId\n field.searchProviderId = enable ? COMMANDCODE_SEARCH_PROVIDER_ID : DEFAULT_WEB_SEARCH_PROVIDER_ID\n return prior\n } catch {\n return undefined\n }\n}\n\n/**\n * Tracked web-search selection state for one mounted `WebRuntime`.\n *\n * `owner` marks whether this plugin currently owns the selection (i.e. it\n * wrote `commandcode` and has not given it back yet). `displaced` is the\n * backend id the plugin displaced when it took over — restored when the\n * toggle turns off or the plugin unloads. `undefined` means \"nothing was\n * configured, leave auto-select\" and must round-trip untouched: writing the\n * factory default instead would still override a sibling plugin's own\n * constructor-time pin.\n */\nexport interface CommandCodeSearchSelection {\n owner: boolean\n displaced: string | undefined\n}\n\n/** Fresh selection state: the plugin starts out not owning the selection. */\nexport function commandCodeSearchSelection(): CommandCodeSearchSelection {\n return { owner: false, displaced: undefined }\n}\n\n/**\n * Reach one end of the `webSearch` toggle without trampling sibling search\n * providers (issue #26).\n *\n * - Enabling writes `commandcode` and remembers whatever it displaced. When\n * the plugin already owns the selection (e.g. a settings save while still\n * on), the original `displaced` value is kept — the field currently holds\n * our own id, which must never be mistaken for the user's backend.\n * - Disabling hands the selection back to the remembered backend. When the\n * state holds no memory (a fresh boot straight into `webSearch: false`),\n * the field is left alone: the runtime's current value — a sibling's\n * cordis pin such as `searchProvider: modsearch`, or unset for\n * auto-select — already says what the user wants.\n * - When the field already reads `commandcode` at first touch (e.g. a\n * surviving runtime the plugin did not set, or a manual\n * `searchProvider: commandcode` pin), `displaced` stays undefined so the\n * later disable is a no-op rather than a guess at the factory default.\n *\n * Never throws: like the low-level rewrite, a hardened runtime shape degrades\n * to registered-but-unselected.\n */\nexport function applyCommandCodeSearchSelection(\n web: WebRuntime,\n state: CommandCodeSearchSelection,\n enable: boolean,\n): void {\n try {\n const field = web as unknown as WebRuntimeSearchField\n if (enable) {\n if (state.owner) {\n // Still on across a re-apply: re-assert without forgetting whom we displaced.\n field.searchProviderId = COMMANDCODE_SEARCH_PROVIDER_ID\n return\n }\n const prior = field.searchProviderId\n state.displaced = prior === COMMANDCODE_SEARCH_PROVIDER_ID ? undefined : prior\n field.searchProviderId = COMMANDCODE_SEARCH_PROVIDER_ID\n state.owner = true\n return\n }\n if (state.owner) {\n state.owner = false\n field.searchProviderId = state.displaced\n return\n }\n // Off without ever having taken over: nothing of ours to give back.\n } catch {\n // Hardened/frozen runtime: stay registered-but-unselected.\n }\n}\n\n/** Command Code's lower/upper bound on `numResults` (from the CLI's `web_search` schema). */\nconst MIN_NUM_RESULTS = 1\nconst MAX_NUM_RESULTS = 10\n/** CLI default when the caller sets no result cap. */\nconst DEFAULT_NUM_RESULTS = 5\n\n/** The endpoint the search POST goes to; `{apiBase}` is prepended. */\nconst SEARCH_ROUTE = '/alpha/web-search'\n\n/** Per-request facts the provider needs, all injected so the class stays cordis-free and testable. */\nexport interface CommandCodeSearchProviderDeps {\n /** Resolve one usable Command Code key (credential seam → env → auth file), or undefined when none. */\n resolveKey(): Promise<string | undefined>\n /** The API base host (defaults to `https://api.commandcode.ai`). */\n apiBase(): string\n /** Injectable fetch for tests; defaults to the global fetch. */\n fetchImpl?: typeof fetch\n}\n\n/**\n * Clamp a DSH `maxResults` bound into Command Code's 1–10 range, applying the\n * CLI default of 5 when the caller supplied none.\n */\nfunction clampNumResults(maxResults: number | undefined): number {\n return maxResults === undefined\n ? DEFAULT_NUM_RESULTS\n : Math.max(MIN_NUM_RESULTS, Math.min(MAX_NUM_RESULTS, Math.round(maxResults)))\n}\n\n/** Build a `WebSearchSource` from one raw `{ title, url, snippet }` result, omitting empty optional fields. */\nfunction toSource(result: { url?: string; title?: string; snippet?: string }): WebSearchSource | undefined {\n const url = result.url?.trim()\n if (url === undefined || url.length === 0) return undefined\n const title = result.title?.trim()\n const snippet = result.snippet?.trim()\n return {\n url,\n ...title !== undefined && title.length > 0 ? { title } : {},\n ...snippet !== undefined && snippet.length > 0 ? { snippet } : {},\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError'\n}\n\n/** Build the provider's stable cancellation error while retaining the caller's reason. */\nfunction searchAborted(signal: AbortSignal | undefined, fallback: unknown): WebError {\n return new WebError('Command Code web search aborted', 'WEB_ABORTED', {\n cause: signal?.aborted === true ? signal.reason : fallback,\n })\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) throw searchAborted(signal, undefined)\n}\n\n/**\n * A `ctx.web` search provider backed by the Command Code Provider API. Reuses\n * the plugin's credential chain and `apiBase`, so search \"just works\" with the\n * existing key — the model-facing `web_search` tool needs no separate\n * configuration. Selection between multiple search providers is the web seam's\n * job (pin `searchProvider: commandcode` if ambiguous).\n */\nexport class CommandCodeSearchProvider implements WebSearchProvider {\n readonly id = COMMANDCODE_SEARCH_PROVIDER_ID\n\n constructor(private readonly deps: CommandCodeSearchProviderDeps) {}\n\n /** Cheap local check; must not make network calls. Presence of a parseable base is enough. */\n available(): boolean {\n const base = this.deps.apiBase()\n return base.length > 0 && URL.canParse(base)\n }\n\n async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult> {\n throwIfAborted(signal)\n const apiBase = this.deps.apiBase()\n if (!URL.canParse(apiBase)) {\n throw new WebError(\n `Command Code web search is misconfigured: apiBase ${JSON.stringify(apiBase)} is not a valid URL`,\n 'WEB_PROVIDER_ERROR',\n )\n }\n const key = await this.resolveKey(signal)\n throwIfAborted(signal)\n const endpoint = `${apiBase.replace(/\\/$/, '')}${SEARCH_ROUTE}`\n\n const body = {\n query: request.query,\n numResults: clampNumResults(request.maxResults),\n }\n\n let response: Response\n try {\n response = await (this.deps.fetchImpl ?? fetch)(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n ...signal !== undefined ? { signal } : {},\n })\n } catch (error: unknown) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n throw new WebError(\n `Command Code web search request failed: ${error instanceof Error ? error.message : String(error)}`,\n 'WEB_PROVIDER_ERROR',\n { cause: error },\n )\n }\n\n if (!response.ok) {\n let message = `Command Code web search failed (HTTP ${response.status})`\n try {\n const parsed: unknown = await response.json()\n const detail = typeof parsed === 'object' && parsed !== null\n ? (parsed as { error?: unknown })?.error\n : undefined\n if (typeof detail === 'string' && detail.length > 0) message += `: ${detail}`\n else if (typeof detail === 'object' && detail !== null) {\n const code = (detail as { code?: unknown })?.code\n const inner = (detail as { message?: unknown })?.message\n if (typeof code === 'string' || typeof inner === 'string') {\n message += `: ${typeof code === 'string' ? code : ''}${typeof code === 'string' && typeof inner === 'string' ? ' — ' : ''}${typeof inner === 'string' ? inner : ''}`\n }\n }\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n // Non-JSON error bodies (proxy/gateway HTML): keep a truncated slice\n // so the status line still says something actionable.\n const text = await response.text().catch(() => '')\n const slice = text.trim().slice(0, 200)\n if (slice !== '') message += `: ${slice}`\n }\n throw new WebError(message, 'WEB_PROVIDER_ERROR')\n }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n throw new WebError('Command Code web search returned an unparseable response body', 'WEB_PROVIDER_ERROR', { cause: error })\n }\n\n const results = (payload as { results?: unknown })?.results\n if (!Array.isArray(results)) {\n throw new WebError(\n 'Command Code web search returned no results array (the server may have rejected the query)',\n 'WEB_PROVIDER_ERROR',\n )\n }\n\n const sources: WebSearchSource[] = []\n const seen = new Set<string>()\n for (const item of results) {\n if (typeof item !== 'object' || item === null) continue\n const source = toSource(item as { url?: string; title?: string; snippet?: string })\n if (source === undefined || seen.has(source.url)) continue\n seen.add(source.url)\n sources.push(source)\n }\n\n return { sources, truncated: false }\n }\n\n private async resolveKey(signal: AbortSignal | undefined): Promise<string> {\n let key: string | undefined\n try {\n key = await this.deps.resolveKey()\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n // Preserve the plugin's structured credential/usage taxonomy so the web\n // tool surfaces the real cause (e.g. every account exhausted, key\n // invalid) instead of a generic provider failure. The actionable\n // \"no key configured\" case maps to WEB_PROVIDER_CREDENTIAL_MISSING;\n // real rejection causes (INVALID_CREDENTIAL / RATE_LIMIT) keep their\n // message but ride the provider-error code the tool understands.\n if (error instanceof Error && typeof (error as HarnessError).code === 'string') {\n const code = (error as HarnessError).code\n if (code === 'MISSING_CREDENTIAL') throw new WebError(error.message, 'WEB_PROVIDER_CREDENTIAL_MISSING', { cause: error })\n if (code === 'INVALID_CREDENTIAL' || code === 'RATE_LIMIT') {\n throw new WebError(error.message, 'WEB_PROVIDER_ERROR', { cause: error })\n }\n }\n throw new WebError(\n `Command Code web search credential resolution failed: ${error instanceof Error ? error.message : String(error)}`,\n 'WEB_PROVIDER_ERROR',\n { cause: error },\n )\n }\n if (key === undefined || key.length === 0) {\n throw new WebError(\n 'Command Code web search has no API key; store COMMANDCODE_API_KEY through the credentials service (the web Models page writes it), export it in the launching environment, set config.apiKey, or run `command-code login` to write ~/.commandcode/auth.json',\n 'WEB_PROVIDER_CREDENTIAL_MISSING',\n )\n }\n return key\n }\n}\n","/**\n * dsh-TUI settings section (`tuiSettingsSections`).\n *\n * The terminal front door (dsh-TUI) owns its settings screen and asks plugins\n * only to DECLARE what is editable: a section over the plugin's own settings\n * namespace, which the screen renders and writes through the dsh settings\n * service. Without such a declaration a TUI-only user cannot enter the Command\n * Code API key at all — the web Models page is the only surface that writes\n * it, and dsh-TUI's own `/provider` wizard manages its `llm-pi-ai` routes\n * exclusively (issue #28).\n *\n * The seam is third-party, so this module carries LOCAL structural types\n * instead of importing `@deepseek-harness-tui/dsh-tui`: the plugin keeps zero\n * dependency on a terminal front door it may never meet, and an unmeet seam\n * degrades to \"no section\" rather than to a failed import. Registration rides\n * `ctx.inject(['tuiSettingsSections'], …)` in the plugin entry, so a profile\n * without dsh-TUI never activates the fiber — the same optional-service shape\n * `commands`, `web` and `typert` already use.\n *\n * The API-key field is a **secret** field: dsh-TUI keeps the literal out of\n * the settings document and writes the draft through the credentials seam\n * under the declared reference — the same guarantee the web card provides.\n * The reference must not collide with a host-owned one; dsh-TUI rejects\n * `DEEPSEEK_*`/`DSH_*` refs from plugin sections, and this plugin's default\n * (`COMMANDCODE_API_KEY`) is its own namespace.\n *\n * The model allowlist is a **checkbox per catalog model**, grouped by plan\n * tier — the terminal counterpart of the web page's searchable dropdown, and\n * the reason this page does not ask anyone to type 60+ model ids from memory.\n * dsh-TUI's seam has no multi-select kind (only `text | number | boolean |\n * select`) and no array element path a checkbox could own, so each model is\n * its own `boolean` field that WRITES THE WHOLE ARRAY through its `parse`:\n * the seam lets a field's write carry any value, which is what makes a\n * per-model checkbox express set membership. Two rules keep that honest.\n * (1) `parse` reads the allowlist LIVE through its thunk instead of the value\n * the field was built with, and rebuilds the array from THAT: the screen\n * stages several toggles into one save, so a captured base would let two\n * quick toggles resurrect each other's stale list. (2) An empty allowlist\n * means \"show every model\" to the adapter, so the checkboxes render the\n * EFFECTIVE set — unset shows everything checked, and checking a box only\n * records an explicit list once something is excluded.\n *\n * @module dsh-commandcode-provider/tui-settings\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n\nimport {\n KNOWN_PLANS,\n capabilityDescription,\n isFreeModel,\n} from './capabilities.ts'\n\n/** Provider-owned translations for one title, label, or hint. */\nexport interface TuiLocalizedText {\n readonly zh?: string\n readonly en?: string\n}\n\n/** Control kinds the dsh-TUI settings screen knows how to render. */\nexport type TuiSettingsFieldKind = 'text' | 'number' | 'boolean' | 'select'\n\n/** One choice of an options-bearing field. */\nexport interface TuiSettingsFieldOption {\n /** Stored value. */\n readonly value: string\n /** Display label (English; also the fallback). */\n readonly label: string\n /** Provider-owned translations for the label. */\n readonly descriptions?: TuiLocalizedText\n}\n\n/** The write one field's draft stages when the section is saved. */\nexport type TuiSettingsFieldWrite =\n | { readonly kind: 'set'; readonly value: unknown }\n | { readonly kind: 'clear' }\n\n/** One editable field inside a section. */\nexport interface TuiSettingsField {\n /** Key path from the section root, in the settings service's `mutate` vocabulary. */\n readonly path: readonly string[]\n /** Short field label (English; also the fallback). */\n readonly label: string\n /** Provider-owned translations for the label. */\n readonly descriptions?: TuiLocalizedText\n /** Optional one-line help rendered under the field. */\n readonly hint?: string\n /** Provider-owned translations for the hint. */\n readonly hintDescriptions?: TuiLocalizedText\n /** Optional group id; grouped fields render on that group's subpage. */\n readonly group?: string\n readonly kind: TuiSettingsFieldKind\n /**\n * Choices for an options-bearing field. A `text` field that carries options\n * is the TUI's own \"preset plus custom value\" shape: `←`/`→` cycle the\n * presets while Enter opens the text editor.\n */\n readonly options?: readonly TuiSettingsFieldOption[]\n /** Input placeholder for `kind: 'text' | 'number'`. */\n readonly placeholder?: string\n /**\n * Credential control: the literal never rides the settings document — the\n * draft starts blank on every open, a blank draft writes nothing, and a\n * typed draft writes through the credentials seam under `ref`.\n */\n readonly secret?: { readonly ref: string }\n /** Render a stored value as draft text. */\n readonly format?: (value: unknown) => string\n /** The write a draft text stages; `undefined` marks the draft invalid. */\n readonly parse?: (text: string) => TuiSettingsFieldWrite | undefined\n}\n\n/** Optional navigation group inside one section. */\nexport interface TuiSettingsGroup {\n /** Stable identifier, unique inside the section. */\n readonly id: string\n /** Group title (English; also the fallback). */\n readonly title: string\n /** Provider-owned translations for the title. */\n readonly descriptions?: TuiLocalizedText\n}\n\n/** One plugin's section inside the dsh-TUI settings screen. */\nexport interface TuiSettingsSection {\n /** Settings namespace this section edits. */\n readonly ns: string\n /** Section title (English; also the fallback). */\n readonly title: string\n /** Provider-owned translations for the title. */\n readonly descriptions?: TuiLocalizedText\n /** Optional navigation groups, in display order. */\n readonly groups?: readonly TuiSettingsGroup[]\n /** Editable fields, in display order. */\n readonly fields: readonly TuiSettingsField[]\n}\n\n/** The slice of the `tuiSettingsSections` service this module uses. */\nexport interface TuiSettingsSectionsService {\n /** Declare a section; the returned disposer withdraws it. */\n register(section: TuiSettingsSection): () => void\n}\n\n/** The selector value meaning \"no pinned account — follow rotation order\". */\nexport const ACTIVE_ACCOUNT_AUTO = 'auto'\n\n/** The selector value meaning \"no language override — follow the shell locale\". */\nexport const LANG_AUTO = 'auto'\n\n/** Tier display names, mirroring the web dropdown's headings (`model-select.ts`). */\nconst TIER_TITLES: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/** Tiers in picker order; a model outside this set joins the \"Other\" group. */\nconst TIER_ORDER: readonly string[] = ['go', 'goat', 'pro', 'provider', 'max']\n\n/** The group holding models this build's catalog does not know. */\nconst OTHER_GROUP_ID = 'models-other'\n\n/** One catalog model offered as a checkbox. */\nexport interface TuiModelChoice {\n /** Catalog model id, e.g. `deepseek/deepseek-v4-pro`. */\n readonly id: string\n /** Minimum plan tier key from `KNOWN_PLANS`. */\n readonly tier: string\n /** Whether the model is currently free, so it leads its group. */\n readonly free: boolean\n /** Footer hint for the focused row: plan tier · deal · peak · `Image`. */\n readonly hint: string\n}\n\n/**\n * Every model this build knows, in checkbox order: plan tier (Go first), then\n * free before paid inside a tier, then by id.\n *\n * The list is the static capability snapshot rather than a live catalog read\n * on purpose — a settings page must draw synchronously, and the snapshot is\n * synced from the same upstream table the picker's tier headings come from.\n * A model added upstream after this build still reaches the user: an empty\n * allowlist shows everything, and a model named in the allowlist but absent\n * here is rendered by the \"Other\" group instead of disappearing.\n */\nexport function commandCodeTuiModelChoices(): readonly TuiModelChoice[] {\n return Object.keys(KNOWN_PLANS)\n .map((id) => ({\n id,\n tier: KNOWN_PLANS[id] ?? '',\n free: isFreeModel(id),\n hint: capabilityDescription(id),\n }))\n .sort((a, b) => {\n const tierDelta = tierRank(a.tier) - tierRank(b.tier)\n if (tierDelta !== 0) return tierDelta\n if (a.free !== b.free) return a.free ? -1 : 1\n return a.id.localeCompare(b.id)\n })\n}\n\n/** Sort rank of a tier key; unknown tiers trail every known one. */\nfunction tierRank(tier: string): number {\n const rank = TIER_ORDER.indexOf(tier)\n return rank === -1 ? TIER_ORDER.length : rank\n}\n\n/** The stored allowlist as a clean id list (non-strings and blanks dropped). */\nfunction storedIds(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((id): id is string => typeof id === 'string' && id !== '')\n : []\n}\n\n/** Everything the section needs from the plugin entry. */\nexport interface CommandCodeTuiSettingsDeps {\n /** The plugin's settings namespace (`llm-commandcode`). */\n ns: string\n /** Section title; defaults to `Command Code`. */\n title?: string\n /**\n * The credential reference the API-key field writes through, read per\n * registration so a `Config.apiKeyEnv` change re-targets the field instead\n * of silently writing to the old reference.\n */\n apiKeyRef: () => string\n /**\n * Account slots for the active-account selector, in rotation order, read\n * per registration. A changed list re-registers the section (see\n * {@link applyCommandCodeTuiSettings}).\n */\n accountSlots: () => readonly { id: string; label: string }[]\n /**\n * The stored model allowlist, read LIVE at save time. A checkbox judges its\n * inherited state against this, so it must be read when the write runs, not\n * captured when the section was registered. An empty list means \"every model\n * is visible\" (the adapter's rule).\n */\n visibleModels: () => readonly string[]\n /**\n * The per-model override map the checkboxes write, read per registration so\n * ids this build's catalog does not know still get a row of their own. Same\n * live-read rule as {@link visibleModels}.\n */\n modelVisibility?: () => Readonly<Record<string, boolean>> | undefined\n /** The models to offer as checkboxes; defaults to the static snapshot. */\n modelChoices?: () => readonly TuiModelChoice[]\n}\n\n/**\n * Build the section descriptor. Pure, so tests can pin the exact fields\n * without a dsh-TUI host.\n *\n * Field choices worth keeping: the two option-bearing fields (`activeAccount`,\n * `lang`) are `text` + `options` rather than `select`, because a `select`\n * cannot express \"unset\" — cycling only ever lands on a declared option, so a\n * `select` would strand the user on a pinned value with no way back to\n * automatic. The `auto` sentinel plus a `parse` that clears the path keeps the\n * unset state reachable. `filterModelsByPlan` formats its EFFECTIVE default\n * (unset means true at the adapter), so a fresh install reads true instead of\n * the screen's \"(empty)\".\n */\nexport function buildCommandCodeTuiSection(\n deps: CommandCodeTuiSettingsDeps,\n): TuiSettingsSection {\n const ref = deps.apiKeyRef()\n const slots = deps.accountSlots()\n const choices = (deps.modelChoices ?? commandCodeTuiModelChoices)()\n const catalogIds = choices.map((choice) => choice.id)\n const known = new Set(catalogIds)\n // An empty allowlist means \"show every model\" at the adapter, so an\n // unchecked-for-no-reason model reads as visible. The stored facts are read\n // live by each field, never captured here.\n const stored = storedIds(deps.visibleModels())\n const overrides = deps.modelVisibility?.() ?? {}\n // Models this build's catalog cannot place (retired or renamed upstream, or\n // added after this snapshot) plus stored-but-unknown ids. They get their own\n // group so they stay visible and switchable instead of silently sticking.\n const extras = [...new Set([...stored, ...Object.keys(overrides)])].filter((id) => !known.has(id))\n\n const tierGroups = TIER_ORDER\n .filter((tier) => choices.some((choice) => choice.tier === tier))\n .map((tier) => ({\n id: `models-${tier}`,\n title: `${TIER_TITLES[tier] ?? tier} models`,\n descriptions: { zh: `${TIER_TITLES[tier] ?? tier} 模型` },\n }))\n // Models this snapshot cannot place (a tier added upstream) share the group\n // with the stored-but-unknown allowlist entries.\n const unranked = choices.filter((choice) => tierRank(choice.tier) === TIER_ORDER.length)\n const otherGroup = unranked.length > 0 || extras.length > 0\n ? [{ id: OTHER_GROUP_ID, title: 'Other models', descriptions: { zh: '其他模型' } }]\n : []\n\n /**\n * One checkbox: a boolean at a path of its OWN (`modelVisibility.<id>`).\n *\n * The path must be unique per model. dsh-TUI keys a staged draft by the\n * field's path (`fieldKey`), so N checkboxes sharing `visibleModels` share\n * ONE draft: every one of them then parses that same draft on save, all N\n * write ops address the same path, and only the LAST field's op survives —\n * which silently rewrote the allowlist from the last catalog model instead\n * of the one that was toggled. A per-model key is what makes a checkbox\n * express one model's state.\n *\n * An override equal to what the array already says is written as a CLEAR, so\n * toggling a model back to its inherited state leaves no residue and the\n * document stays minimal.\n */\n const modelField = (id: string, hint: string, group: string): TuiSettingsField => ({\n path: ['modelVisibility', id],\n group,\n kind: 'boolean',\n label: id,\n ...(hint === '' ? {} : { hint }),\n format: (value) => {\n if (typeof value === 'boolean') return String(value)\n // No override: the model follows the array allowlist, where empty or\n // unset means \"everything is visible\".\n const listed = storedIds(deps.visibleModels())\n return String(listed.length === 0 || listed.includes(id))\n },\n parse: (text) => {\n const on = text.trim() === 'true'\n // Read the array LIVE, not at registration time: the screen stages a\n // toggle and saves it later, and the inherited state must be judged\n // against what the document holds when the write runs.\n const listed = storedIds(deps.visibleModels())\n const inherited = listed.length === 0 || listed.includes(id)\n return on === inherited ? { kind: 'clear' } : { kind: 'set', value: on }\n },\n })\n\n return {\n ns: deps.ns,\n title: deps.title ?? 'Command Code',\n descriptions: { zh: 'Command Code(非官方)' },\n groups: [\n { id: 'connection', title: 'Connection', descriptions: { zh: '连接' } },\n { id: 'models', title: 'Models', descriptions: { zh: '模型' } },\n ...tierGroups,\n ...otherGroup,\n { id: 'advanced', title: 'Advanced', descriptions: { zh: '高级' } },\n ],\n fields: [\n {\n path: ['apiKey'],\n group: 'connection',\n kind: 'text',\n label: 'API key',\n descriptions: { zh: 'API 密钥' },\n secret: { ref },\n hint: `Stored in the credential store as ${ref}, never in settings.yaml.`,\n hintDescriptions: { zh: `保存在凭据库(${ref}),不会写入 settings.yaml。` },\n },\n {\n path: ['apiBase'],\n group: 'connection',\n kind: 'text',\n label: 'API base',\n descriptions: { zh: 'API 地址' },\n placeholder: 'https://api.commandcode.ai',\n hint: 'Leave empty for the public Command Code Provider API.',\n hintDescriptions: { zh: '留空即使用官方 Command Code Provider API。' },\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n },\n {\n path: ['filterModelsByPlan'],\n group: 'models',\n kind: 'boolean',\n label: 'Hide out-of-plan models',\n descriptions: { zh: '隐藏套餐外的模型' },\n hint: 'Keeps models above your subscription tier out of the picker. Fails open.',\n hintDescriptions: { zh: '在选择器里隐藏超出当前订阅档位的模型;判断不出来时全部显示。' },\n // Unset means \"filter\" at the adapter, so render the effective default\n // rather than letting the raw boolean format report an empty value.\n format: (value) => (value === false ? 'false' : 'true'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\n },\n ...choices\n .filter((choice) => tierRank(choice.tier) !== TIER_ORDER.length)\n .map((choice) => modelField(choice.id, choice.hint, `models-${choice.tier}`)),\n ...unranked.map((choice) => modelField(choice.id, choice.hint, OTHER_GROUP_ID)),\n ...extras.map((id) => modelField(id, capabilityDescription(id), OTHER_GROUP_ID)),\n {\n path: ['activeAccount'],\n group: 'advanced',\n kind: 'text',\n label: 'Active account',\n descriptions: { zh: '当前账号' },\n hint: 'A pinned account id, or auto to follow the rotation order.',\n hintDescriptions: { zh: '固定使用某个账号的 id;auto 表示按轮换顺序自动选择。' },\n options: [\n {\n value: ACTIVE_ACCOUNT_AUTO,\n label: 'Automatic (rotation order)',\n descriptions: { zh: '自动(按轮换顺序)' },\n },\n ...slots.map((slot) => ({\n value: slot.id,\n label: slot.label,\n descriptions: { zh: slot.label },\n })),\n ],\n format: (value) => (typeof value === 'string' && value.trim() !== '' ? value : ACTIVE_ACCOUNT_AUTO),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' || trimmed === ACTIVE_ACCOUNT_AUTO\n ? { kind: 'clear' }\n : { kind: 'set', value: trimmed }\n },\n },\n {\n path: ['lang'],\n group: 'advanced',\n kind: 'text',\n label: 'Command language',\n descriptions: { zh: '命令语言' },\n hint: 'Language of the /commandcode dashboard; auto follows the shell locale.',\n hintDescriptions: { zh: '/commandcode 用量面板的语言;auto 跟随终端 locale。' },\n options: [\n { value: LANG_AUTO, label: 'Automatic (shell locale)', descriptions: { zh: '自动(跟随终端 locale)' } },\n { value: 'zh', label: '中文' },\n { value: 'en', label: 'English' },\n ],\n format: (value) => (value === 'zh' || value === 'en' ? value : LANG_AUTO),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' || trimmed === LANG_AUTO\n ? { kind: 'clear' }\n : { kind: 'set', value: trimmed }\n },\n },\n ],\n }\n}\n\n/**\n * The `tuiSettingsSections` service, read defensively.\n *\n * The service name is declared by dsh-TUI's own module augmentation, which\n * this package deliberately does not import, so the typed `Context` has no\n * such property. The read goes through the REFLECTIVE `ctx.get` rather than a\n * bare property access: cordis refuses a property read for a service the fiber\n * never declared in `inject` (`cannot get property … without inject`), and an\n * unmeet seam must degrade to \"no section\" instead of throwing out of the\n * plugin's boot.\n */\nfunction tuiSettingsService(ctx: Context): TuiSettingsSectionsService | undefined {\n let candidate: unknown\n try {\n candidate = ctx.get('tuiSettingsSections')\n } catch {\n return undefined\n }\n if (typeof candidate !== 'object' || candidate === null) return undefined\n const register = (candidate as { register?: unknown }).register\n if (typeof register !== 'function') return undefined\n return {\n register: (register as (section: TuiSettingsSection) => () => void)\n .bind(candidate) as TuiSettingsSectionsService['register'],\n }\n}\n\n/**\n * Identity of everything in the section that can change at runtime: the\n * credential reference behind the API-key field, the account slots behind the\n * active-account selector, and the stored-but-unknown allowlist entries that\n * get a checkbox of their own. Re-registration is skipped while this matches,\n * so ordinary settings writes never churn the screen's section list — the\n * checkboxes themselves read their state live and need no re-declaration.\n */\nfunction sectionSignature(section: TuiSettingsSection): string {\n const active = section.fields.find((field) => field.path.join('.') === 'activeAccount')\n return JSON.stringify({\n secret: section.fields.find((field) => field.secret !== undefined)?.secret?.ref ?? '',\n options: active?.options?.map((option) => option.value) ?? [],\n // Only this group's membership can change the field LIST: every catalog\n // checkbox reads its own state live, so an ordinary toggle needs no\n // re-declaration.\n other: section.fields\n .filter((field) => field.group === OTHER_GROUP_ID)\n .map((field) => field.label),\n })\n}\n\n/**\n * Register the Command Code section on a dsh-TUI host.\n *\n * @param ctx - the context of an activated `tuiSettingsSections` injection.\n * @param deps - plugin-owned facts the section reads.\n * @returns a refresh function that re-registers the section when a fact it\n * renders changed (the plugin entry calls it from its settings `onChange`\n * hook), or `undefined` when the seam is unusable. The returned function is\n * inert after the fiber is torn down.\n */\nexport function applyCommandCodeTuiSettings(\n ctx: Context,\n deps: CommandCodeTuiSettingsDeps,\n): (() => void) | undefined {\n const service = tuiSettingsService(ctx)\n if (service === undefined) return undefined\n let disposed = false\n let current: { signature: string; dispose: () => void } | undefined\n const refresh = (): void => {\n if (disposed) return\n const section = buildCommandCodeTuiSection(deps)\n const signature = sectionSignature(section)\n if (current?.signature === signature) return\n // Withdraw before re-declaring: dsh-TUI keeps one section per namespace,\n // so a second register would otherwise be refused (or shadow the first,\n // depending on the host build) instead of replacing it.\n current?.dispose()\n current = undefined\n try {\n current = { signature, dispose: service.register(section) }\n } catch (error: unknown) {\n // A host that rejects the declaration (a shadow-mode capability policy,\n // a future contract change) must not take the plugin down with it: the\n // terminal simply keeps no Command Code page, and the web page plus\n // settings.yaml stay the fallback.\n ctx.logger?.warn(\n `llm-commandcode: could not register the dsh-TUI settings section: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n refresh()\n ctx.effect(() => () => {\n disposed = true\n current?.dispose()\n current = undefined\n }, 'dsh-commandcode-provider: tui settings section')\n return refresh\n}\n","/**\n * A bounded retry budget for `TRANSPORT` failures (issue #39, second report).\n *\n * The route's retry policy (`providerRetryPolicy` in `./adapter.ts`) is\n * deliberately near-unbounded: 1000 attempts with waits doubling to a 15-minute\n * cap. That shape exists for the failures a provider ASKS to have retried — an\n * exhausted 5-hour window, a Cloudflare 520 — where the wait is the point.\n *\n * A transport failure is not that. The reporter's second event at ~710k\n * context was `Connect Timeout Error ... timeout: 10000ms` (undici's own\n * connect timeout; this plugin's `requestTimeoutMs` is 60s) and, on another\n * attempt, `read ECONNRESET` against `/alpha/generate`. Because `TRANSPORT` is\n * in the whitelist, each of those entered the same 1000-attempt loop: with\n * `initialDelayMs: 500` doubling, the wait before attempt 11 alone is 512 s and\n * the cumulative wait before it is ~500 s — the \"模型请求重试已取消(11/1000)·\n * 482s\" the reporter photographed is that 512 s countdown, 30 s into it — and\n * those waits are counted BEFORE each retry attempt, not after it.\n *\n * A connection that cannot be established is either a sub-second blip (the\n * first few attempts recover it, invisibly) or an outage that no amount of\n * waiting inside one request will fix. So transport failures get their own\n * budget, and when it is exhausted the failure is surfaced with the diagnosis\n * instead of manufacturing a multi-minute stall. Waiting out a real outage is\n * the user's call — the next send starts a fresh budget — and\n * `dsh-llm-retry`'s window for rate limits is untouched.\n *\n * Deliberately NOT counted here: the pre-stream recovery the ADAPTER performs\n * inside one `stream()` call (account rotation on 429/401, the 413 image-budget\n * step-down, the Provider-API → CLI protocol switch). Those are invisible to\n * the caller and bounded on their own; this budget caps only the harness's\n * retry loop.\n *\n * Reset rule: the budget clears at each new STEP — one step is exactly one\n * model request (`step/start` is appended immediately before the call) — so the\n * cap is per logical request and the next step of the same turn gets its own\n * grace. `agent/status` → `idle` is NOT the reset signal even though it looks\n * like the natural one: the agent loop's `setPhase` emits it only on a status\n * CHANGE, and a turn's steps all run inside one `running` phase, so it never\n * fires between them — a budget reset only there would be per-turn, and an\n * outage would fail every later step of that turn immediately instead of\n * retrying each. `assistant/attempt` is wrong for the opposite reason: the loop\n * appends it for the FAILED attempt itself, *before* dispatching\n * `agent/request-error`, so resetting on it would clear the budget on every\n * failure and restore the very loop this module exists to stop.\n *\n * @module\n */\n\n/** Failure code this budget covers. */\nexport const TRANSPORT_FAILURE_CODE = 'TRANSPORT'\n\n/**\n * Transport failures to absorb before surfacing the failure, by default.\n *\n * The waits between the attempts come from the route policy's cadence\n * (`initialDelayMs: 500` doubling): the retries this setting buys are scheduled\n * 0.5 s, 1 s, 2 s, 4 s and 8 s after the failures that preceded them, so the\n * default absorbs an ordinary blip for ~15.5 s and then reports the failure\n * instead of continuing into the 16 s, 32 s … 15-minute waits. (Those figures\n * are the waits BEFORE each retry attempt, which is how the harness's own retry\n * chrome counts them — the `· 482s` on the reporter's row is one such wait.)\n */\nexport const DEFAULT_TRANSPORT_MAX_RETRIES = 5\n\n/**\n * Ceiling for {@link DEFAULT_TRANSPORT_MAX_RETRIES}'s setting.\n *\n * Deliberately far above the default rather than near it: raising the budget is\n * a legitimate answer to a genuinely flaky link, and the cap is a plausibility\n * bound, not a recommendation. The same number is mirrored in `Config`'s schema\n * and in the settings page's field bound (the client bundle cannot import this\n * node-side module); `tests/transport-retry.test.ts` pins the schema's bound\n * against this constant, which is what makes a drift visible.\n */\nexport const MAX_TRANSPORT_MAX_RETRIES = 50\n\n/** Why {@link absorbTransportFailure} answered the way it did. */\nexport type TransportRetryDecision = 'retry' | 'exhausted' | 'ignored'\n\n/** One agent's live transport-failure count, keyed weakly so a dropped agent cannot leak. */\nconst counts = new WeakMap<object, number>()\n\n/**\n * Count one attempt's outcome against the transport budget.\n *\n * @param agent - the identity the budget is scoped to (the agent object).\n * @param failureCode - the failed attempt's `LlmFailure.code`.\n * @param maxRetries - transport retries to absorb before the failure surfaces.\n * @returns `'ignored'` for any non-transport code (the route policy decides\n * those, unchanged), `'retry'` while the budget has room, `'exhausted'` once\n * it does not.\n */\nexport function absorbTransportFailure(\n agent: object,\n failureCode: string,\n maxRetries: number,\n): TransportRetryDecision {\n if (failureCode !== TRANSPORT_FAILURE_CODE) return 'ignored'\n const used = counts.get(agent) ?? 0\n if (used >= maxRetries) return 'exhausted'\n counts.set(agent, used + 1)\n return 'retry'\n}\n\n/** Clear one agent's transport budget (a new step starts, or the turn ended). */\nexport function resetTransportFailures(agent: object): void {\n counts.delete(agent)\n}\n\n/**\n * What one session event means for the transport budget.\n *\n * Exported and pure on purpose: the choice of event is the part of this design\n * that is easy to get plausibly wrong (`agent/status` → `idle` looks like the\n * natural reset and is not one — see the module comment), so it is stated once,\n * here, where a test can pin it, instead of being implied by a listener body.\n *\n * @param type - the appended session event's type.\n * @returns `'reset'` for a new step (one model request), `'forget'` when the\n * turn ended and the session → agent mapping is no longer needed, otherwise\n * `'none'`.\n */\nexport function transportResetAction(type: string): 'reset' | 'forget' | 'none' {\n if (type === 'step/start') return 'reset'\n if (type === 'turn/end') return 'forget'\n return 'none'\n}\n\n/**\n * The diagnosis a capped turn ends with. Bilingual, because the harness renders\n * a failed turn's message verbatim and this plugin's other user-facing failures\n * are bilingual too (see the adapter's error builders). It names the retry\n * budget and the checks that actually help, instead of the bare \"fetch failed\"\n * chain the retry chrome would otherwise show.\n */\nexport function transportBudgetMessage(failureMessage: string, maxRetries: number): string {\n return `${failureMessage}`\n + ';Command Code API 连接在连续重试后仍失败——已停止重试以免整轮卡死。'\n + `插件已自动重试 ${maxRetries} 次。通常说明当前网络到 api.commandcode.ai 的连接不通,`\n + '常见原因是代理未生效:DSH 只读取环境变量 HTTPS_PROXY/HTTP_PROXY(系统代理/PAC 不会被读取),'\n + '请确认启动 DSH 的终端里已导出代理,或先关闭代理直连后重试。网络恢复后直接重发即可'\n + ` — Command Code API transport still failed after ${maxRetries} automatic retries, which were`\n + ' stopped so the turn could not stall for minutes. This is a connectivity problem between this'\n + ' machine and api.commandcode.ai, not a context-window or request-size rejection. Common cause:'\n + ' the proxy is not reaching the harness — DSH reads HTTPS_PROXY/HTTP_PROXY from the environment'\n + ' only (a Windows system proxy/PAC setting is not consulted), so export it in the launching'\n + ' shell, or turn the proxy off and retry. Resend when the network recovers; the budget is per'\n + ' request and has been reset'\n}\n","/**\n * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command\n * Code (unofficial; ported from pi-commandcode-provider@0.5.1).\n *\n * Registers the `commandcode` provider route on `ctx.llm` and declares it in\n * the configurable-provider directory, so the web Models page shows a\n * \"Command Code\" card with an API-key field and the model picker lists the\n * live Command Code model catalog. Connection facts resolve per request over\n * the optional `llm-commandcode` user-settings section and the credential\n * seam, so a changed key, endpoint, or cache path reaches the next request\n * without a restart.\n *\n * ```yaml\n * - id: llm-commandcode\n * name: \"@mars-sea/dsh-commandcode-provider\"\n * config:\n * apiKeyEnv: COMMANDCODE_API_KEY\n * ```\n *\n * The `name` is the full package specifier as installed in the profile's\n * node_modules: the loader imports it as a module, and pnpm links packages by\n * their true (scoped) name — a bare `dsh-commandcode-provider` fails to\n * resolve (ERR_MODULE_NOT_FOUND) and crashes the app on boot. The value must\n * be quoted in YAML: an unquoted scalar starting with `@` fails to parse.\n *\n * @module dsh-commandcode-provider\n */\n\nimport { installCostProjection } from './cost-projection.ts'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { RequestErrorAction } from '@deepseek-ai/dsh-agent'\nimport type { WebRuntime } from '@deepseek-ai/dsh-web'\nimport z from '@deepseek-ai/schemastery'\nimport { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'\nimport { assertUsableApiKey, LlmError } from '@deepseek-ai/dsh-llm'\nimport { credentialRef, type CredentialRef } from '@deepseek-ai/dsh-credentials'\nimport { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'\nimport type {} from '@deepseek-ai/dsh-settings'\nimport { CommandCodeAdapter, DEFAULT_API_BASE, resolveAuthFileApiKey } from './adapter.ts'\nimport { DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS } from './adapter.ts'\nimport type { CommandCodeConnectionOptions, CommandCodeUsageReport } from './adapter.ts'\nimport { CommandCodeAccountPool, accountUsable, selectActiveAccount } from './accounts.ts'\nimport type { CommandCodeAccountConfig, CommandCodeAccountSlot, CommandCodeModelAccountRule } from './accounts.ts'\nimport { applyCommands } from './commands.ts'\nimport { applyUsageRemote } from './usage-remote.ts'\nimport type { CommandCodeAccountsReport, CommandCodeCatalog } from './usage-wire.ts'\nimport { CommandCodeLoginFlow } from './login.ts'\nimport type { CommandCodeLoginCredentials } from './login.ts'\nimport { pickCommandLocale, type LocaleId } from './command-locales.ts'\nimport { CommandCodeSearchProvider, applyCommandCodeSearchSelection, commandCodeSearchSelection } from './web-search.ts'\nimport { applyCommandCodeTuiSettings } from './tui-settings.ts'\nimport {\n DEFAULT_TRANSPORT_MAX_RETRIES,\n MAX_TRANSPORT_MAX_RETRIES,\n TRANSPORT_FAILURE_CODE,\n absorbTransportFailure,\n resetTransportFailures,\n transportBudgetMessage,\n transportResetAction,\n} from './transport-retry.ts'\nimport { KNOWN_PLANS } from './capabilities.ts'\n\nexport {\n COMMAND_CODE_CLI_VERSION,\n DEFAULT_API_BASE,\n DEFAULT_GENERATE_MAX_TOKENS,\n DEFAULT_MAX_OUTPUT_TOKENS,\n DEFAULT_REQUEST_TIMEOUT_MS,\n DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n CommandCodeAdapter,\n BILLING_ACCESS_TTL_MS,\n projectSlugFromPath,\n resolveAuthFileApiKey,\n} from './adapter.ts'\nexport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n KNOWN_THINKING_MODELS,\n KNOWN_PLANS,\n KNOWN_SUBSCRIPTION_PLANS,\n KNOWN_DEALS,\n KNOWN_PEAK_PRICING,\n PLAN_LABELS,\n PLAN_ORDER,\n capabilityDescription,\n compareByPlan,\n dealLabel,\n formatContext,\n modelVisibleInPlan,\n peakPricingLabel,\n peakPricingState,\n planLabel,\n subscriptionPlanInfo,\n} from './capabilities.ts'\nexport type { CommandCodeAdapterDeps, CommandCodeConnectionOptions, CommandCodeUsageReport, ResolveAttachments } from './adapter.ts'\nexport type { CommandCodeBillingAccess } from './capabilities.ts'\nexport { applyCommands, commandDefinition } from './commands.ts'\nexport type { CommandCodeCommandDeps } from './commands.ts'\nexport { applyUsageRemote, CommandCodeUsageService } from './usage-remote.ts'\nexport type { CommandCodeUsageDeps, LoginFlowFacade } from './usage-remote.ts'\nexport { USAGE_REPORT_ENDPOINT, usageReportSchema } from './usage-wire.ts'\nexport type { CommandCodeAccountUsage, CommandCodeAccountsReport } from './usage-wire.ts'\nexport {\n LOGIN_BEGIN_ENDPOINT,\n LOGIN_STATUS_ENDPOINT,\n LOGIN_CANCEL_ENDPOINT,\n parseLoginStatus,\n loginStatusSchema,\n} from './login-wire.ts'\nexport type {\n CommandCodeLoginStatus,\n CommandCodeLoginFailureReason,\n} from './login-wire.ts'\nexport {\n LOGIN_TIMEOUT_MS,\n LOGIN_START_PORT,\n LOGIN_MAX_PORT_ATTEMPTS,\n LOGIN_BODY_LIMIT_BYTES,\n LOGIN_ALLOWED_ORIGINS,\n buildCommandAuthUrl,\n studioBaseForApiBase,\n validateCommandApiKey,\n CommandCodeLoginFlow,\n} from './login.ts'\nexport type {\n CommandCodeLoginCredentials,\n CommandCodeLoginFlowDeps,\n ApiKeyValidation,\n} from './login.ts'\nexport { CommandCodeAccountPool, accountUsable, selectActiveAccount, matchModelRule, selectAccountForModel } from './accounts.ts'\nexport type { CommandCodeAccountConfig, CommandCodeAccountSlot, CommandCodeAccountState, CommandCodeModelAccountRule } from './accounts.ts'\nexport { CommandCodeSearchProvider, COMMANDCODE_SEARCH_PROVIDER_ID, DEFAULT_WEB_SEARCH_PROVIDER_ID, applyCommandCodeSearchSelection, commandCodeSearchSelection, selectCommandCodeSearchProvider } from './web-search.ts'\nexport type { CommandCodeSearchSelection } from './web-search.ts'\nexport type { CommandCodeSearchProviderDeps } from './web-search.ts'\nexport { ACTIVE_ACCOUNT_AUTO, LANG_AUTO, applyCommandCodeTuiSettings, buildCommandCodeTuiSection } from './tui-settings.ts'\nexport type {\n CommandCodeTuiSettingsDeps,\n TuiSettingsField,\n TuiSettingsFieldOption,\n TuiSettingsFieldWrite,\n TuiSettingsGroup,\n TuiSettingsSection,\n TuiSettingsSectionsService,\n} from './tui-settings.ts'\n\nexport const name = 'llm-commandcode'\nexport const inject = ['llm']\n\nconst NS = 'llm-commandcode'\nconst DEFAULT_API_KEY_ENV = 'COMMANDCODE_API_KEY'\n\n/** The single provider route this plugin owns. */\nexport const PROVIDER = 'commandcode'\n/** Default models cache path (mirrors the pi plugin's on-disk cache). */\nexport const DEFAULT_MODELS_CACHE_PATH = join(homedir(), '.commandcode', 'models-cache.json')\n\n/**\n * Plugin config, validated by the same-named schemastery schema and doubling\n * as the `llm-commandcode` settings-section shape. Every field is optional:\n * a missing API key resolves through {@link Config.apiKeyEnv} at each request\n * (the web Models page writes it), with the official Command Code CLI auth\n * file (`~/.commandcode/auth.json`) as the last fallback.\n */\nexport interface Config {\n /** Credential reference (environment-variable name) resolved per request; defaults to `COMMANDCODE_API_KEY`. */\n apiKeyEnv?: string\n /** Literal API key override (composition config only); takes precedence over `apiKeyEnv`. */\n apiKey?: string\n /** API base; defaults to the public Command Code Provider API. */\n apiBase?: string\n /** Working directory reported to the API; defaults to the process cwd. */\n workingDir?: string\n /** Model catalog cache path; defaults to `~/.commandcode/models-cache.json`. */\n modelsCachePath?: string\n /** Milliseconds to wait for the generate response's first byte; defaults to 60s. */\n requestTimeoutMs?: number\n /** Milliseconds a stream may stall before being treated as a dead connection; defaults to 300s. */\n streamIdleTimeoutMs?: number\n /**\n * Transport failures one request absorbs before the failure is surfaced;\n * defaults to 5. The route's retry policy is near-unbounded on purpose (1000\n * attempts, waits doubling to 15 minutes) because that shape is for the\n * failures a provider asks to have retried — an exhausted rate-limit window,\n * a gateway 520. A transport failure is not one of those: the first attempts\n * recover an ordinary blip (the default 5 retries are scheduled 0.5/1/2/4/8 s\n * after the failures before them, so ~15.5 s of grace), and after that the\n * wait is pure stall, so the retries are capped here. Raise it on a genuinely\n * flaky link; 0 surfaces every transport failure immediately.\n */\n transportMaxRetries?: number\n /**\n * Whether the model picker hides models above the account's subscription\n * tier; defaults to true. The filter fails open (unknown plan, billing\n * endpoint failure, or a positive on-demand credit balance all keep the\n * full catalog visible). Set false to always list every model.\n */\n filterModelsByPlan?: boolean\n /**\n * Visible-model allowlist: catalog model ids shown in pickers. Empty or\n * unset means \"show everything\". Persisted by the settings page's model\n * filter card; applies after the subscription-tier filter.\n */\n visibleModels?: string[]\n /**\n * Per-model visibility overrides from the terminal settings page's checkbox\n * list, keyed by catalog id (`true` = listed, `false` = hidden). An id here\n * decides that model on its own; an id absent here follows `visibleModels`.\n * dsh-TUI keys a staged edit by the field's path, so the checkboxes need one\n * path per model — a map — because a boolean field cannot express \"this id\n * is a member of the array\".\n */\n modelVisibility?: Record<string, boolean>\n /**\n * Extra accounts for multi-account rotation. The top-level\n * `apiKey`/`apiKeyEnv` (plus the CLI auth file) always form the first\n * (`default`) account; each entry here adds one more. When a request is\n * rejected pre-stream with 429 (usage window exhausted) or 401, the next\n * account's key retried transparently; when every account is exhausted the\n * request fails with a `RATE_LIMIT` error naming the earliest window\n * reset. Entries without `apiKey` or `apiKeyEnv` are ignored.\n */\n accounts?: CommandCodeAccountConfig[]\n /**\n * Manually selected active account: a slot id — `default`, or an extra\n * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). The\n * selected account serves whenever it is usable; an unknown id or an\n * exhausted selected account falls back to the first usable slot (automatic\n * rotation still applies). Unset means \"first usable account\".\n */\n activeAccount?: string\n /**\n * Model → account routing rules. Each rule lists catalog model ids to an\n * account slot id (`default`, or an extra account's credential reference).\n * When a request's model is in a rule's list and the routed account is\n * usable, that account serves — before the manual {@link activeAccount} and\n * the passive rotation order. A routed account that is exhausted or invalid\n * falls back to the normal selection, so the router is a hint, never a hard\n * gate. The first matching rule wins.\n */\n modelAccountRules?: CommandCodeModelAccountRule[]\n /**\n * Whether to use Command Code as the backend for dsh's model-facing\n * `web_search` tool. When enabled, the plugin registers a `commandcode`\n * search provider on `ctx.web` AND selects `commandcode` in the web seam\n * (so it wins over the shipped `deepseek-official` or a sibling search\n * plugin's pin), using the SAME Command Code API key/base as chat. When\n * disabled, the selection is handed back to whichever backend was there\n * before — turning it off never forces the factory default, so a sibling\n * search plugin (e.g. modsearch) keeps working (issue #26). The rewrite\n * rides dsh's internal `searchProviderId`, which is read per search call,\n * so a setting change lands on the next search without a restart.\n * Defaults to true.\n */\n webSearch?: boolean\n /**\n * Whether the Web sidebar shows the plans & quota card\n * (`sidebar.footer.action`). Defaults to false: the card is opt-in, so an\n * unset document renders no quota surface in the sidebar and mounts no\n * background usage poll for it. Only the sidebar entry is affected — the\n * dashboard cell behind it stays registered, it simply has no trigger until\n * the toggle is on. Read by the browser client; the adapter ignores it.\n */\n showSidebarQuota?: boolean\n /**\n * Language override for the `/commandcode` Host-side command's user-facing\n * copy. Host commands cannot read the client's `ctx.locale`, so this is\n * the explicit knob: `'zh'` or `'en'`. Unset means the command reads\n * `LC_ALL`/`LANG` from the launching shell, falling back to `'zh'`. The\n * web settings page is unaffected — it follows the browser's language\n * preference on its own. Two surfaces, two independent locales. The\n * declared type is `string` (the schemastery `pattern` cannot narrow\n * literal types); an unknown value is treated as \"unset\" by\n * `pickCommandLocale`.\n */\n lang?: string\n}\n\nexport const Config: z<Config> = z.object({\n apiKeyEnv: z.string().role('credential-ref').default(DEFAULT_API_KEY_ENV),\n // `role('secret')` is load-bearing, not decoration: a literal key is the one\n // credential path this plugin cannot keep out of a settings document (the\n // page writes through the credentials seam instead), so the harness must\n // strip it from every descriptor read (`settings.describe()` runs with\n // `redactSecrets: true`). Without the role the literal rides back to the\n // browser verbatim — including on a remote-Host setup, where that is another\n // machine. Same declaration as the official providers' `apiKey` field.\n apiKey: z.string().role('secret'),\n apiBase: z.string(),\n workingDir: z.string(),\n modelsCachePath: z.string(),\n requestTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),\n streamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),\n transportMaxRetries: z.number().min(0).max(MAX_TRANSPORT_MAX_RETRIES),\n filterModelsByPlan: z.boolean(),\n visibleModels: z.array(z.string()),\n /**\n * Per-model visibility overrides for the terminal settings page's checkbox\n * list, keyed by catalog id. dsh-TUI addresses a staged edit by its field\n * PATH, so two checkboxes sharing one path would overwrite each other's\n * draft and the section's last model would decide every write; a map gives\n * each checkbox a path of its own. An id listed here wins over\n * {@link visibleModels}; ids absent here keep following it.\n */\n modelVisibility: z.dict(z.boolean()),\n webSearch: z.boolean().default(true),\n showSidebarQuota: z.boolean().default(false),\n accounts: z.array(z.object({\n label: z.string(),\n apiKeyEnv: z.string().role('credential-ref'),\n /** Literal key for one extra slot; see the top-level `apiKey` secret note. */\n apiKey: z.string().role('secret'),\n })),\n activeAccount: z.string(),\n modelAccountRules: z.array(z.object({\n models: z.array(z.string()),\n account: z.string(),\n })),\n lang: z.string().pattern(/^(zh|en)$/).default('zh' as const),\n})\n\n/** One resolution's complete request facts: connection plus credential reference. */\nexport interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {\n apiKeyEnv: CredentialRef\n}\n\n/**\n * The one explicit resolve step from raw config to validated connection\n * facts. Programmatic construction may bypass Schemastery normalization, so\n * every default is re-judged here — for the composition entry at load and for\n * each settings snapshot at its first use.\n */\nexport function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions {\n return {\n apiKeyEnv: credentialRef(config.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n apiBase: config.apiBase ?? DEFAULT_API_BASE,\n workingDir: config.workingDir ?? process.cwd(),\n modelsCachePath: config.modelsCachePath ?? DEFAULT_MODELS_CACHE_PATH,\n requestTimeoutMs: config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n streamIdleTimeoutMs: config.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n filterModelsByPlan: config.filterModelsByPlan ?? true,\n visibleModels: Array.isArray(config.visibleModels)\n ? config.visibleModels.filter((id) => typeof id === 'string' && id !== '')\n : undefined,\n // Only real booleans survive: a hand-edited document can carry anything,\n // and a malformed flag must fall back to the array rather than hide a\n // model. An all-empty map is the same as no map.\n modelVisibility: readModelVisibility(config.modelVisibility),\n }\n}\n\n/**\n * Per-model visibility overrides, cleaned for the adapter. Programmatic\n * construction may bypass Schemastery normalization, so a non-object or a\n * non-boolean entry is dropped here instead of reaching the picker filter.\n * @param raw - The `modelVisibility` value from any config source.\n * @returns A frozen id → boolean map, or undefined when nothing is set.\n */\nfunction readModelVisibility(raw: unknown): Readonly<Record<string, boolean>> | undefined {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined\n const entries = Object.entries(raw).filter(\n (entry): entry is [string, boolean] => entry[0] !== '' && typeof entry[1] === 'boolean',\n )\n return entries.length === 0 ? undefined : Object.fromEntries(entries)\n}\n\nexport function apply(ctx: Context, config: Config): void {\n installCostProjection(ctx)\n let current: () => Config = () => config\n let lastRaw: Config | undefined\n let lastGood: ResolvedCommandCodeOptions | undefined\n const options = (): ResolvedCommandCodeOptions => {\n const raw = current()\n if (raw === lastRaw && lastGood !== undefined) return lastGood\n const next = resolveAdapterOptions(raw)\n lastRaw = raw\n lastGood = next\n return next\n }\n options()\n\n // The account slots, rebuilt from the live config on every resolution so\n // a settings-page accounts change reaches the very next request. The\n // top-level apiKey/apiKeyEnv (+ the CLI auth file) form the default\n // account; each config.accounts entry adds one more.\n const slots = (): CommandCodeAccountSlot[] => {\n const raw = current()\n const list: CommandCodeAccountSlot[] = [{\n id: 'default',\n label: 'Default',\n ref: credentialRef(raw.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n literal: raw.apiKey,\n allowAuthFile: true,\n }]\n for (const [index, account] of (raw.accounts ?? []).entries()) {\n const refName = typeof account.apiKeyEnv === 'string' && account.apiKeyEnv.trim() !== ''\n ? account.apiKeyEnv.trim()\n : undefined\n const literal = typeof account.apiKey === 'string' && account.apiKey !== '' ? account.apiKey : undefined\n if (refName === undefined && literal === undefined) continue\n list.push({\n // Slot ids must survive account-list edits: an extra's id is its\n // credential reference (stable across reorders/removals), falling\n // back to the positional id only for literal-only composition\n // entries, which no settings document can name anyway.\n id: refName ?? `account-${index + 2}`,\n label: typeof account.label === 'string' && account.label.trim() !== ''\n ? account.label.trim()\n : `Account ${index + 2}`,\n ref: refName === undefined ? undefined : credentialRef(refName),\n literal,\n allowAuthFile: false,\n })\n }\n return list\n }\n\n // The manually selected account (settings page / config), re-read per\n // resolution like every other settings-backed fact.\n const preferredId = (): string | undefined => {\n const raw = current().activeAccount\n return typeof raw === 'string' && raw.trim() !== '' ? raw.trim() : undefined\n }\n\n const resolveRef = async (ref: ReturnType<typeof credentialRef>): Promise<string | undefined> => {\n const credentials = ctx.get('credentials')\n if (credentials !== undefined) {\n // The credentials seam layers the process environment, the\n // provider-managed store, and `.env` files itself — a miss here is\n // genuinely unconfigured, not \"not in the store\".\n const hit = await credentials.resolve(ref)\n return hit?.value\n }\n const ambient = launchEnvironmentOf(ctx).get(ref)\n return ambient !== undefined && ambient.value.length > 0 ? ambient.value : undefined\n }\n\n // The multi-account pool: passive rotation only — a key is marked when a\n // request using it is actually rejected (429/401), and the marks are\n // re-checked against the live window limits only once every account is\n // marked, so the steady state costs zero extra API calls.\n // Explicit annotations break the pool↔adapter inference cycle (the pool's\n // probe calls the adapter; the adapter's rotation hook calls the pool).\n const pool: CommandCodeAccountPool = new CommandCodeAccountPool({\n slots,\n resolveRef,\n authFileKey: resolveAuthFileApiKey,\n // The adapter reference is assigned right below; the probe runs only at\n // request time, never during plugin startup.\n probeWindow: (apiKey: string) => adapter.probeFiveHourWindow(apiKey),\n preferredId,\n // Model → account routing rules, re-read per resolution like every\n // settings-backed fact.\n modelAccountRules: (): readonly CommandCodeModelAccountRule[] => current().modelAccountRules ?? [],\n })\n\n const resolveApiKey = async (connection: ResolvedCommandCodeOptions, model?: string): Promise<string> => {\n const resolved = await pool.resolveKey(model === undefined ? {} : { model })\n if (resolved !== undefined) {\n return assertUsableApiKey(resolved.key, 'llm-commandcode', resolved.slot.ref ?? `${resolved.slot.label} (config.apiKey)`)\n }\n const ref = connection.apiKeyEnv\n throw new LlmError(\n `llm-commandcode: no API key for provider route \"${PROVIDER}\"; store ${ref} through the`\n + ' credentials service (the web Models page writes it), export it in the launching'\n + ' environment, set config.apiKey, or run `command-code login` to write'\n + ' ~/.commandcode/auth.json',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter: CommandCodeAdapter<ResolvedCommandCodeOptions> = new CommandCodeAdapter({\n options,\n resolveApiKey,\n // Pre-stream 429/401: mark the rejected key and hand the adapter the next\n // account's key. When every account is exhausted the pool throws the\n // RATE_LIMIT/INVALID_CREDENTIAL error that names the earliest reset —\n // that error, not the raw 429, is what the caller sees.\n rotateApiKey: async (rejectedKey: string, rejection: 'rate-limit' | 'invalid-credential', _connection: ResolvedCommandCodeOptions, model?: string): Promise<string | undefined> => {\n pool.markRejected(rejectedKey, rejection)\n // Exclude the just-rejected key from probe-revival: a probe clearing its\n // window must not re-offer the same key within this request (the\n // adapter refuses already-tried keys); the next request picks it up.\n // The model rides along so model-routing rules pick the next account\n // for the same model.\n const resolved = await pool.resolveKey(\n model === undefined ? { exclude: rejectedKey } : { exclude: rejectedKey, model },\n )\n // Normalize like the initial resolution does: the pool keys its state\n // by the resolved key, so the adapter must send (and report back) the\n // same normalized form or the marks would miss.\n return resolved === undefined\n ? undefined\n : assertUsableApiKey(resolved.key, 'llm-commandcode', resolved.slot.ref ?? `${resolved.slot.label} (config.apiKey)`)\n },\n // The durable attachment service carries image bytes referenced by\n // ImageBlock; resolved lazily only when a request actually has images.\n resolveAttachments: () => {\n const attachments = ctx.get('attachments')\n return attachments === undefined ? undefined : attachments\n },\n })\n // The Models page card: a configurable provider with a settings address.\n // settingsPath [] means the whole `llm-commandcode` section configures it.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n // The live route: this is what makes models requestable under `commandcode`.\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n // Bounded retry for TRANSPORT failures (issue #39, second report). The route\n // policy is near-unbounded on purpose (see `providerRetryPolicy`), because\n // an exhausted rate-limit window or a gateway 520 is a failure that ASKS to\n // be retried — but a connection that cannot be established is not, and at the\n // long-context sizes this plugin serves the unbounded cadence turned a\n // 10-second TCP connect timeout into an ~8-minute stall (the reporter's\n // 11/1000 row, whose \"482s\" is the wait before the 11th attempt). So the\n // first few transport failures are absorbed here and the rest surface with a\n // diagnosis. `dsh-llm-retry` keeps its window for every other code.\n //\n // The failure is surfaced by THROWING out of the waterfall: the agent loop\n // wraps the rejection into the turn's error, so the retry chain stops here.\n // The failure's own message is carried in the thrown message (the loop may\n // re-wrap with the original), and the diagnostic also goes to the log, which\n // nothing can rewrite.\n const transportMaxRetries = (): number => {\n const value = current().transportMaxRetries\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) return DEFAULT_TRANSPORT_MAX_RETRIES\n return Math.min(Math.trunc(value), MAX_TRANSPORT_MAX_RETRIES)\n }\n // `async` is a type-level requirement, not a behavior change: the waterfall's\n // listener contract is `=> Promise<RequestErrorAction>`, so a handler that\n // returns `next()`'s promise on one path and a bare decision on another does\n // not type-check (`Promise<RequestErrorAction> | { kind: 'retry' }` is not\n // assignable, even though the runtime accepts both).\n //\n // The session → agent map exists for the reset below: `session/event` carries\n // the session, and the agent is the natural budget key (it is what the\n // request-error payload hands over). Weak on BOTH sides so a long-lived Host\n // cannot be held open by sessions whose turn never appended a `turn/end`.\n const sessionAgents = new WeakMap<object, object>()\n ctx.on('agent/request-error', async ({ agent, failure, signal }, next) => {\n // Checked BEFORE the budget: a cancelled turn is the user's own stop, so it\n // must neither be answered with a retry nor consume the slot a later live\n // failure needs.\n if (signal.aborted) return next()\n const session: unknown = Reflect.get(agent, 'session')\n if (typeof session === 'object' && session !== null) sessionAgents.set(session, agent)\n const decision = absorbTransportFailure(agent, failure.code, transportMaxRetries())\n if (decision === 'ignored') return next()\n // The literal is spelled as the event's own decision type; the union this\n // handler returns (`RequestErrorAction | Promise<RequestErrorAction>`) is\n // what the waterfall accepts, and `{ kind: 'retry' }` alone widens to\n // `string` and stops matching it.\n if (decision === 'retry') return { kind: 'retry' } satisfies RequestErrorAction\n const message = transportBudgetMessage(failure.message, transportMaxRetries())\n ctx.logger.warn(`llm-commandcode: transport retry budget exhausted for ${PROVIDER} (${TRANSPORT_FAILURE_CODE})`)\n throw new Error(message)\n })\n // Reset the budget at each new STEP — one step is exactly one model request\n // (`step/start` is appended immediately before the call), so this is what\n // makes the cap \"per logical request\" and gives the next step of the same\n // turn its own grace. `agent/status` → `idle` is deliberately NOT the reset\n // signal: `setPhase` emits it only on a status CHANGE, and a turn's steps run\n // inside one `running` phase, so it never fires between them — a budget reset\n // only there would be per-turn, and a network outage would fail every later\n // step of that turn instantly instead of retrying each. `assistant/attempt`\n // is wrong for the opposite reason: the loop appends it for the FAILED\n // attempt before dispatching `agent/request-error`, so resetting on it would\n // clear the budget on every failure. `idle` still clears the agent's count,\n // and the WeakMap drops a finished session on its own.\n ctx.on('session/event', (session, event) => {\n const action = transportResetAction(event.type)\n if (action === 'forget') {\n sessionAgents.delete(session)\n return\n }\n if (action !== 'reset') return\n const agent = sessionAgents.get(session)\n if (agent !== undefined) resetTransportFailures(agent)\n })\n ctx.on('agent/status', ({ agent, status }) => {\n if (status === 'idle') resetTransportFailures(agent)\n })\n\n // Per-account usage for the /commandcode dashboard and the settings\n // page's account card: every pool account (configured or not) gets one\n // entry, each fetched with its own key so plan/credit facts never mix.\n const usageReports = async (): Promise<CommandCodeAccountsReport> => {\n // describeAccounts (not deduped) so two slots sharing one credential are\n // both reported as configured; the active badge follows the deduped\n // serving selection.\n const described = await pool.describeAccounts()\n const byId = new Map(described.map((account) => [account.slot.id, account]))\n const active = selectActiveAccount(await pool.resolvedAccounts(), preferredId())\n const entries = await Promise.all(slots().map(async (slot) => {\n const account = byId.get(slot.id)\n let report: CommandCodeUsageReport\n if (account === undefined) {\n report = { failures: [] }\n } else {\n try {\n report = await adapter.getUsage(account.key)\n } catch (error: unknown) {\n report = { failures: [error instanceof Error ? error.message : String(error)] }\n }\n }\n const state = account?.state\n // The mark mirrors servability: a usable account (never marked, or a\n // cooldown whose reset passed) shows no mark; a cooldown without a\n // known reset still shows \"rate-limit\" (it is not serving).\n const usable = accountUsable(state)\n return {\n id: slot.id,\n label: slot.label,\n configured: account !== undefined,\n active: account !== undefined && active?.slot.id === slot.id,\n mark: usable ? '' : state?.kind === 'disabled' ? 'invalid-credential' : 'rate-limit',\n cooldownUntil: !usable && state?.kind === 'cooldown' ? state.until : 0,\n report,\n }\n }))\n return { accounts: entries }\n }\n\n // The /commandcode usage command rides the optional `commands` service: a\n // child fiber injects it, so it registers whenever the profile mounts\n // dsh-commands and the fiber simply never activates when it does not.\n // The command runs Host-side and has no access to the client's locale\n // service, so its language is resolved here from `Config.lang` (explicit\n // override) and the launching shell's `LC_ALL`/`LANG` (inferred default);\n // resolved per invocation so a settings change reaches the next command\n // run without a restart.\n const commandLocale = (): LocaleId => pickCommandLocale(current().lang)\n ctx.inject(['commands'], (commandCtx) => {\n applyCommands(commandCtx, { adapter, reports: usageReports, getLocale: commandLocale })\n })\n\n // The settings page's account card: getUsage exposed to the browser through\n // the Typert Gateway (`commandcode/report`). Rides the optional `typert`\n // registry service, so profiles without the web stack never activate it.\n // The same service also exposes the browser-login flow: the Host binds a\n // loopback callback server (the official `command-code login` dance) and\n // stores the delivered key through the credentials seam under the same\n // reference the default slot resolves — no restart, no settings document.\n const loginFlow = new CommandCodeLoginFlow({\n apiBase: () => options().apiBase,\n storeKey: async ({ apiKey }: CommandCodeLoginCredentials): Promise<void> => {\n const ref = credentialRef(current().apiKeyEnv ?? DEFAULT_API_KEY_ENV)\n const credentials = ctx.get('credentials')\n if (credentials === undefined) {\n throw new Error('the credentials service is unavailable in this profile; paste the key manually')\n }\n await credentials.set(ref, apiKey)\n },\n })\n ctx.effect(() => () => loginFlow.dispose(), 'dsh-commandcode-provider: login flow')\n // The full model catalog for the settings page's model editors (the\n // routing-rule editor and the visible-models filter): served Host-side\n // from the adapter's cached/fetched catalog (sorted for picking), so the\n // browser never calls the Command Code API directly. Unfiltered, so an\n // editor never loses its own options — e.g. a rule can route a GOAT-only\n // model while the picker (plan-filtered + allowlisted) hides it. Each\n // entry carries its plan-tier key so the editors can group under tier\n // headings without importing the Host's capability snapshot.\n const catalogForEditors = async (): Promise<CommandCodeCatalog> => {\n const models = await adapter.listModels(PROVIDER, { unfiltered: true })\n return {\n models: models.map((model) => {\n const tier = KNOWN_PLANS[model.id]\n return {\n id: model.id,\n name: model.name.replace(/\\s*\\(CC\\)$/, ''),\n ...(tier === undefined ? {} : { tier }),\n }\n }),\n }\n }\n applyUsageRemote(ctx, { adapter, reports: usageReports, login: loginFlow, listModels: catalogForEditors })\n\n // Web search over the Command Code Provider API, exposed through the web\n // capability seam (`ctx.web`). Rides the optional `web` service: a child\n // fiber injects it, so the provider registers whenever the profile mounts\n // the web stack and the fiber never activates when it does not (profiles\n // without web remain an LLM-provider-only plugin). It reuses the SAME\n // credential chain as the model adapter (pool.resolveKey → env → auth file)\n // and the same apiBase, so DSH's model-facing web_search tool needs no\n // separate key or endpoint config — a Command Code key works as-is.\n //\n // Whether the `commandcode` provider WINS over the shipped `deepseek-official`\n // (or a sibling search plugin's pin, e.g. modsearch) is controlled by\n // `Config.webSearch` (default on). The web seam has no public runtime\n // selector, so the plugin writes its private `searchProviderId` field (read\n // per call) via `applyCommandCodeSearchSelection`. A settings change lands\n // on the next search without a restart. See src/web-search.ts for why this\n // runtime write is safe and what it depends on.\n //\n // The tracked selection remembers whichever backend was displaced, so\n // turning the toggle off hands the selection back to it (issue #26) — the\n // disable path never forces the factory default. Disposing the fiber (the\n // plugin unloads) restores it the same way: without that, the stale\n // `commandcode` pin would outlive its unregistered provider and every\n // search would fail with WEB_PROVIDER_CONFIGURED_MISSING.\n const searchSelection = commandCodeSearchSelection()\n const applySearchSelection = (enabled: boolean): void => {\n if (webRuntime !== undefined) {\n applyCommandCodeSearchSelection(webRuntime, searchSelection, enabled)\n }\n }\n let webRuntime: WebRuntime | undefined\n ctx.inject(['web'], (webCtx) => {\n webRuntime = webCtx.web\n webCtx.web.registerSearchProvider(new CommandCodeSearchProvider({\n resolveKey: async () => {\n const resolved = await pool.resolveKey()\n return resolved === undefined ? undefined : resolved.key\n },\n apiBase: () => options().apiBase,\n }))\n // Apply the selection at boot too, so a profile WITHOUT the manual\n // `searchProvider: commandcode` cordis patch still routes web search to\n // Command Code once this plugin loads (default `webSearch` on).\n applySearchSelection(current().webSearch ?? true)\n // The fiber's disposer restores the displaced backend the same way the\n // toggle-off path does (`webCtx.effect` registers the inner function as\n // the fiber's teardown; a bare `return` from the inject callback would\n // not). Without this, the stale `commandcode` pin would outlive its\n // unregistered provider and every search would fail with\n // WEB_PROVIDER_CONFIGURED_MISSING.\n webCtx.effect(() => () => {\n webRuntime = undefined\n applyCommandCodeSearchSelection(webCtx.web, searchSelection, false)\n }, 'dsh-commandcode-provider: web search selection')\n })\n\n // The terminal front door (dsh-TUI) settings page. dsh-TUI owns its own\n // settings screen and only asks plugins to DECLARE what is editable, so\n // without this a TUI-only user has no way to enter the API key — the web\n // Models page is the only other surface that writes it, and dsh-TUI's\n // `/provider` wizard manages its own `llm-pi-ai` routes exclusively\n // (issue #28). The seam is an optional service, exactly like `commands`\n // and `web`: on a profile without dsh-TUI the fiber never activates, and\n // the plugin stays a plain LLM-provider bundle. The API-key field is a\n // secret field, so the literal goes to the credentials seam and never into\n // a settings document.\n let refreshTuiSettings: (() => void) | undefined\n ctx.inject(['tuiSettingsSections'], (tuiCtx) => {\n refreshTuiSettings = applyCommandCodeTuiSettings(tuiCtx, {\n ns: NS,\n // Read per registration, so a `Config.apiKeyEnv` change re-targets the\n // key field instead of leaving it writing to the previous reference.\n apiKeyRef: () => current().apiKeyEnv ?? DEFAULT_API_KEY_ENV,\n // The account slots behind the active-account selector. The section is\n // re-registered when this list changes (the refresh call below), since\n // the host renders a fixed option list per declaration.\n accountSlots: () => slots().map((slot) => ({ id: slot.id, label: slot.label })),\n // The model allowlist is read LIVE on every toggle: a checkbox judges\n // its inherited state against the current document, not against\n // whatever the declaration happened to be registered with. The override\n // map is read here too, so an id this build's catalog does not place\n // still gets a row of its own.\n visibleModels: () => options().visibleModels ?? [],\n modelVisibility: () => options().modelVisibility,\n })\n tuiCtx.effect(() => () => {\n refreshTuiSettings = undefined\n }, 'dsh-commandcode-provider: tui settings handle')\n })\n\n // Settings became an optional service in dsh 0.1.2. Register the section\n // through its provider when present; profiles without settings continue to\n // use the composition entry captured by `current` above.\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.settings.installSection(ctx, NS, Config, config, {\n setSource: (source) => {\n current = source\n },\n // Re-apply the web search selection on every settings change so the\n // `webSearch` toggle reaches the web seam's next search without a\n // restart. The tracked state remembers the displaced backend (issue\n // #26), so flipping the toggle is a handoff, not an overwrite. The\n // adapter's own facts are resolved per request, so nothing else needs\n // registration-level action here.\n //\n // The dsh-TUI section is refreshed from the same hook: its key field\n // follows `apiKeyEnv` and its account selector follows `accounts`, and\n // both are frozen into the declaration the host renders. The refresh is\n // a no-op unless one of those facts actually moved, so ordinary writes\n // (the key itself, the model filters) never churn the screen.\n onChange: () => {\n applySearchSelection(current().webSearch ?? true)\n refreshTuiSettings?.()\n },\n })\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["record","record","stringField","reject","createNetServer","createHttpServer"],"sources":["../src/capabilities.ts","../src/model-prices.ts","../src/cost-facts.ts","../src/cost-projection.ts","../src/accounts.ts","../src/image-request.ts","../src/image-tokens.ts","../src/adapter.ts","../src/command-locales.ts","../src/commands.ts","../src/wire-shared.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/usage-remote.ts","../src/login.ts","../src/web-search.ts","../src/tui-settings.ts","../src/transport-retry.ts","../src/index.ts"],"sourcesContent":["/**\n * Static capability snapshot for the Command Code provider: model →\n * reasoning-effort levels, vision/thinking flags, model → minimum plan tier,\n * subscription-plan labels, deals, and hourly (peak/off-peak) pricing.\n *\n * Everything in this module is synced from official sources (the command-code\n * CLI bundle's model table and the official plan/pricing/model docs — see the\n * dsh-commandcode-upstream skill for the exact extraction procedures), and\n * changes whenever an upstream CLI release reshuffles models/plans/prices.\n * Keeping the snapshot in its own module confines those frequent sync diffs\n * here: src/adapter.ts holds only the stable wire/runtime logic and imports\n * these tables + read helpers.\n *\n * Snapshot read helpers (planLabel, dealLabel, formatContext,\n * capabilityDescription, peakPricing*, compareByPlan, modelVisibleInPlan,\n * subscriptionPlanInfo, isFreeModel) live here too — they exist only to read\n * the tables, so a sync never has to touch src/adapter.ts.\n *\n * Ported from pi-commandcode-provider (MIT); originally part of src/adapter.ts\n * and split out so upstream syncs stay reviewable.\n */\n// ---------------------------------------------------------------------------\n// Static capability snapshot (from the official command-code@1.53.0 bundled\n// model catalog, dist/cli.mjs). The Provider API does not expose reasoning\n// metadata; models omitted here let Command Code choose their reasoning\n// depth, matching the official CLI.\n// ---------------------------------------------------------------------------\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n // Re-verified against the authoritative command-code@1.53.0 bundled model\n // table (dist/cli.mjs, the provider effort map): exactly these models carry\n // selectable efforts. Models marked 'reasoning:!0' without efforts\n // (e.g. Tencent Hy3, GLM-5/5.1/5.2-Fast)\n // think automatically and are absent here - the CLI omits\n // 'reasoning_effort' for them, so the picker must not offer a selector. Do\n // NOT add entries from the OAuth provider tables (anthropic/openai) - only\n // the Provider-API table is authoritative for this plugin's route.\n // `stealth/ox-alpha` (['low', 'high', 'max']) was removed in\n // command-code@1.34.0 when its preview ended; its successor,\n // `z-ai/glm-5.3-flash`, ships the same effort set.\n // `tencent/hy4-preview` gained ['low', 'medium', 'high'] in\n // command-code@1.38.0 (it previously thought automatically with no\n // selectable levels).\n // `moonshotai/Kimi-K3` gained ['low', 'high', 'max'] in command-code@1.39.3\n // (it previously thought automatically with no selectable levels).\n // `claude-fable-5-1` (Claude Fable 5.1, command-code@1.40.0) ships the same\n // five-level effort set as its predecessor `claude-fable-5` and is served\n // by the Provider API (the Provider/Max tier; see KNOWN_PLANS).\n // command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` and command-code@1.43.0\n // added `google/gemini-3.8-flash`; both carry effort sets matching their\n // existing family members. command-code@1.45.0 added selectable\n // ['low', 'medium', 'high', 'xhigh'] efforts for the Muse Spark family\n // (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor); they previously reasoned\n // automatically with no selectable levels. command-code@1.48.0 added the\n // `max` effort tier to Muse Spark 1.3 (previously ['low','medium','high',\n // 'xhigh']); 1.3 and 1.3-contributor now ship different effort sets.\n // command-code@1.49.0 added `gpt-6-astra` with the five-level effort set.\n // command-code@1.51.0 briefly added `deepseek/deepseek-v4.1-flash-beta`\n // (text+image, reasoning without selectable efforts, hidden behind a\n // 2026-09-10 expiry gate); command-code@1.51.2 removed it from the bundle\n // entirely, so no snapshot entry is needed.\n 'Qwen/Qwen3.8-Max': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-Max-0902': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-27B': ['low', 'medium', 'xhigh'],\n 'Qwen/Qwen3.8-Flash': ['low', 'medium', 'xhigh'],\n 'claude-fable-5-1': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-fable-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-7': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-8': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-4-6': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n // `deepseek/deepseek-v4-flash-fast` joined in command-code@1.39.0\n // (\"Add DeepSeek V4 Flash Fast\"); 1.39.1 dropped `medium` for it, and\n // the 1.39.2 table ships ['low', 'high', 'max'].\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0 added DeepSeek V4.1 Flash (\"Add new\n // deepseek/deepseek-v4.1-flash model\"); the bundle ships\n // ['low', 'high', 'max'] for it.\n 'deepseek/deepseek-v4.1-flash': ['low', 'high', 'max'],\n 'deepseek/deepseek-v4-flash': ['high', 'max'],\n 'deepseek/deepseek-v4-flash-vision-exp': ['high', 'max'],\n 'deepseek/deepseek-v4-pro': ['high', 'max'],\n 'google/gemini-3.1-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.6-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.7-flash': ['low', 'medium', 'high'],\n 'gpt-5.3-codex': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4-mini': ['low', 'medium', 'high'],\n 'gpt-5.5': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-sol': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-terra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // `moonshotai/Kimi-K3` gained selectable ['low', 'high', 'max'] efforts in\n // command-code@1.39.3 (\"Add low, high, and max reasoning effort support for\n // Kimi K3\"); it previously reasoned automatically with no levels.\n 'moonshotai/Kimi-K3': ['low', 'high', 'max'],\n // command-code@1.43.0 added Gemini 3.8 Flash with the same three-level\n // effort set as the rest of the Gemini Flash family.\n 'google/gemini-3.8-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n 'tencent/hy4-preview': ['low', 'medium', 'high'],\n 'xai/grok-4.5': ['low', 'medium', 'high'],\n 'xai/grok-4.6': ['low', 'medium', 'high', 'xhigh'],\n 'z-ai/glm-5.3-flash': ['low', 'high', 'max'],\n 'zai-org/GLM-5.2': ['high', 'max'],\n 'zai-org/GLM-5.3': ['low', 'high', 'max'],\n // Muse Spark family (command-code@1.45.0: \"Reasoning levels for Muse\n // Spark 1.3\") gained selectable ['low', 'medium', 'high', 'xhigh'] efforts\n // — they previously reasoned automatically with no levels.\n 'meta/muse-spark-1.1': ['low', 'medium', 'high', 'xhigh'],\n 'meta/muse-spark-1.2': ['low', 'medium', 'high', 'xhigh'],\n 'meta/muse-spark-1.2-contributor': ['low', 'medium', 'high', 'xhigh'],\n // command-code@1.48.0 added `max` to Muse Spark 1.3; 1.3-contributor keeps\n // the four-level set.\n 'meta/muse-spark-1.3': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'meta/muse-spark-1.3-contributor': ['low', 'medium', 'high', 'xhigh'],\n // command-code@1.49.0 added GPT-6 Astra with the full five-level effort set.\n 'gpt-6-astra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.51.3 gave MiniMax M3 selectable ['low', 'medium', 'high']\n // efforts (it previously reasoned automatically with no levels and lived in\n // KNOWN_THINKING_MODELS; the hidden `minimax/minimax-m3-free` sibling gained\n // the same set in the bundle). No CLI changelog entry exists for 1.51.1–1.51.3\n // yet — this was read from the 1.51.3 bundled model table.\n // command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free` with\n // automatic reasoning and no selectable efforts, so the effort map is\n // unchanged by that release.\n 'MiniMaxAI/MiniMax-M3': ['low', 'medium', 'high'],\n}\n\n/**\n * Models whose Capabilities include Vision, per the official Command Code\n * model registry (`https://commandcode.ai/docs/reference/cli/models`, generated\n * from the same registry as `cmd --list-models` / the `/model` picker).\n *\n * The Provider API does not expose modality metadata, so this snapshot is the\n * source of truth for image-input gating. Command Code's own CLI falls back to\n * a client-side VISION side-call for text-only models; this adapter does not\n * reproduce that interactive feature, so images sent to a model outside this\n * list are refused loudly (`UNSUPPORTED_CONTENT`) instead of being dropped or\n * sent to a model that cannot read them.\n *\n * Keep in sync with the official registry when new models ship (see the\n * dsh-commandcode-upstream skill).\n */\nexport const KNOWN_IMAGE_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.6-Plus',\n 'Qwen/Qwen3.7-Flash',\n 'Qwen/Qwen3.7-Plus',\n 'Qwen/Qwen3.8-27B',\n 'Qwen/Qwen3.8-Flash',\n 'Qwen/Qwen3.8-Max',\n // command-code@1.41.0 added Qwen 3.8 Max 0902; Vision per the official\n // registry (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'Qwen/Qwen3.8-Max-0902',\n 'claude-fable-5-1',\n 'claude-fable-5',\n 'claude-haiku-4-5-20251001',\n 'claude-opus-4-7',\n 'claude-opus-4-8',\n 'claude-opus-5',\n 'claude-sonnet-4-6',\n 'claude-sonnet-5',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0 added DeepSeek V4.1 Flash; Vision per the official\n // registry (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'deepseek/deepseek-v4.1-flash',\n 'google/gemini-3.1-flash-lite',\n 'google/gemini-3.5-flash',\n 'google/gemini-3.5-flash-lite',\n 'google/gemini-3.6-flash',\n 'google/gemini-3.7-flash',\n // command-code@1.43.0 added Gemini 3.8 Flash; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"].\n 'google/gemini-3.8-flash',\n 'gpt-5.3-codex',\n 'gpt-5.4',\n 'gpt-5.4-mini',\n 'gpt-5.5',\n 'gpt-5.6-luna',\n 'gpt-5.6-sol',\n 'gpt-5.6-terra',\n // command-code@1.49.0 added GPT-6 Astra; Vision per the official registry\n // and the CLI's inputModalities:[\"text\",\"image\"].\n 'gpt-6-astra',\n // command-code@1.44.0 added Muse Spark 1.3 and its Contributor sibling;\n // both are Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'meta/muse-spark-1.1',\n 'meta/muse-spark-1.2',\n 'meta/muse-spark-1.2-contributor',\n 'meta/muse-spark-1.3',\n 'meta/muse-spark-1.3-contributor',\n 'moonshotai/Kimi-K2.5',\n 'moonshotai/Kimi-K2.6',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'moonshotai/Kimi-K3',\n 'sakana/fugu-ultra',\n 'stepfun/Step-3.7-Flash',\n 'thinkingmachines/inkling',\n 'thinkingmachines/inkling-small',\n 'xai/grok-4.5',\n // command-code@1.47.0 marked Grok 4.6 vision-capable (it was text-only in\n // 1.46.0); re-verified present in the 1.53.0 bundle's\n // inputModalities:[\"text\",\"image\"] entries.\n 'xai/grok-4.6',\n 'xiaomi/mimo-v2.5',\n 'z-ai/glm-5.3-flash',\n])\n\n/**\n * Models the official CLI's model table (command-code@1.53.0) marks\n * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they\n * think automatically, with Command Code driving the depth. This is the\n * authoritative \"thinks, effort not adjustable\" set: `KNOWN_EFFORTS` (which\n * mirrors the CLI's effort map exactly) stays the sole source for selectable\n * effort levels, and this snapshot is not surfaced in the picker's compact\n * description — it exists for programmatic consumers.\n *\n * Source: the command-code@1.53.0 bundled model table (dist/cli.mjs),\n * cross-checked with https://commandcode.ai/docs/reference/cli/models.\n * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it\n * selectable `['low', 'high', 'max']` efforts; the preview then ended in\n * 1.34.0, removing the model from the catalog entirely. `tencent/hy4-preview`\n * joined this set in command-code@1.37.0 — reasoning:!0, no efforts, 1M\n * context, routed through OpenRouter — then gained selectable\n * `['low', 'medium', 'high']` efforts in command-code@1.38.0 and moved to\n * `KNOWN_EFFORTS`. `moonshotai/Kimi-K3` followed the same path in\n * command-code@1.39.3 — it gained `['low', 'high', 'max']` efforts and moved\n * to `KNOWN_EFFORTS`. command-code@1.42.0 added `meituan/LongCat-2.0:free`\n * (reasoning:!0, no efforts). command-code@1.45.0 gave the Muse Spark family\n * (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor) selectable\n * `['low', 'medium', 'high', 'xhigh']` efforts — they moved to `KNOWN_EFFORTS`.\n * command-code@1.51.3 gave `MiniMaxAI/MiniMax-M3` selectable\n * `['low', 'medium', 'high']` efforts — it moved to `KNOWN_EFFORTS` too.\n * command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free`\n * (reasoning:!0, no efforts).)\n * command-code@1.53.0 added `deepseek/deepseek-v4.1-flash` with selectable\n * ['low', 'high', 'max'] efforts, so it lives in `KNOWN_EFFORTS`, not here.)\n * Keep in sync via the dsh-commandcode-upstream skill.\n */\nexport const KNOWN_THINKING_MODELS: ReadonlySet<string> = new Set([\n 'Qwen/Qwen3.6-Max-Preview',\n 'Qwen/Qwen3.6-Plus',\n 'Qwen/Qwen3.7-Flash',\n 'Qwen/Qwen3.7-Max',\n 'Qwen/Qwen3.7-Plus',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'stepfun/Step-3.5-Flash',\n 'stepfun/Step-3.7-Flash',\n 'tencent/hy3-paid',\n 'nvidia/nemotron-3-ultra-550b-a55b',\n 'thinkingmachines/inkling',\n 'thinkingmachines/inkling-small',\n 'poolside/laguna-s-2.1-free',\n // LongCat 2.0 (command-code@1.42.0, Meituan's trillion-parameter coding\n // model, 1M context) is free and text-only, with automatic reasoning.\n 'meituan/LongCat-2.0:free',\n // Ling 3.0 Flash Sante (command-code@1.52.0, 262K context, text-only) is\n // free and reasons automatically with no selectable efforts.\n 'inclusionai/ling-3.0-flash-sante:free',\n])\n\n/**\n * Catalog models the Provider API serves ONLY through `/provider/v1/messages`\n * (Anthropic Messages shape). Every other model in the catalog answers on\n * `/provider/v1/chat/completions`; these reject it outright with HTTP 400\n * `Model \"<id>\" must be called via /provider/v1/messages (Anthropic Messages\n * shape)`.\n *\n * Measured 2026-09-16 against the live catalog (command-code@1.54.0): all 69\n * models were posted to `/provider/v1/chat/completions`; exactly these eight\n * — the whole Claude family — refused, and every one of them is routed\n * normally by `/alpha/generate` (a lower-plan key gets the ordinary\n * `MODEL_NOT_IN_PLAN` 403 there, never a routing error). So the CLI transport\n * is a complete fallback and the adapter does not need a Messages transport.\n *\n * Note what this list is NOT: it is not a plan gate. `claude-sonnet-5` is\n * Pro-tier and `claude-opus-4-8` Provider-tier, so the accounts entitled to\n * these models are exactly the non-Go ones, which `resolveProtocol()` sends to\n * the Provider API by default — picking any Claude model there failed every\n * request before this snapshot existed.\n *\n * Keep in sync when models ship (see the dsh-commandcode-upstream skill).\n * `requiresMessagesEndpoint()` additionally treats any `claude-*` id as\n * Messages-only, so a Claude model added upstream is routed correctly by an\n * un-updated plugin instead of hard-failing with the 400 above; the worst case\n * of that rule going stale the other way (upstream teaching\n * `/provider/v1/chat/completions` to serve Claude) is one model riding the CLI\n * transport it already works on.\n */\nexport const MESSAGES_ONLY_MODELS: ReadonlySet<string> = new Set([\n 'claude-sonnet-5',\n 'claude-sonnet-4-6',\n 'claude-fable-5-1',\n 'claude-fable-5',\n 'claude-opus-5',\n 'claude-opus-4-8',\n 'claude-opus-4-7',\n 'claude-haiku-4-5-20251001',\n])\n\n/** True when the Provider API will only serve `modelId` via `/provider/v1/messages`. */\nexport function requiresMessagesEndpoint(modelId: string): boolean {\n return MESSAGES_ONLY_MODELS.has(modelId) || modelId.startsWith('claude-')\n}\n\n/**\n * The minimum subscription plan a model is included in, per the official plan\n * pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`, `/docs/plans/max`\n * and `/docs/resources/pricing-limits`). Each plan's model list is a superset of\n * the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max. Models absent from every\n * plan list (Claude Opus/Fable, Fugu Ultra) are Provider-tier.\n * `claude-fable-5-1` (Claude Fable 5.1, added in command-code@1.40.0) is\n * Provider/Max-tier exactly like `claude-fable-5` — its availability matrix on\n * the official plan/pricing pages grants individual-provider/max/ultra and\n * teams-pro only, and the CLI's plan-access map blocks it on Go/GOAT/Pro.\n * command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` (Go) and 1.42.0 added\n * `meituan/LongCat-2.0:free` (Go, free promo); command-code@1.43.0 added\n * `google/gemini-3.8-flash` (GOAT) and 1.44.0 added `meta/muse-spark-1.3`\n * (GOAT) plus its Contributor sibling (Go); command-code@1.52.0 added the\n * free `inclusionai/ling-3.0-flash-sante:free` (Go); command-code@1.53.0\n * added `deepseek/deepseek-v4.1-flash` (Go).\n *\n * The Provider API exposes no plan metadata, so this snapshot is the source of\n * truth for the picker's plan annotation — it answers \"which plan do I need to\n * actually use this model?\" at a glance. Plan labels use the official tier\n * names (`Go`, `GOAT`, `Pro`, `Provider`), with `Max` implying Provider.\n *\n * Keep in sync with the official plan pages when they change (see the\n * dsh-commandcode-upstream skill).\n */\nexport const KNOWN_PLANS: Readonly<Record<string, string>> = {\n // --- Go (44) ---\n 'MiniMaxAI/MiniMax-M2.5': 'go',\n 'MiniMaxAI/MiniMax-M2.7': 'go',\n 'MiniMaxAI/MiniMax-M3': 'go',\n 'Qwen/Qwen3.6-Max-Preview': 'go',\n 'Qwen/Qwen3.6-Plus': 'go',\n 'Qwen/Qwen3.7-Flash': 'go',\n 'Qwen/Qwen3.7-Max': 'go',\n 'Qwen/Qwen3.7-Plus': 'go',\n 'Qwen/Qwen3.8-27B': 'go',\n 'Qwen/Qwen3.8-Flash': 'go',\n 'Qwen/Qwen3.8-Max': 'go',\n // command-code@1.41.0 added Qwen 3.8 Max 0902; it sits on the Go plan page.\n 'Qwen/Qwen3.8-Max-0902': 'go',\n // command-code@1.39.0 added DeepSeek V4 Flash Fast; it is a Go-tier model\n // alongside the rest of the DeepSeek V4 family.\n 'deepseek/deepseek-v4-flash-fast': 'go',\n // command-code@1.53.0 added DeepSeek V4.1 Flash (\"Add new\n // deepseek/deepseek-v4.1-flash model\"); the pricing page's embedded\n // availability grants it every plan including Go, and the Go/GOAT/Pro/Max\n // plan pages all list it.\n 'deepseek/deepseek-v4.1-flash': 'go',\n 'deepseek/deepseek-v4-flash': 'go',\n 'deepseek/deepseek-v4-flash-vision-exp': 'go',\n 'deepseek/deepseek-v4-pro': 'go',\n 'gpt-5.6-luna': 'go',\n // command-code@1.42.0 added Meituan's LongCat 2.0 as a free Go-tier model\n // (\"LongCat 2.0 free model\" — 100% off while it lasts, every plan).\n 'meituan/LongCat-2.0:free': 'go',\n // command-code@1.52.0 added Ling 3.0 Flash Sante as a free Go-tier model\n // (\"free, up to 100 requests a day\", every plan) — the successor to the\n // retired `inclusionai/ling-3.0-flash-free` promo.\n 'inclusionai/ling-3.0-flash-sante:free': 'go',\n // command-code@1.44.0 added Muse Spark 1.3 Contributor on every plan\n // including Go, like its 1.2 Contributor sibling.\n 'meta/muse-spark-1.2-contributor': 'go',\n 'meta/muse-spark-1.3-contributor': 'go',\n\n 'moonshotai/Kimi-K2.5': 'go',\n 'moonshotai/Kimi-K2.6': 'go',\n 'moonshotai/Kimi-K2.7-Code': 'go',\n 'moonshotai/Kimi-K2.7-Code-Highspeed': 'go',\n 'moonshotai/Kimi-K3': 'go',\n 'nvidia/nemotron-3-ultra-550b-a55b': 'go',\n 'poolside/laguna-s-2.1-free': 'go',\n 'stepfun/Step-3.5-Flash': 'go',\n 'stepfun/Step-3.7-Flash': 'go',\n 'tencent/hy3-paid': 'go',\n 'tencent/hy4-preview': 'go',\n 'thinkingmachines/inkling': 'go',\n 'thinkingmachines/inkling-small': 'go',\n 'xai/grok-4.5': 'go',\n 'xiaomi/mimo-v2.5': 'go',\n 'xiaomi/mimo-v2.5-pro': 'go',\n 'z-ai/glm-5.3-flash': 'go',\n 'zai-org/GLM-5': 'go',\n 'zai-org/GLM-5.1': 'go',\n 'zai-org/GLM-5.2': 'go',\n 'zai-org/GLM-5.2-Fast': 'go',\n 'zai-org/GLM-5.3': 'go',\n // --- GOAT (6 more) ---\n 'google/gemini-3.7-flash': 'goat',\n // command-code@1.43.0 added Gemini 3.8 Flash; the pricing page marks it\n // \"Available on GOAT and above\", like the rest of the Gemini Flash family.\n 'google/gemini-3.8-flash': 'goat',\n 'gpt-5.6-sol': 'goat',\n 'meta/muse-spark-1.2': 'goat',\n // command-code@1.44.0 added Muse Spark 1.3; the pricing page marks it\n // \"Available on GOAT and above\", like the 1.2/1.1 models.\n 'meta/muse-spark-1.3': 'goat',\n 'xai/grok-4.6': 'goat',\n // --- Pro (13 more) ---\n 'claude-haiku-4-5-20251001': 'pro',\n 'claude-sonnet-4-6': 'pro',\n 'claude-sonnet-5': 'pro',\n 'google/gemini-3.1-flash-lite': 'pro',\n 'google/gemini-3.5-flash': 'pro',\n 'google/gemini-3.5-flash-lite': 'pro',\n 'google/gemini-3.6-flash': 'pro',\n 'gpt-5.3-codex': 'pro',\n 'gpt-5.4': 'pro',\n 'gpt-5.4-mini': 'pro',\n 'gpt-5.5': 'pro',\n 'gpt-5.6-terra': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider / Max (7) ---\n 'claude-fable-5-1': 'provider',\n 'claude-fable-5': 'provider',\n 'claude-opus-4-7': 'provider',\n 'claude-opus-4-8': 'provider',\n 'claude-opus-5': 'provider',\n // command-code@1.49.0 added GPT-6 Astra; per the pricing page it sits on\n // Max (Provider/Max tier).\n 'gpt-6-astra': 'provider',\n 'sakana/fugu-ultra': 'provider',\n}\n\n/** Official display labels for each plan tier. */\nexport const PLAN_LABELS: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/**\n * Plan-tier sort weights, low to high. Models outside the snapshot (unknown\n * plans) sort after every known tier, keeping known models predictable.\n */\nexport const PLAN_ORDER: Readonly<Record<string, number>> = {\n go: 0,\n goat: 1,\n pro: 2,\n provider: 3,\n max: 4,\n}\n\n/**\n * Whether a model is free (requests cost no credits), per the pricing page's\n * deals (`KNOWN_DEALS` `free: true`). Free models lead the picker regardless\n * of tier — they are usable by every account, so they are the best default\n * candidates.\n */\nexport function isFreeModel(modelId: string): boolean {\n return KNOWN_DEALS[modelId]?.free === true\n}\n\n/**\n * Comparator for the model picker: free models first (zero credit cost, usable\n * by every account), then by plan tier (lowest first), then by model name,\n * then by id as a tiebreak. Models with no known plan sort last.\n */\nexport function compareByPlan(\n a: { id: string; name: string },\n b: { id: string; name: string },\n): number {\n const freeDelta = Number(isFreeModel(b.id)) - Number(isFreeModel(a.id))\n if (freeDelta !== 0) return freeDelta\n const pa = PLAN_ORDER[KNOWN_PLANS[a.id] ?? ''] ?? Number.MAX_SAFE_INTEGER\n const pb = PLAN_ORDER[KNOWN_PLANS[b.id] ?? ''] ?? Number.MAX_SAFE_INTEGER\n if (pa !== pb) return pa - pb\n const nameDiff = a.name.localeCompare(b.name)\n if (nameDiff !== 0) return nameDiff\n return a.id.localeCompare(b.id)\n}\n\n/**\n * Subscription plan table, synced from the official CLI bundle's plan maps\n * (located by the `\"individual-go\"` key in command-code@1.53.0 `dist/cli.mjs`,\n * re-verified unchanged through 1.53.0): subscription `planId`\n * prefix → display name and the plan's monthly credit total. This is the\n * account's own subscription (from `/alpha/billing/subscriptions`) — distinct\n * from {@link KNOWN_PLANS}, which maps catalog models to their minimum tier.\n *\n * `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on\n * the {@link PLAN_ORDER} scale, used by the picker's plan filter\n * ({@link modelVisibleInPlan}) to hide models above the account's tier.\n */\nexport const KNOWN_SUBSCRIPTION_PLANS: Readonly<Record<string, { name: string; monthlyCredits: number; tierWeight: number }>> = {\n 'individual-go': { name: 'Go', monthlyCredits: 10, tierWeight: 0 },\n 'individual-goat': { name: 'GOAT', monthlyCredits: 70, tierWeight: 1 },\n 'individual-pro': { name: 'Pro', monthlyCredits: 30, tierWeight: 2 },\n 'individual-pro-v1': { name: 'Pro', monthlyCredits: 80, tierWeight: 2 },\n 'individual-provider': { name: 'Provider', monthlyCredits: 15, tierWeight: 3 },\n 'individual-max': { name: 'Max', monthlyCredits: 150, tierWeight: 4 },\n 'individual-ultra': { name: 'Ultra', monthlyCredits: 300, tierWeight: 4 },\n 'teams-pro': { name: 'Teams Pro', monthlyCredits: 40, tierWeight: 2 },\n}\n\n/** Plan-id prefixes, longest first — the CLI's prefix-match order. */\nconst SUBSCRIPTION_PLAN_PREFIXES = Object.keys(KNOWN_SUBSCRIPTION_PLANS).sort((a, b) => b.length - a.length)\n\n/**\n * Resolve a subscription `planId` (e.g. `individual-pro-v1`) to its display\n * name and monthly credit total, mirroring the CLI's `getPlanInfo`:\n * normalize (lowercase, `_` → `-`), then longest-prefix match so\n * `individual-pro-v1` wins over `individual-pro`. Unknown ids return\n * `undefined`.\n */\nexport function subscriptionPlanInfo(planId: string): { name: string; monthlyCredits: number; tierWeight: number } | undefined {\n const normalized = planId.toLowerCase().replace(/_/g, '-')\n const prefix = SUBSCRIPTION_PLAN_PREFIXES.find((candidate) => normalized.startsWith(candidate))\n return prefix === undefined ? undefined : KNOWN_SUBSCRIPTION_PLANS[prefix]\n}\n\n/**\n * The billing facts the picker's plan filter needs, fetched by mirroring the\n * CLI's `createBilling` flow (whoami → orgId, then `/alpha/billing/subscriptions`\n * for the plan id and `/alpha/billing/credits` for the on-demand balances).\n */\nexport interface CommandCodeBillingAccess {\n /** Account plan tier weight on the {@link PLAN_ORDER} scale; undefined when the plan is unknown. */\n tierWeight: number | undefined\n /**\n * Purchased + free on-demand credit balance. The official access model\n * (`evaluateModelAccess` in the CLI) allows every model when the account\n * holds any on-demand credits — the plan gate only applies at zero balance.\n */\n onDemandCredits: number\n}\n\n/**\n * Whether the picker lists `modelId` for an account with the given billing\n * access. Fails open at every uncertainty: no billing data, an unknown plan,\n * a non-finite weight (corrupt billing fact), or a model outside\n * {@link KNOWN_PLANS} all keep the model visible — the server remains the\n * final gate (`403 MODEL_NOT_IN_PLAN`).\n */\nexport function modelVisibleInPlan(modelId: string, access: CommandCodeBillingAccess | undefined): boolean {\n if (access === undefined) return true\n if (access.onDemandCredits > 0) return true\n if (access.tierWeight === undefined || !Number.isFinite(access.tierWeight)) return true\n const tier = KNOWN_PLANS[modelId]\n if (tier === undefined) return true\n const weight = PLAN_ORDER[tier]\n if (weight === undefined) return true\n return weight <= access.tierWeight\n}\n\n/**\n * Active pricing deals per the official pricing page\n * (`/docs/resources/pricing-limits#deals`). Each entry records the model's\n * promotional label and — critically — when it expires, so the picker never\n * shows a stale discount after the plugin's snapshot has gone out of date.\n *\n * - `expiresAt` is an ISO timestamp. When it is in the past (checked at\n * render time against `Date.now()`), the deal label is hidden until the\n * snapshot is refreshed from the official page. `undefined` means\n * \"no expiry\" (permanent).\n * - `free` marks models whose requests cost no credits (Laguna S 2.1), shown\n * as a `FREE` badge; it degrades to a plain discount once the deal lapses.\n *\n * Keep in sync with the official pricing page when deals change (see the\n * dsh-commandcode-upstream skill).\n */\nexport interface KnownDeal {\n /** Promotional label, e.g. \"50% off\" or \"2× usage\". */\n label: string\n /** Deal end date (ISO). `undefined` = permanent / no expiry. */\n expiresAt?: string\n /** Model is free (requests cost no credits). */\n free?: boolean\n}\n\nexport const KNOWN_DEALS: Readonly<Record<string, KnownDeal>> = {\n // Gemini 3.7 Flash's 50% off deal was retired from the official pricing\n // page's #deals section (command-code@1.38.2 sync); the model now shows at\n // full price.\n 'MiniMaxAI/MiniMax-M3': { label: '50% off' },\n 'xiaomi/mimo-v2.5-pro': { label: '99% off' },\n 'xiaomi/mimo-v2.5': { label: '98% off' },\n // The MiniMax M3 / M2.7 FREE promo variants were retired in\n // command-code@1.39.2 (\"Retire MiniMax free models\"): the official CLI hides\n // them and the pricing page no longer lists them as free, so the free\n // entries that shipped through 1.38.2 (with a 2026-09-05 expiry) are removed\n // here rather than left to lapse on schedule. The paid MiniMax M3 / M2.7\n // rows keep their own rates.\n 'poolside/laguna-s-2.1-free': { label: 'FREE', free: true },\n // Meituan's LongCat 2.0 (command-code@1.42.0, \"LongCat 2.0 free model\") is\n // 100% off while it lasts — a permanent-style deal (no fixed end date; the\n // pricing page's DEAL block says \"Term: while it lasts\"). Free requests cost\n // no credits on every plan, like Laguna S 2.1.\n 'meituan/LongCat-2.0:free': { label: 'FREE', free: true },\n // Ling 3.0 Flash Sante (command-code@1.52.0) is free \"up to 100 requests a\n // day\" while the promo lasts — a permanent-style deal (no fixed end date,\n // like LongCat 2.0). Free requests cost no credits on every plan.\n 'inclusionai/ling-3.0-flash-sante:free': { label: 'FREE', free: true },\n}\n\n/**\n * Models with time-of-day (peak/off-peak) pricing, per the official pricing\n * page (`/docs/resources/pricing-limits`). Since 2026-08-16 16:00 UTC, DeepSeek\n * charges by the hour: peak hours are 01:00–04:00 and 06:00–10:00 UTC (7h per\n * weekday, full price) **Monday to Friday only**; the other 17 hours of a\n * weekday and every hour of Saturday/Sunday (UTC) are off-peak at half price.\n * The V4 Flash Vision (exp) variant (command-code@1.32.0) shares the V4 Flash\n * rates exactly — $0.15/$0.60 off-peak and $0.30/$1.20 peak, per the page's own\n * `timeOfDay` block, not merely 2× its own off-peak figures: a rate that is\n * internally consistent can still be the wrong row, which is why the vendored\n * price table (`./model-prices.ts`) is synced from the page and not hand-kept.\n * The picker shows the\n * *current* state as a compact\n * label (`Peak`/`Half`) matching the English noun style of the other markers\n * (`Image`, `FREE`), so a developer can tell at a glance whether calling the\n * model right now is cheap or expensive.\n *\n * Authoritative extraction: the pricing page embeds a model JSON array whose\n * hourly-priced entries carry a `timeOfDay` block\n * (`{ windows: \"01–04 & 06–10 UTC, Mon–Fri\", peakHoursPerDay: 7,\n * offPeakHoursPerDay: 17, peak: {...}, offPeak: {...} }`). Exactly four models\n * carry it: V4 Pro, V4 Flash, V4 Flash Vision (exp), and V4.1 Flash (added in\n * command-code@1.53.0 at $0.15/$0.60 off-peak, $0.30/$1.20 peak — the same\n * schedule as the other three).\n *\n * Extraction caution: the rendered HTML rows are a trap. Each annotation div\n * sits inside its OWN row's container, immediately before the NEXT row starts,\n * so flattening the page to text makes every annotation look like it belongs\n * to the model printed after it — that is how `deepseek/deepseek-v4-flash-fast`\n * was wrongly added here (its row is flat-priced at $0.28/$0.56/$0.07 and has\n * no `timeOfDay` block). Trust the embedded JSON's `timeOfDay` membership and\n * the 2× price relation, never the flat-text neighbor.\n *\n * Keep in sync with the official pricing page when the model set, the peak\n * windows, or the weekday rule change (see the dsh-commandcode-upstream skill).\n */\nexport const KNOWN_PEAK_PRICING: ReadonlySet<string> = new Set([\n 'deepseek/deepseek-v4-pro',\n 'deepseek/deepseek-v4-flash',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0 added DeepSeek V4.1 Flash with the same `timeOfDay`\n // block as the other DeepSeek models (off-peak $0.15/$0.60, peak\n // $0.30/$1.20, 01–04 & 06–10 UTC Mon–Fri).\n 'deepseek/deepseek-v4.1-flash',\n])\n\n/**\n * Peak hours (UTC, hour-of-day range end-exclusive): 01–03 and 06–09.\n * Weekday-only — see `peakPricingState()`; weekends are fully off-peak.\n *\n * Exported because the vendored price table (`./model-prices.ts`) ships these\n * windows to the browser with the table itself: the composer prices a session\n * against the very schedule this snapshot knows rather than restating it, so\n * there is one place to update when the windows move.\n */\nexport const PEAK_HOUR_RANGES: ReadonlyArray<readonly [number, number]> = [\n [1, 4],\n [6, 10],\n]\n\n/**\n * Whether `now` (defaults to `Date.now()`) falls inside a peak-pricing window,\n * ignoring which model is asking. Peak rates apply Monday–Friday (UTC) only,\n * so a weekend timestamp is off-peak even inside {@link PEAK_HOUR_RANGES}.\n *\n * Model-independent on purpose: `peakPricingState()` adds the membership test\n * on top for the picker's label, while the price table selects peak rates from\n * a row's own `peak` block — so a model whose catalog id spelling differs from\n * the one in {@link KNOWN_PEAK_PRICING} still gets the right half of the day.\n */\nexport function isPeakPricingHour(now: number = Date.now()): boolean {\n const at = new Date(now)\n const day = at.getUTCDay()\n if (day === 0 || day === 6) return false\n const hour = at.getUTCHours()\n return PEAK_HOUR_RANGES.some(([start, end]) => hour >= start && hour < end)\n}\n\n/**\n * Whether `now` (defaults to `Date.now()`) falls in a peak-pricing window for\n * time-of-day-priced models. Peak rates apply Monday–Friday (UTC) only: the\n * official rule charges Saturday and Sunday completely off-peak for all 24\n * hours, so a weekend timestamp is off-peak even inside `PEAK_HOUR_RANGES`.\n * `undefined` for models outside the snapshot.\n */\nexport function peakPricingState(\n modelId: string,\n now: number = Date.now(),\n): 'peak' | 'off-peak' | undefined {\n if (!KNOWN_PEAK_PRICING.has(modelId)) return undefined\n return isPeakPricingHour(now) ? 'peak' : 'off-peak'\n}\n\n/**\n * Compact label for the current peak/off-peak state: `Peak` (full price) or\n * `Half` (off-peak, half price). These English nouns match the picker's other\n * markers (`Go`, `Image`, `FREE`), and since they appear only on time-of-day\n * priced models they double as a \"priced by the hour\" signal. Returns undefined\n * for models without time-of-day pricing.\n */\nexport function peakPricingLabel(\n modelId: string,\n now: number = Date.now(),\n): string | undefined {\n const state = peakPricingState(modelId, now)\n if (state === undefined) return undefined\n return state === 'peak' ? 'Peak' : 'Half'\n}\n\n// ---------------------------------------------------------------------------\n// Snapshot read helpers (kept with the tables: a model/plan/deal sync must\n// never touch src/adapter.ts)\n// ---------------------------------------------------------------------------\n/**\n * Official display label for a model's minimum plan, or undefined for models\n * outside the snapshot (e.g. future catalog additions).\n */\nexport function planLabel(modelId: string): string | undefined {\n const plan = KNOWN_PLANS[modelId]\n return plan === undefined ? undefined : PLAN_LABELS[plan]\n}\n\n/**\n * The active deal label for a model, or undefined when the model has no deal\n * or the deal has expired. Expiry is judged against `now` (defaults to\n * `Date.now()`), so a snapshot that has gone stale stops showing its discount\n * the moment the official end date passes — the user never believes a lapsed\n * deal is still live. Permanent deals (no `expiresAt`) never lapse.\n */\nexport function dealLabel(modelId: string, now: number = Date.now()): string | undefined {\n const deal = KNOWN_DEALS[modelId]\n if (deal === undefined) return undefined\n if (deal.expiresAt !== undefined && now >= Date.parse(deal.expiresAt)) return undefined\n return deal.label\n}\n\n/**\n * Compact human-readable context window, e.g. `1_000_000 -> \"1M\"`,\n * `256_000 -> \"256K\"`, `262_144 -> \"262K\"` (floor to the nearest K).\n * Returns undefined for unknown/absent sizes; values under 1K render raw.\n */\nexport function formatContext(contextWindow: number | undefined): string | undefined {\n if (contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) {\n return undefined\n }\n if (contextWindow >= 1_000_000) {\n const m = contextWindow / 1_000_000\n // Round to one decimal only when it adds information: 1_048_576 -> \"1M\",\n // 1_050_000 -> \"1.1M\".\n const rounded = Math.round(m * 10) / 10\n return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}M`\n }\n if (contextWindow < 1_000) return String(Math.floor(contextWindow))\n return `${Math.floor(contextWindow / 1_000)}K`\n}\n\n/**\n * Compact one-line summary for the model picker: plan tier, then any active\n * deal (discount or FREE), then the current peak/off-peak state (`Peak`/`Half`)\n * for time-of-day-priced models, then `Image` for Vision-capable models, then\n * the context window. Text-only models simply omit the Image marker — \"Text\n * only\" adds nothing the picker needs to show.\n */\nexport function capabilityDescription(\n modelId: string,\n contextWindow?: number,\n now: number = Date.now(),\n): string {\n const parts: string[] = []\n const plan = planLabel(modelId)\n if (plan !== undefined) parts.push(plan)\n const deal = dealLabel(modelId, now)\n if (deal !== undefined) parts.push(deal)\n const peak = peakPricingLabel(modelId, now)\n if (peak !== undefined) parts.push(peak)\n if (KNOWN_IMAGE_MODELS.has(modelId)) parts.push('Image')\n const ctx = formatContext(contextWindow)\n if (ctx !== undefined) parts.push(ctx)\n return parts.join(' · ')\n}\n","/**\n * Vendored Command Code model prices: the per-token rates the official\n * pricing page publishes, which is what lets the composer price a session in\n * dollars.\n *\n * Source: the model array embedded in\n * https://commandcode.ai/docs/resources/pricing-limits, read out of its\n * Next.js flight payload. That payload is the only place the `timeOfDay` and\n * `contextTiers` blocks exist, so it is what the generator parses — but it is\n * NOT trusted on its own: the generator also reads the page's rendered table\n * and reports any rate where the two disagree. A figure can be internally\n * consistent and still be the wrong row (this table once carried\n * `0.22 → 0.44` for a model the page prices `0.15 → 0.30` — exactly the 2× the\n * peak/off-peak rule promises), so the cross-check exists to catch that class\n * of error rather than to restate the invariant. Every figure is USD per\n * 1,000,000 tokens, which the page confirms itself: its Go-plan estimate for\n * DeepSeek V4 Flash (800 in / 200 out on a $10 budget) resolves to the ~42K\n * requests the page states, and ~26K once its typical 50K cache reads are\n * priced at the cacheRead rate.\n *\n * Three buckets are always published (inputCost, outputCost, cacheReadCost);\n * cacheWriteCost is published for a minority of models. A model without the\n * key has UNPRICED cache-write tokens: never invent a multiplier for them, and\n * never fold them into the input rate. A published `0` is a different fact and\n * is kept as a real zero — see the note on the GPT rows below.\n *\n * Time-of-day models store a `peak` triplet only. The page repeats the flat\n * rates inside its own offPeak block, so the top-level rates ARE the off-peak\n * rates and only the peak override is worth keeping — the generator asserts\n * that equality and refuses to emit otherwise. Whether \"now\" counts as peak is\n * decided by `isPeakPricingHour()` in ./capabilities.ts, on the same\n * Monday-Friday UTC schedule the model picker labels.\n *\n * Context-tiered models carry every band, with inclusive prompt-token bounds\n * and an unbounded final band. The durable cost projection selects each\n * request's band from its input/cache buckets, never from session totals.\n *\n * Do not hand-edit the table below: run `node scripts/sync-model-prices.mjs`,\n * which re-reads the page, asserts the structure and the off-peak equality,\n * prints cross-check warnings for a human, and rewrites\n * only the rows. `--check` reports drift without writing (exit 1 on drift,\n * exit 2 when the page could not be read, so a network failure never reads as\n * \"up to date\"). Everything else in this file — this doc, the types, the slug\n * rules, the table builder — is written by hand and survives that rewrite.\n *\n * @module dsh-commandcode-provider/model-prices\n */\n\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\nimport { KNOWN_PLANS, PEAK_HOUR_RANGES, isFreeModel } from './capabilities.ts'\n\n/**\n * One pricing-page row. `rates` is `[input, output, cacheRead, cacheWrite?]`\n * and `peak` is the `[input, output, cacheRead]` triplet charged inside the\n * peak windows. All figures are USD per 1,000,000 tokens.\n */\ninterface ModelPriceRow {\n readonly id: string\n readonly rates: readonly number[]\n readonly peak?: readonly number[]\n readonly contextTiers?: readonly { maxContext?: number; rates: readonly number[] }[]\n}\n\n/**\n * Every price row the page publishes, ordered by its own slug.\n *\n * Note on the GPT rows: `gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini` and\n * `gpt-5.5` carry a LITERAL `cacheWriteCost: 0` — a different fact from a\n * missing key, because `ratesOf()` keeps it and the readout then charges\n * cache writes at zero instead of reporting them unpriced. That is what the\n * page's JSON says; its rendered column shows `—` for exactly these four while\n * rendering a genuine zero as `$0.00` elsewhere, so the page contradicts\n * itself. The table stays faithful to the machine-readable source and the\n * discrepancy is recorded in AGENTS.md rather than papered over here.\n */\nconst MODEL_PRICE_ROWS: readonly ModelPriceRow[] = [\n { id: 'claude-fable-5', rates: [10, 50, 1, 12.5] },\n { id: 'claude-fable-5-1', rates: [10, 50, 0.25, 12.5] },\n { id: 'claude-haiku-4-5', rates: [1, 5, 0.1, 1.25] },\n { id: 'claude-opus-4-6', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-4-7', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-4-8', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-opus-5', rates: [5, 25, 0.5, 6.25] },\n { id: 'claude-sonnet-4-6', rates: [3, 15, 0.3, 3.75] },\n { id: 'claude-sonnet-5', rates: [2, 10, 0.2, 2.5] },\n { id: 'deepseek-v4-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'deepseek-v4-flash-fast', rates: [0.28, 0.56, 0.07] },\n { id: 'deepseek-v4-flash-vision-exp', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'deepseek-v4-pro', rates: [0.66, 1.98, 0.022], peak: [1.32, 3.96, 0.044] },\n { id: 'deepseek-v4.1-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006] },\n { id: 'fugu-ultra', rates: [5, 30, 0.5] },\n { id: 'gemini-3.1-flash-lite', rates: [0.25, 1.5, 0.03] },\n { id: 'gemini-3.5-flash', rates: [1.5, 9, 0.15] },\n { id: 'gemini-3.5-flash-lite', rates: [0.3, 2.5, 0.03] },\n { id: 'gemini-3.6-flash', rates: [1.5, 7.5, 0.15] },\n { id: 'gemini-3.7-flash', rates: [1.5, 7.5, 0.15, 0.08334] },\n { id: 'gemini-3.8-flash', rates: [1.5, 7.5, 0.15] },\n { id: 'glm-5', rates: [1, 3.2, 0.2] },\n { id: 'glm-5.1', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.2', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.2-fast', rates: [3, 10.25, 0.5] },\n { id: 'glm-5.3', rates: [1.4, 4.4, 0.26] },\n { id: 'glm-5.3-flash', rates: [0.15, 0.5, 0.03] },\n { id: 'gpt-5.3-codex', rates: [2, 8, 0.5, 0] },\n { id: 'gpt-5.4', rates: [2.5, 15, 0.25, 0] },\n { id: 'gpt-5.4-mini', rates: [0.75, 4.5, 0.075, 0] },\n { id: 'gpt-5.5', rates: [5, 30, 0.5, 0] },\n { id: 'gpt-5.6-luna', rates: [0.2, 1.2, 0.02, 0.25], contextTiers: [{\"maxContext\":272000,\"rates\":[0.2,1.2,0.02,0.25]},{\"rates\":[0.4,1.8,0.04,0.5]}] },\n { id: 'gpt-5.6-sol', rates: [5, 30, 0.5, 6.25], contextTiers: [{\"maxContext\":272000,\"rates\":[5,30,0.5,6.25]},{\"rates\":[10,45,1,12.5]}] },\n { id: 'gpt-5.6-terra', rates: [2, 12, 0.2, 2.5], contextTiers: [{\"maxContext\":272000,\"rates\":[2,12,0.2,2.5]},{\"rates\":[4,18,0.4,5]}] },\n { id: 'gpt-6-astra', rates: [10, 50, 1, 12.5], contextTiers: [{\"maxContext\":272000,\"rates\":[10,50,1,12.5]},{\"rates\":[20,75,2,25]}] },\n { id: 'grok-4.5', rates: [2, 6, 0.5] },\n { id: 'grok-4.6', rates: [2, 6, 0.5], contextTiers: [{\"maxContext\":200000,\"rates\":[2,6,0.5]},{\"rates\":[4,12,1]}] },\n { id: 'inkling', rates: [1, 4.05, 0.17] },\n { id: 'inkling-small', rates: [0.5, 1.2, 0.1] },\n { id: 'kimi-k2.5', rates: [0.6, 3, 0.1] },\n { id: 'kimi-k2.6', rates: [0.95, 4, 0.16] },\n { id: 'kimi-k2.7-code', rates: [0.95, 4, 0.19] },\n { id: 'kimi-k2.7-code-highspeed', rates: [1.9, 8, 0.38] },\n { id: 'kimi-k3', rates: [3, 15, 0.3] },\n { id: 'mimo-v2.5', rates: [0.14, 0.28, 0.0028] },\n { id: 'mimo-v2.5-pro', rates: [0.435, 0.87, 0.0036] },\n { id: 'minimax-m2.5', rates: [0.3, 1.2, 0.03] },\n { id: 'minimax-m2.7', rates: [0.3, 1.2, 0.06] },\n { id: 'minimax-m3', rates: [0.3, 1.2, 0.06] },\n { id: 'muse-spark-1.1', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.2', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.2-contributor', rates: [0.1, 0.2, 0.002] },\n { id: 'muse-spark-1.3', rates: [1.25, 4.25, 0.15] },\n { id: 'muse-spark-1.3-contributor', rates: [0.1, 0.2, 0.002] },\n { id: 'nemotron-3-ultra', rates: [0.6, 2.4, 0.12] },\n { id: 'qwen-3.6-max', rates: [1.3, 7.8, 0.26, 1.63] },\n { id: 'qwen-3.6-plus', rates: [0.5, 3, 0.1], contextTiers: [{\"maxContext\":256000,\"rates\":[0.5,3,0.1]},{\"rates\":[2,6,0.2]}] },\n { id: 'qwen-3.7-flash', rates: [0.03, 0.13, 0.006, 0.038], contextTiers: [{\"maxContext\":32000,\"rates\":[0.03,0.13,0.006,0.038]},{\"maxContext\":256000,\"rates\":[0.1,0.4,0.02,0.125]},{\"rates\":[0.2,0.8,0.04,0.25]}] },\n { id: 'qwen-3.7-max', rates: [2.5, 7.5, 0.5, 3.13] },\n { id: 'qwen-3.7-plus', rates: [0.4, 1.6, 0.08, 0.5], contextTiers: [{\"maxContext\":256000,\"rates\":[0.4,1.6,0.08,0.5]},{\"rates\":[1.2,4.8,0.24,1.5]}] },\n { id: 'qwen-3.8-27b', rates: [0.4, 3, 0.04] },\n { id: 'qwen-3.8-flash', rates: [0.16, 0.47, 0.016] },\n { id: 'qwen-3.8-max', rates: [2, 6, 0.25, 2.5] },\n { id: 'qwen-3.8-max-0902', rates: [2, 6, 0.25] },\n { id: 'step-3.5-flash', rates: [0.1, 0.3, 0.02] },\n { id: 'step-3.7-flash', rates: [0.2, 1.15, 0.04] },\n { id: 'tencent/hy3-paid', rates: [0.14, 0.58, 0.035] },\n { id: 'tencent/hy4-preview', rates: [0.834, 2.501, 0.042] },\n]\n\n/**\n * Catalog ids no candidate rule can reach, because the page names the model\n * differently from the catalog. `tests/model-prices.test.ts` fails whenever a\n * catalog model has no price, so a new miss lands here as a visible decision\n * rather than a silently unpriced model.\n */\nconst PRICE_SLUG_OVERRIDES: Readonly<Record<string, string>> = {\n // The page lists it by its short name; the catalog carries the full one.\n 'nvidia/nemotron-3-ultra-550b-a55b': 'nemotron-3-ultra',\n}\n\n/**\n * Plausible price slugs for one catalog model id, most specific first.\n *\n * The page normalizes to lowercase and usually drops the vendor segment, but\n * not consistently: `tencent/hy4-preview` keeps its prefix while\n * `Qwen/Qwen3.8-Max-0902` becomes `qwen-3.8-max-0902`, with a hyphen the\n * catalog id does not have. Generating candidates and taking the first that\n * exists in the vendored table absorbs that drift without a hand-maintained\n * map of seventy ids.\n */\nfunction priceSlugCandidates(modelId: string): string[] {\n const lower = modelId.toLowerCase()\n const bare = lower.includes('/') ? lower.slice(lower.indexOf('/') + 1) : lower\n const out = new Set<string>()\n const add = (slug: string): void => {\n const hyphenated = slug.replace(/^([a-z]+)(\\d)/, '$1-$2')\n out.add(slug)\n out.add(hyphenated)\n out.add(slug.replace(/-\\d{8}$/, ''))\n out.add(slug.replace(/-(preview|latest)$/, ''))\n out.add(hyphenated.replace(/-\\d{8}$/, ''))\n out.add(hyphenated.replace(/-(preview|latest)$/, ''))\n }\n add(lower)\n add(bare)\n return [...out]\n}\n\n/** The pricing-page slug for one catalog model id, or undefined when unpriced. */\nfunction priceSlugFor(modelId: string, known: ReadonlySet<string>): string | undefined {\n const override = PRICE_SLUG_OVERRIDES[modelId]\n if (override !== undefined) return known.has(override) ? override : undefined\n return priceSlugCandidates(modelId).find((slug) => known.has(slug))\n}\n\n/** Split a stored triplet/quadruplet into the wire rate shape. */\nfunction ratesOf(values: readonly number[]): CommandCodeModelRates {\n // Indexed access is asserted rather than defaulted: the generator above only\n // ever emits rows with the three published rates, so a short row is a broken\n // table and must not silently become a free model.\n const rates: CommandCodeModelRates = {\n inputCost: values[0]!,\n outputCost: values[1]!,\n cacheReadCost: values[2]!,\n }\n if (values[3] !== undefined) rates.cacheWriteCost = values[3]\n return rates\n}\n\n/** Build the full price row the browser prices a session with. */\nfunction wireRow(id: string, slug: string, row: ModelPriceRow): CommandCodeModelPrice {\n const price: CommandCodeModelPrice = { id, slug, ...ratesOf(row.rates) }\n if (row.peak !== undefined) price.peak = ratesOf(row.peak)\n if (row.contextTiers !== undefined) price.contextTiers = row.contextTiers.map(tier => ({\n ...ratesOf(tier.rates), ...(tier.maxContext === undefined ? {} : { maxContext: tier.maxContext }),\n }))\n return price\n}\n\n/**\n * Build the table the composer prices a session with.\n *\n * Rows are keyed by CATALOG id wherever the two namespaces reconcile, because\n * that is what a session reports, and every row also carries its page slug as a\n * second lookup key. Price rows no catalog model claims are served under the\n * slug alone, so drift in either direction still prices: a page rename the\n * catalog has not followed, or a model the catalog snapshot has not learned\n * yet. Free models are served explicitly at zero so the composer can say so\n * instead of showing nothing.\n *\n * The peak windows travel with the table, so the browser applies the very\n * schedule this snapshot knows instead of restating it.\n */\nexport function modelPriceTable(): CommandCodePriceTable {\n const bySlug = new Map(MODEL_PRICE_ROWS.map((row) => [row.id, row]))\n const known = new Set(bySlug.keys())\n const models: CommandCodeModelPrice[] = []\n const claimed = new Set<string>()\n\n for (const catalogId of Object.keys(KNOWN_PLANS)) {\n if (isFreeModel(catalogId) || catalogId.endsWith(':free')) {\n models.push({ id: catalogId, slug: catalogId, inputCost: 0, outputCost: 0, cacheReadCost: 0, free: true })\n continue\n }\n const slug = priceSlugFor(catalogId, known)\n if (slug === undefined) continue\n const row = bySlug.get(slug)\n if (row === undefined) continue\n claimed.add(slug)\n models.push(wireRow(catalogId, slug, row))\n }\n\n for (const row of MODEL_PRICE_ROWS) {\n if (claimed.has(row.id)) continue\n models.push(wireRow(row.id, row.id, row))\n }\n\n return {\n models,\n peakHours: PEAK_HOUR_RANGES.map(([start, end]) => [start, end] as [number, number]),\n }\n}\n\n","/** Shared, JSON-only billing facts. No Host or browser runtime imports. */\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\n\nexport interface CostTokens {\n uncachedInputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n}\n\n/** Requests with identical model/rates are folded into one group. */\nexport interface CostUsageGroup {\n provider: string\n model: string\n at: number | null\n contextTokens: number\n tokens: CostTokens\n}\n\nexport interface SessionCostFacts {\n pricingKey: number\n groups: CostUsageGroup[]\n}\n\nexport const zeroCostTokens = (): CostTokens => ({ uncachedInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })\nexport const COST_TOKEN_KEYS = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\n\nexport function peakHour(at: number, windows: ReadonlyArray<readonly [number, number]>): boolean {\n const time = new Date(at)\n return time.getUTCDay() !== 0 && time.getUTCDay() !== 6\n && windows.some(([start, end]) => time.getUTCHours() >= start && time.getUTCHours() < end)\n}\n\n/**\n * All prompt billing buckets determine a request's band, never cumulative session input.\n *\n * A tiered model returns the matching band and does NOT then apply `peak`: the\n * page publishes those two dimensions independently, no row carries both today,\n * and the generator would report a tiered row on every sync — so the combination\n * becoming real is visible before it reaches a user. This ordering is a latent\n * choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // The first band whose bound accepts the prompt. ORDER IS LOAD-BEARING, and\n // both producers enforce it: the generator refuses non-ascending bounds or a\n // bounded last band, and the wire parser rejects the same shapes — so a\n // conforming table cannot present bands out of order, and this `find` cannot\n // select a band a later one should have won.\n const tier = price.contextTiers?.find(tier => tier.maxContext === undefined || contextTokens <= tier.maxContext)\n if (tier !== undefined) return tier\n return price.peak !== undefined && at !== null && peakHour(at, table.peakHours) ? price.peak : price\n}\n\n/** Cache version and wire guard: changing bands/rates must refold historical groups. */\nexport function pricingKey(table: CommandCodePriceTable): number {\n const rates = (r: CommandCodeModelRates) => [r.inputCost, r.outputCost, r.cacheReadCost, r.cacheWriteCost ?? null]\n const canonical = JSON.stringify(['commandCodeCost-v1', table.peakHours, table.models.map(p => [p.id, p.slug, p.free === true, rates(p), p.peak ? rates(p.peak) : null, p.contextTiers?.map(t => [t.maxContext ?? null, rates(t)]) ?? null])])\n let hash = 2166136261\n for (const c of canonical) hash = Math.imul(hash ^ c.charCodeAt(0), 16777619) >>> 0\n return hash\n}\n\n/** Only safe to merge requests whose billing classification is identical. */\nexport function costGroupKey(group: CostUsageGroup, table: CommandCodePriceTable): string {\n const price = table.models.find(p => p.id === group.model || p.slug === group.model)\n return JSON.stringify([group.provider, group.model, price === undefined ? null : requestRates(price, group.at, group.contextTokens, table), group.at === null])\n}\n","/** Durable cost facts: mirrors token-meter's replacement/retry rules across v1/v2 logs. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { modelPriceTable } from './model-prices.ts'\nimport { COST_TOKEN_KEYS, costGroupKey, pricingKey, zeroCostTokens, type CostTokens, type CostUsageGroup, type SessionCostFacts } from './cost-facts.ts'\n\ninterface CostState {\n selection: { provider: string; model: string } | null\n at: number | null\n last: { turn: number; step: number; group: CostUsageGroup } | null\n facts: SessionCostFacts\n}\ninterface LogEvent { type: string; time: number; data: unknown }\nconst record = (v: unknown): Record<string, unknown> | undefined => typeof v === 'object' && v !== null && !Array.isArray(v) ? v as Record<string, unknown> : undefined\nconst finite = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v >= 0\n\nfunction tokensOf(value: unknown): CostTokens | undefined {\n const u = record(value)\n if (!u || !finite(u.inputTokens) || !finite(u.outputTokens)) return undefined\n if (u.cacheReadTokens !== undefined && !finite(u.cacheReadTokens) || u.cacheWriteTokens !== undefined && !finite(u.cacheWriteTokens)) return undefined\n return { uncachedInputTokens: u.inputTokens, outputTokens: u.outputTokens, cacheReadTokens: u.cacheReadTokens as number ?? 0, cacheWriteTokens: u.cacheWriteTokens as number ?? 0 }\n}\n\n/** Current v2 settlements store the last usage in their stream; v1 stores chunk events. */\nfunction usageOf(type: string, data: Record<string, unknown>): CostTokens | undefined {\n if (type === 'assistant/chunk') {\n const chunk = record(data.chunk)\n return chunk?.type === 'usage' ? tokensOf(chunk.usage) : undefined\n }\n if (type !== 'assistant/message' && type !== 'assistant/attempt') return undefined\n const direct = tokensOf(data.usage)\n if (direct !== undefined) return direct\n if (!Array.isArray(data.stream)) return undefined\n for (let i = data.stream.length - 1; i >= 0; i--) {\n const item = record(data.stream[i])\n const chunk = item?.type === 'chunk' ? record(item.chunk) : undefined\n if (chunk?.type === 'usage') return tokensOf(chunk.usage)\n }\n return undefined\n}\n\nfunction parseState(value: unknown): CostState {\n const s = record(value), facts = record(s?.facts)\n if (!s || !facts || !finite(facts.pricingKey) || !Array.isArray(facts.groups)) throw new TypeError('invalid commandCodeCost state')\n const group = (v: unknown): boolean => {\n const g = record(v), t = record(g?.tokens)\n return !!g && typeof g.provider === 'string' && typeof g.model === 'string' && (g.at === null || finite(g.at)) && finite(g.contextTokens) && !!t && COST_TOKEN_KEYS.every(k => finite(t[k]))\n }\n const sel = record(s.selection), last = record(s.last)\n if (!(s.selection === null || sel && typeof sel.provider === 'string' && typeof sel.model === 'string')\n || !(s.at === null || finite(s.at)) || !facts.groups.every(group)\n || !(s.last === null || last && finite(last.turn) && finite(last.step) && group(last.group))) throw new TypeError('invalid commandCodeCost state')\n return value as CostState\n}\n\n/** Optional registry uses only synchronous parse/view; no new runtime module is required. */\nexport function createCostProjection(table = modelPriceTable()) {\n const version = pricingKey(table)\n return {\n key: 'commandCodeCost', stateVersion: version,\n stateSchema: { parse: parseState },\n init: (): CostState => ({ selection: null, at: null, last: null, facts: { pricingKey: version, groups: [] } }),\n apply(state: CostState, event: LogEvent): CostState {\n const data = record(event.data)\n if (!data) return state\n if (event.type === 'request/header') {\n const config = record(record(data.header)?.config)\n return { ...state, selection: config && typeof config.provider === 'string' && typeof config.model === 'string' ? { provider: config.provider, model: config.model } : null }\n }\n if (event.type === 'step/start' || event.type === 'llm/retry-started') return { ...state, at: finite(event.time) ? event.time : null, last: null }\n const tokens = usageOf(event.type, data)\n if (tokens === undefined || !finite(data.turn) || !finite(data.step)) return state\n const previous = state.last?.turn === data.turn && state.last.step === data.step ? state.last.group : undefined\n const group: CostUsageGroup = { provider: state.selection?.provider ?? '', model: state.selection?.model ?? '', at: state.at, contextTokens: tokens.uncachedInputTokens + tokens.cacheReadTokens + tokens.cacheWriteTokens, tokens }\n if (previous && JSON.stringify(previous) === JSON.stringify(group)) return state\n const groups = state.facts.groups.map(g => ({ ...g, tokens: { ...g.tokens } }))\n if (previous) {\n const old = groups.find(g => costGroupKey(g, table) === costGroupKey(previous, table))\n if (old) for (const k of COST_TOKEN_KEYS) old.tokens[k] -= previous.tokens[k]\n }\n let target = groups.find(g => costGroupKey(g, table) === costGroupKey(group, table))\n if (!target) { target = { ...group, tokens: zeroCostTokens() }; groups.push(target) }\n for (const k of COST_TOKEN_KEYS) target.tokens[k] += tokens[k]\n return { ...state, last: { turn: data.turn, step: data.step, group }, facts: { pricingKey: version, groups: groups.filter(g => COST_TOKEN_KEYS.some(k => g.tokens[k] > 0)) } }\n },\n wire: {\n view: (state: CostState) => state.facts,\n viewSchema: { parse(value: unknown): SessionCostFacts { return parseState({ selection: null, at: null, last: null, facts: value }).facts } },\n },\n }\n}\n\nexport function installCostProjection(ctx: Context): void {\n ctx.inject(['sessionProjections'], c => {\n const registry = c.get('sessionProjections') as { register(definition: ReturnType<typeof createCostProjection>): () => void } | undefined\n if (typeof registry?.register === 'function') c.effect(() => registry.register(createCostProjection()), 'commandcode cost projection')\n })\n}\n","/**\n * Multi-account pool for the Command Code provider (host side).\n *\n * One Command Code subscription (e.g. the Go plan's 5-hour window) is\n * metered; a user with several subscriptions wants a request that hits one\n * account's limit to continue on the next account without a visible failure.\n * This module owns that rotation:\n *\n * - {@link CommandCodeAccountPool.resolveKey} hands out the first account\n * whose key is not currently marked exhausted — or, when the request's\n * model matches a {@link CommandCodeModelAccountRule} and that account is\n * usable, the routed account — resolving each slot's key lazily (literal\n * config key → credential seam → launch environment → the official CLI\n * auth file for the default slot only).\n * - {@link CommandCodeAccountPool.markRejected} records a 429 (rate limit,\n * window unknown) or 401 (invalid key, disabled until the config changes)\n * against the exact API key, so several slots sharing one key share one\n * state.\n * - When every account is marked, the pool probes each key's\n * `/alpha/billing/credits` window limits (through the injected\n * {@link CommandCodeAccountPoolDeps.probeWindow}): an account whose window\n * no longer reports `exceeded` is revived, otherwise the pool throws a\n * `RATE_LIMIT` error naming the earliest reset time.\n *\n * The pool is deliberately cordis-free (like the adapter): every host fact\n * arrives through injected thunks, so node tests can drive it directly.\n *\n * @module dsh-commandcode-provider/accounts\n */\n\nimport { LlmError } from '@deepseek-ai/dsh-llm'\nimport type { CredentialRef } from '@deepseek-ai/dsh-credentials'\n\n/**\n * Upper bound on the retry wait this pool attaches to the all-exhausted\n * `RATE_LIMIT` error. Must equal the `backoff.maxDelayMs` in the adapter's\n * `providerRetryPolicy` (which imports it from here): dsh-llm-retry honors a\n * provider-specified wait verbatim only at or below that cap — in normal mode\n * a LONGER attached wait makes the executor abandon the retry entirely\n * instead of falling back to local backoff, which would turn \"poll until the\n * window opens\" into \"fail now\".\n */\nexport const RETRY_MAX_DELAY_MS = 900_000\n\n/** One extra account's raw configuration (composition config or settings). */\nexport interface CommandCodeAccountConfig {\n /** Display label shown in the usage dashboard and settings page. */\n label?: string\n /** Credential reference (environment-variable style name) holding this account's API key. */\n apiKeyEnv?: string\n /** Literal API key (composition config only; never stored in settings). */\n apiKey?: string\n}\n\n/** One account slot after config normalization. */\nexport interface CommandCodeAccountSlot {\n /** Stable id: `default` for the implicit first account, `account-N` for extras. */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Credential reference resolved through the seam; undefined for literal-only slots. */\n ref?: CredentialRef | undefined\n /** Literal key from composition config. */\n literal?: string | undefined\n /** Whether the official CLI auth file may back this slot (default slot only). */\n allowAuthFile: boolean\n}\n\n/** Why a key stopped serving requests. */\nexport type AccountRejection = 'rate-limit' | 'invalid-credential'\n\n/** One key's rotation state. */\nexport interface CommandCodeAccountState {\n kind:\n /** Marked by a 429; the window's reset time is unknown until probed. */\n | 'unknown'\n /** Probed (or marked with a known reset): unusable until `until` (millis). */\n | 'cooldown'\n /** Marked by a 401: skipped until the stored credential changes. */\n | 'disabled'\n /** Human-readable reason for the mark (e.g. `rate limited (429)`). */\n reason: string\n /** Cooldown end in millis; 0 for the other kinds. */\n until: number\n}\n\n/** A slot paired with its resolved key (both pool-internal and UI-facing). */\nexport interface ResolvedAccount {\n slot: CommandCodeAccountSlot\n key: string\n /** The key's current rotation state; undefined means usable. */\n state: CommandCodeAccountState | undefined\n}\n\n/** Five-hour window facts probed from `/alpha/billing/credits`. */\nexport interface FiveHourWindowProbe {\n exceeded: boolean\n resetAt: number\n}\n\n/** Everything the pool needs from the host; all seams are injected. */\nexport interface CommandCodeAccountPoolDeps {\n /** The current account slots, re-read per resolution so settings changes apply live. */\n slots(): readonly CommandCodeAccountSlot[]\n /** Resolve one credential reference through the credentials service or the launch environment. */\n resolveRef(ref: CredentialRef): Promise<string | undefined>\n /** The official CLI auth-file key (`~/.commandcode/auth.json`); default slot only. */\n authFileKey(): string | undefined\n /** Probe one key's five-hour window; undefined when the probe itself failed. */\n probeWindow(apiKey: string): Promise<FiveHourWindowProbe | undefined>\n /**\n * The manually selected account (a slot id, e.g. `default` or an extra's\n * credential reference), re-read per resolution. The preferred account\n * serves whenever it is usable; an unknown id or an exhausted preferred\n * account falls back to the first usable slot.\n */\n preferredId?(): string | undefined\n /**\n * Model → account routing rules, re-read per resolution so settings changes\n * apply live. Each rule lists catalog model ids (see\n * {@link CommandCodeModelAccountRule}) to an account slot id. When the\n * request's model matches a rule and that account is usable, it serves\n * before the preferred/rotation selection; an unusable routed account falls\n * back to the normal selection (the router is a hint, never a hard gate).\n */\n modelAccountRules?(): readonly CommandCodeModelAccountRule[]\n}\n\n/**\n * One \"route these models to that account\" rule. `models` lists catalog ids\n * (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an\n * extra account's credential reference). A request whose model id is in the\n * list routes to that account. The first matching rule in list order wins.\n */\nexport interface CommandCodeModelAccountRule {\n /** Catalog model ids to match against the request's model. */\n models: string[]\n /** Account slot id to prefer for matching models. */\n account: string\n}\n\n/** A labeled, human-readable clock reading for error messages. */\nfunction clockLabel(ms: number): string {\n return new Date(ms).toLocaleString()\n}\n\n/**\n * Whether an account with this rotation state can serve a request right now.\n * `undefined` (never rejected) is usable; a cooldown becomes usable again\n * once its reset time passes; `unknown` (429, reset unprobed) and\n * `disabled` (401) are not.\n */\nexport function accountUsable(state: CommandCodeAccountState | undefined): boolean {\n if (state === undefined) return true\n if (state.kind === 'cooldown') return state.until > 0 && Date.now() >= state.until\n return false\n}\n\n/**\n * Pick the account that should serve now: the manually preferred slot when it\n * is usable, otherwise the first usable account in rotation order; undefined\n * when no account is usable. Shared by the pool (request path) and the plugin\n * entry (the usage view's active badge) so both always agree.\n */\nexport function selectActiveAccount(\n accounts: readonly ResolvedAccount[],\n preferredId: string | undefined,\n): ResolvedAccount | undefined {\n const usable = accounts.filter((account) => accountUsable(account.state))\n if (preferredId !== undefined) {\n const preferred = usable.find((account) => account.slot.id === preferredId)\n if (preferred !== undefined) return preferred\n }\n return usable[0]\n}\n\n/**\n * The first routing rule whose model list contains the request's model id.\n * Undefined when no rule matches.\n */\nexport function matchModelRule(\n model: string,\n rules: readonly CommandCodeModelAccountRule[] | undefined,\n): CommandCodeModelAccountRule | undefined {\n if (model === '' || rules === undefined || rules.length === 0) return undefined\n for (const rule of rules) {\n if (rule.models.includes(model)) return rule\n }\n return undefined\n}\n\n/**\n * The routed account for a request's model: the first usable account whose\n * slot id matches the first matching rule's target. Undefined when no rule\n * matches or the routed account is not usable (the caller then falls back to\n * the normal preferred/rotation selection).\n */\nexport function selectAccountForModel(\n accounts: readonly ResolvedAccount[],\n model: string,\n rules: readonly CommandCodeModelAccountRule[] | undefined,\n): ResolvedAccount | undefined {\n const rule = matchModelRule(model, rules)\n if (rule === undefined) return undefined\n return accounts.find((account) => account.slot.id === rule.account && accountUsable(account.state))\n}\n\n/**\n * The account pool. Rotation state is keyed by API key (never logged), so two\n * slots resolving to the same credential share one mark, and a key changed in\n * the credentials service starts with a clean slate.\n */\nexport class CommandCodeAccountPool {\n /** Rotation state by API key. */\n private readonly states = new Map<string, CommandCodeAccountState>()\n constructor(private readonly deps: CommandCodeAccountPoolDeps) {}\n\n /**\n * Resolve every slot's key, deduplicated by key (first slot wins). Slots\n * without any resolvable key are omitted — they still appear in the\n * settings page as unconfigured, they just cannot serve requests.\n */\n async resolvedAccounts(): Promise<ResolvedAccount[]> {\n const out: ResolvedAccount[] = []\n const seen = new Set<string>()\n for (const slot of this.deps.slots()) {\n const key = await this.resolveSlotKey(slot)\n if (key === undefined || seen.has(key)) continue\n seen.add(key)\n out.push({ slot, key, state: this.states.get(key) })\n }\n return out\n }\n\n /**\n * Every slot paired with its resolved key and rotation state — NOT\n * deduplicated: two slots sharing one credential both appear (the usage\n * view reports them individually), while slots without any resolvable key\n * are omitted. The serving path uses {@link resolvedAccounts} instead.\n */\n async describeAccounts(): Promise<ResolvedAccount[]> {\n const out: ResolvedAccount[] = []\n for (const slot of this.deps.slots()) {\n const key = await this.resolveSlotKey(slot)\n if (key === undefined) continue\n out.push({ slot, key, state: this.states.get(key) })\n }\n return out\n }\n\n /**\n * Hand out the key for a request: the model-routed account when the\n * request's model matches a rule (and that account is usable), else the\n * manually preferred account when usable, else the first usable account in\n * rotation order. Returns `undefined` when no account resolves any key at\n * all (the caller then reports the missing credential). Throws\n * `RATE_LIMIT` — naming the earliest window reset — or\n * `INVALID_CREDENTIAL` when accounts exist but none can serve.\n *\n * `options.model` is the request's model id; routing rules re-read per\n * resolution, so a settings change applies live.\n *\n * `options.exclude` skips one key during the probe-revival pass: the\n * rotation hook excludes the just-rejected key so a probe that clears its\n * window cannot re-offer the same key within the same request (the adapter\n * refuses already-tried keys; the next request picks the revived key up).\n */\n async resolveKey(options?: { exclude?: string; model?: string }): Promise<{ key: string; slot: CommandCodeAccountSlot } | undefined> {\n const accounts = await this.resolvedAccounts()\n if (accounts.length === 0) {\n return undefined\n }\n const routed = selectAccountForModel(accounts, options?.model ?? '', this.deps.modelAccountRules?.())\n if (routed !== undefined) return this.pick(routed)\n const preferred = this.deps.preferredId?.()\n const chosen = selectActiveAccount(accounts, preferred)\n if (chosen !== undefined) return this.pick(chosen)\n\n // Every key is marked: probe the real windows before giving up. Disabled\n // (401) keys are not probed — an invalid key stays invalid. A throwing\n // probe counts as \"unknown\" (like a failed probe): it must not turn the\n // all-exhausted path into a raw rejection instead of RATE_LIMIT.\n await Promise.all(accounts.map(async (account) => {\n if (account.state?.kind === 'disabled') return\n if (options?.exclude !== undefined && account.key === options.exclude) return\n let probe: FiveHourWindowProbe | undefined\n try {\n probe = await this.deps.probeWindow(account.key)\n } catch {\n return\n }\n if (probe === undefined) return\n if (!probe.exceeded) {\n this.states.delete(account.key)\n } else {\n this.states.set(account.key, {\n kind: 'cooldown',\n reason: account.state?.reason ?? 'rate limited (429)',\n until: probe.resetAt,\n })\n }\n }))\n\n // Re-resolve once: the probe pass above may have revived keys (fresh\n // states), and both the revival check and the error classification read\n // the same post-probe snapshot. (Each resolvedAccounts() re-runs the\n // async seams, so two calls — not three — is the minimum here.)\n const latest = await this.resolvedAccounts()\n const revived = selectActiveAccount(latest, preferred)\n if (revived !== undefined) return this.pick(revived)\n\n const disabled = latest.filter((account) => account.state?.kind === 'disabled')\n if (disabled.length === latest.length) {\n // Bilingual: the harness UI renders this message verbatim inside its\n // (already localized) retry/turn-error chrome, so both languages ride\n // in one string — English first, then the Chinese reading.\n throw new LlmError(\n `llm-commandcode: every configured Command Code account (${latest.length}) was rejected with 401`\n + ' — check the stored API keys (Models page / settings) or the auth file'\n + `;已配置的 ${latest.length} 个 Command Code 账户密钥均被拒绝(401)`\n + '——请在设置页检查存储的 API 密钥,或重新运行 command-code login',\n 'INVALID_CREDENTIAL',\n )\n }\n const resets = latest\n .map((account) => account.state)\n .filter((state): state is CommandCodeAccountState => state !== undefined && state.kind === 'cooldown' && state.until > 0)\n .map((state) => state.until)\n const earliest = resets.length > 0 ? Math.min(...resets) : 0\n // Hand dsh-llm-retry the exact wait until the earliest known reset so the\n // retry policy sleeps through the window instead of polling at its\n // backoff cadence. Capped at RETRY_MAX_DELAY_MS: the executor honors a\n // provider wait verbatim only at or below the policy's maxDelayMs — a\n // LONGER attached wait makes it abandon the retry entirely (normal mode),\n // which would turn \"poll until the window opens\" into \"fail now\". Longer\n // resets simply ride the capped local backoff and the probe revival.\n const wait = earliest > 0 ? Math.max(1000, earliest - Date.now()) : 0\n throw new LlmError(\n `llm-commandcode: all ${latest.length} Command Code account(s) have exhausted their usage window`\n + (earliest > 0 ? `; the earliest window resets at ${clockLabel(earliest)}` : '')\n + ' — requests will succeed again after the reset (or add another account)'\n + `;已用尽全部 ${latest.length} 个 Command Code 账户的用量窗口`\n + (earliest > 0 ? `,最早的重置时间为 ${clockLabel(earliest)}` : '')\n + '——窗口重置后请求会自动恢复(也可以添加更多账户)',\n 'RATE_LIMIT',\n wait > 0 && wait <= RETRY_MAX_DELAY_MS ? { providerRetryAfterMs: wait } : undefined,\n )\n }\n\n /**\n * Record a rejection against one key. `rate-limit` (429) marks the key\n * exhausted with an unknown reset (probed lazily at the next resolution\n * once every account is marked); `invalid-credential` (401) disables the\n * key until the stored credential changes.\n */\n markRejected(apiKey: string, rejection: AccountRejection): void {\n if (rejection === 'invalid-credential') {\n this.states.set(apiKey, { kind: 'disabled', reason: 'invalid API key (401)', until: 0 })\n } else {\n this.states.set(apiKey, { kind: 'unknown', reason: 'rate limited (429)', until: 0 })\n }\n }\n\n /**\n * One account's key: literal → credential seam → auth file (default slot).\n *\n * Every source is normalized here, at the single point where a slot's key\n * enters the pool. The adapter sends the key through the harness's\n * `assertUsableApiKey()`, which trims it — a stored key from the credentials\n * seam, a `.env` line, or a shell export all pick up surrounding whitespace\n * — and reports that trimmed form back to `markRejected()`. Returning the\n * raw value would file every 429/401 mark under a key no later lookup can\n * find: rotation would re-offer the same account, the account card would show\n * no mark, and the usage endpoints would 401 while chat kept working.\n * Normalizing once makes resolution, probing, marking, and the request path\n * agree on one string.\n */\n private async resolveSlotKey(slot: CommandCodeAccountSlot): Promise<string | undefined> {\n if (slot.literal !== undefined) {\n const literal = normalizeResolvedKey(slot.literal)\n if (literal !== undefined) return literal\n }\n if (slot.ref !== undefined) {\n const hit = await this.deps.resolveRef(slot.ref)\n if (hit !== undefined) {\n const resolved = normalizeResolvedKey(hit)\n if (resolved !== undefined) return resolved\n }\n }\n if (slot.allowAuthFile) {\n const fromFile = this.deps.authFileKey()\n if (fromFile !== undefined) {\n const fileKey = normalizeResolvedKey(fromFile)\n if (fileKey !== undefined) return fileKey\n }\n }\n return undefined\n }\n\n /** Hand out the chosen account's key. */\n private pick(account: ResolvedAccount): { key: string; slot: CommandCodeAccountSlot } {\n return { key: account.key, slot: account.slot }\n }\n}\n\n/**\n * Normalize one resolved credential to the form every consumer sees. Trim\n * only: a blank-after-trim value means \"no key\" (the slot is omitted and the\n * caller reports `MISSING_CREDENTIAL`), while characters an HTTP header cannot\n * carry are left for `assertUsableApiKey()` to reject with its own message.\n */\nfunction normalizeResolvedKey(value: string): string | undefined {\n const trimmed = value.trim()\n return trimmed === '' ? undefined : trimmed\n}\n","/**\n * Request-image targets: the shape one provider request asks the attachment\n * service to produce.\n *\n * An attachment is stored NORMALIZED, not request-ready — `readImage()` answers\n * the full normalized original, which is what admission accepted. Every request\n * should carry a REQUEST VERSION instead (`readImageRequest()`): the same image\n * re-encoded to a route target and cached under it. On this route that matters\n * three times over, because both transports inline every historical image as\n * base64: bytes become context, latency, and progress against the gateway's\n * undocumented ~50 MB body cap (see the request image budget in `./adapter.ts`).\n *\n * ONE target serves both attachment generations, although they disagree on the\n * shape AND on where the projection happens:\n *\n * ≤ 0.1.5 — `readImageRequest(ref, policy)` takes `{ maxPixels, maxBytes }` and\n * applies the pixel budget itself, aspect-preserving.\n * ≥ 0.1.6 — `readImageRequest(ref, target)` takes the ALREADY PROJECTED\n * `{ width, height, maxBytes }`; there is no pixel budget any more.\n *\n * So the target carries both vocabularies: the projected dimensions, plus the\n * pixel area they came from. Each generation reads the fields it knows and\n * ignores the rest — which is why the object is BUILT HERE and passed as a\n * variable: an object literal at the call site would be rejected by the\n * excess-property check of whichever generation's types this checkout compiles\n * against, and those types are a release behind the engine at runtime.\n *\n * Nothing in here may import a version-specific helper (`longEdgeDimensions`\n * only exists from 0.1.6), so the projection is restated locally.\n *\n * @module dsh-commandcode-provider/image-request\n */\n\nimport type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\n/**\n * Long edge one request image may keep, in pixels.\n *\n * 1568 is Anthropic's documented ceiling — their API downscales anything larger\n * before the model sees it — and it sits inside the high-detail band of the\n * OpenAI and Gemini tile schemes, so no upstream this gateway reaches reads\n * more detail than the target keeps. Screenshots from a Retina display are the\n * case this is for: 2880x1800 becomes 1568x980, a 3.4x pixel cut, and the\n * models lose nothing they would not have downscaled themselves.\n */\nexport const REQUEST_IMAGE_MAX_LONG_EDGE = 1568\n\n/**\n * Encoded bytes one request image may keep, before base64 expansion. The same\n * 1 MiB budget the harness's own multi-provider adapter defaults to; the\n * attachment service keeps its smallest quality-ladder output when no quality\n * fits, so this bounds bytes without ever refusing an image.\n */\nexport const REQUEST_IMAGE_MAX_ENCODED_BYTES = 1024 * 1024\n\n/**\n * One image's request target, in both generations' vocabulary at once. See the\n * module note: the extra fields are deliberate, not leftovers.\n */\nexport interface RequestImageTarget {\n /** ≤0.1.5's pixel budget: the projected area this target came from. */\n maxPixels: number\n /** ≥0.1.6's target width, already projected. */\n width: number\n /** ≥0.1.6's target height, already projected. */\n height: number\n /** Both generations' encoded-byte budget. */\n maxBytes: number\n}\n\n/**\n * Aspect-preserving projection onto a long-edge budget; never enlarges, and\n * never returns a zero dimension (a 1-px degenerate side is what the round of\n * an extreme aspect ratio can produce, and a 0 would make the encoder refuse).\n *\n * A local restatement of the helper 0.1.6 exports from `dsh-attachment`, which\n * 0.1.2–0.1.5 do not have; the math is the whole contract, so keeping the copy\n * here costs less than a version probe would.\n */\nexport function longEdgeDimensions(\n width: number,\n height: number,\n longEdge: number,\n): { width: number; height: number } {\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n // Defensive: a malformed reference must not become a zero-sized target.\n return { width: Math.max(1, Math.round(width) || 1), height: Math.max(1, Math.round(height) || 1) }\n }\n if (longEdge >= Math.max(width, height)) return { width, height }\n return width >= height\n ? { width: longEdge, height: Math.max(1, Math.round((longEdge * height) / width)) }\n : { width: Math.max(1, Math.round((longEdge * width) / height)), height: longEdge }\n}\n\n/**\n * The request target for one normalized attachment: its aspect ratio under the\n * long-edge budget, plus the byte budget every generation honours.\n *\n * The area is computed from the PROJECTED dimensions rather than the source's,\n * so ≤0.1.5's own pixel projection lands on the same geometry instead of\n * re-deriving a slightly different one from the original.\n */\nexport function requestImageTarget(ref: ImageAttachmentRef): RequestImageTarget {\n const projected = longEdgeDimensions(ref.width, ref.height, REQUEST_IMAGE_MAX_LONG_EDGE)\n return {\n maxPixels: projected.width * projected.height,\n width: projected.width,\n height: projected.height,\n maxBytes: REQUEST_IMAGE_MAX_ENCODED_BYTES,\n }\n}\n","/**\n * Vision-token accounting for the model families Command Code routes to.\n *\n * The harness's token meter prices request images through\n * `LlmAdapter.imageRequestPricing(provider, model).priceImages(blocks)` and,\n * when a route declares nothing, falls back to a structural estimate that\n * charges a handful of tokens for ANY image. On an image-heavy session that is\n * not a rounding error: a screenshot loop can carry dozens of full-size images\n * that the heuristic prices at ~0 tokens each, so context pressure is\n * under-reported and the session walks into its own context window.\n *\n * This route is a gateway in front of many upstreams — one catalog id per model,\n * but the visual-token rule belongs to whoever serves it. So the estimate is per\n * FAMILY, using each vendor's published rule, and the families are recognised by\n * the catalog id (which names the vendor). Every formula is stated here rather\n * than imported: the only in-tree implementations live inside the official\n * adapters, and this plugin deliberately does not depend on those protocols.\n *\n * These are ESTIMATES for context accounting, not invoices — the provider's own\n * usage remains authoritative for a completed request, exactly as the published\n * per-token rates the session-cost readout uses are.\n *\n * @module dsh-commandcode-provider/image-tokens\n */\n\nimport { longEdgeDimensions } from './image-request.ts'\n\n/** The published visual-token rules this route can tell apart. */\nexport type ImageTokenFamily = 'anthropic' | 'openai' | 'google' | 'deepseek' | 'generic'\n\n/**\n * Which family prices one catalog model id.\n *\n * `generic` is not \"we do not know the model\" but \"we cannot tell its visual\n * rule apart from the known ones\" — the Qwen, MiniMax, xAI, moonshot and\n * sakana families all publish patch- or tile-based accounting close to the\n * Anthropic rule, so the conservative fallback below covers them without\n * pretending to more precision than we have.\n */\nexport function imageTokenFamily(modelId: string): ImageTokenFamily {\n const id = modelId.toLowerCase()\n const vendor = id.includes('/') ? id.slice(0, id.indexOf('/')) : ''\n if (id.startsWith('claude')) return 'anthropic'\n if (id.startsWith('gpt') || /^o[1-9]/.test(id)) return 'openai'\n if (vendor === 'google' || id.startsWith('gemini')) return 'google'\n if (vendor === 'deepseek') return 'deepseek'\n return 'generic'\n}\n\n/**\n * Visual tokens one request image costs on the given family, at the dimensions\n * this route would actually send (see `./image-request.ts`).\n */\nexport function imageTokenCost(family: ImageTokenFamily, width: number, height: number): number {\n switch (family) {\n case 'anthropic': return anthropicImageTokens(width, height)\n case 'openai': return openAiImageTokens(width, height)\n case 'google': return googleImageTokens(width, height)\n case 'deepseek': return deepSeekImageTokens(width, height)\n default: return genericImageTokens(width, height)\n }\n}\n\n/** Convenience for callers that have a model id: family lookup plus the rule. */\nexport function commandCodeImageTokens(modelId: string, width: number, height: number): number {\n return imageTokenCost(imageTokenFamily(modelId), width, height)\n}\n\n/**\n * Anthropic: the image is first scaled so its long edge is at most 1568 px\n * (never enlarged), then charged roughly one token per 750 pixels.\n * Source: Anthropic vision documentation, \"Image size and token usage\".\n */\nfunction anthropicImageTokens(width: number, height: number): number {\n const projected = longEdgeDimensions(width, height, 1568)\n return Math.max(1, Math.ceil((projected.width * projected.height) / 750))\n}\n\n/**\n * OpenAI (high detail): scale to fit inside 2048x2048, then scale the shortest\n * side to 768 px, then charge an 85-token base plus 170 tokens per 512x512\n * tile. Source: OpenAI vision documentation, \"Calculating costs\".\n */\nfunction openAiImageTokens(width: number, height: number): number {\n let scaled = { width: Math.max(1, width), height: Math.max(1, height) }\n const longest = Math.max(scaled.width, scaled.height)\n if (longest > 2048) scaled = scaleBy(scaled, 2048 / longest)\n const shortest = Math.min(scaled.width, scaled.height)\n if (shortest > 768) scaled = scaleBy(scaled, 768 / shortest)\n const tiles = Math.ceil(scaled.width / 512) * Math.ceil(scaled.height / 512)\n return 85 + 170 * tiles\n}\n\n/**\n * Google Gemini: an image whose both sides are at most 384 px costs a flat 258\n * tokens; anything larger is cropped into 768x768 tiles of 258 tokens each.\n * Source: Gemini image-understanding documentation.\n */\nfunction googleImageTokens(width: number, height: number): number {\n if (width <= 384 && height <= 384) return 258\n return 258 * Math.ceil(width / 768) * Math.ceil(height / 768)\n}\n\n/** 14-px patches, merged 3x3 into one token cell. */\nconst DEEPSEEK_PATCH_SIZE = 14\nconst DEEPSEEK_DOWNSAMPLE_RATIO = 3\n/** The provider's cap on tokens for one request image. */\nconst DEEPSEEK_MAX_IMAGE_TOKENS = 1024\n/** Total-pixel floor; a smaller image is enlarged before grid projection. */\nconst DEEPSEEK_MIN_PIXELS = 544 * 544\n\n/**\n * DeepSeek: pad to 14-px patches, merge each 3x3 patch block into one token\n * cell, charge one token per cell plus one separator per row plus two framing\n * tokens, and cap one image at 1024 tokens by downscaling it aspect-preserving\n * (images below 544x544 are enlarged first).\n *\n * Mirrors `deepSeekImageTokens` in the official `dsh-llm-deepseek` adapter\n * (its `PATCH_SIZE`, `DOWNSAMPLE_RATIO`, `MAX_IMAGE_TOKENS` and `MIN_PIXELS`).\n * The official solver picks the largest grid that fits the cap; this restates\n * that as a bounded search over the scale factor, which lands on the same grid\n * without vendoring the closed-form solver.\n */\nfunction deepSeekImageTokens(width: number, height: number): number {\n let scaled = { width: Math.max(1, width), height: Math.max(1, height) }\n const pixels = scaled.width * scaled.height\n if (pixels < DEEPSEEK_MIN_PIXELS) scaled = scaleBy(scaled, Math.sqrt(DEEPSEEK_MIN_PIXELS / pixels))\n\n const direct = deepSeekGridTokens(scaled.width, scaled.height)\n if (direct <= DEEPSEEK_MAX_IMAGE_TOKENS) return direct\n\n // Over the cap: the provider keeps the aspect ratio and downsamples until the\n // grid fits, so the charge is the largest fitting grid — never above the cap.\n let low = 0\n let high = 1\n let best = direct\n for (let step = 0; step < 24; step += 1) {\n const mid = (low + high) / 2\n const tokens = deepSeekGridTokens(\n Math.max(1, Math.round(scaled.width * mid)),\n Math.max(1, Math.round(scaled.height * mid)),\n )\n if (tokens <= DEEPSEEK_MAX_IMAGE_TOKENS) {\n low = mid\n best = tokens\n } else {\n high = mid\n }\n }\n return best\n}\n\n/** One token grid's charge: every row carries a separator, plus two framing tokens. */\nfunction deepSeekGridTokens(width: number, height: number): number {\n const cellsWide = cellCount(width)\n const cellsHigh = cellCount(height)\n return cellsHigh * (cellsWide + 1) + 2\n}\n\n/** Token cells along one padded pixel axis. */\nfunction cellCount(length: number): number {\n const patches = Math.ceil(length / DEEPSEEK_PATCH_SIZE)\n return Math.ceil(patches / DEEPSEEK_DOWNSAMPLE_RATIO)\n}\n\n/**\n * The conservative fallback for a family we cannot price exactly: the MOST\n * expensive of the three simple published rules at these dimensions.\n *\n * Chosen deliberately. Under-reporting context is what lets a session walk into\n * its own context window, while over-reporting only makes the meter cautious;\n * for the real families this covers (Qwen's 28-px patches, MiniMax, xAI,\n * moonshot, sakana) the Anthropic rule is the close one, and it is the maximum\n * at every size except the sub-384-px band, where Gemini's flat 258 wins.\n */\nfunction genericImageTokens(width: number, height: number): number {\n return Math.max(\n anthropicImageTokens(width, height),\n openAiImageTokens(width, height),\n googleImageTokens(width, height),\n )\n}\n\n/** Scale one dimension pair by a positive factor, rounded to whole pixels. */\nfunction scaleBy(\n size: { width: number; height: number },\n factor: number,\n): { width: number; height: number } {\n return {\n width: Math.max(1, Math.round(size.width * factor)),\n height: Math.max(1, Math.round(size.height * factor)),\n }\n}\n","/**\n * DeepSeek Harness LLM adapter for the Command Code Provider API.\n *\n * Ported from pi-commandcode-provider@0.5.1 (MIT). This is an unofficial,\n * community-maintained integration; you need your own Command Code account\n * and API key or subscription, and Command Code's terms apply.\n *\n * Wire protocol (reverse-engineered by the pi plugin, command-code@1.28.4;\n * re-verified against command-code@1.54.0 — endpoints, request shape, and\n * stream events unchanged):\n * POST {apiBase}/alpha/generate\n * body: { config, memory, taste, skills, params: { model, messages, tools,\n * system, max_tokens, temperature, stream, reasoning_effort? }, threadId }\n * SSE-ish JSONL events: text-delta | reasoning-start/delta/end | tool-call\n * | tool-result | finish | error\n * Model catalog: GET {apiBase}/provider/v1/models -> { object: 'list', data: [...] }\n *\n * The adapter is deliberately free of cordis/schemastery: it receives a\n * per-request options thunk and an API-key resolver from the plugin entry\n * (src/index.ts), so a settings change reaches the very next request.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\n\nimport type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\nimport {\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n ToolCallId,\n errorChain,\n offloadedImageText,\n resolveRetryPolicy,\n textOnlyImageText,\n type ImageBlock,\n type LlmErrorOptions,\n type LlmImageRequestPrice,\n type LlmImageRequestPricing,\n type ResolvedRetryPolicy,\n type ContentBlock,\n type FinishReason,\n type GenerateOptions,\n type LlmModelInfo,\n type LlmProviderInfo,\n type LlmResolvedModelInfo,\n type Message,\n type StreamChunk,\n type TokenUsage,\n} from '@deepseek-ai/dsh-llm'\n// Namespace import, on purpose: the request-image policy is the ONE part of\n// dsh-llm's surface that changed shape between the supported engines (see\n// `CoreImagePolicy`). Every generation is reached through this object and\n// probed at runtime, because a static named import of an export the installed\n// engine does not have is an ESM link-time failure that takes the whole plugin\n// down — `offloadRequestImagesWithPolicy` was removed in 0.1.6, and\n// `requiredImageOffload`/`projectOffloadedImages` do not exist before it.\nimport * as dshLlm from '@deepseek-ai/dsh-llm'\nimport { RETRY_MAX_DELAY_MS } from './accounts.ts'\nimport { requestImageTarget } from './image-request.ts'\nimport { commandCodeImageTokens } from './image-tokens.ts'\n\nimport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n capabilityDescription,\n compareByPlan,\n modelVisibleInPlan,\n requiresMessagesEndpoint,\n subscriptionPlanInfo,\n type CommandCodeBillingAccess,\n} from './capabilities.ts'\n\n// ---------------------------------------------------------------------------\n// Request / connection defaults (protocol constants). The model/plan/deal\n// capability snapshot lives in ./capabilities.ts — the sync-only surface.\n// ---------------------------------------------------------------------------\nexport const COMMAND_CODE_CLI_VERSION = '1.54.0'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\nexport const DEFAULT_GENERATE_MAX_TOKENS = 64_000\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 65_536\nexport const MODELS_TIMEOUT_MS = 10_000\n/** How long the picker's plan-filter billing facts stay cached before refetching. */\nexport const BILLING_ACCESS_TTL_MS = 5 * 60_000\n/**\n * How long a learned CLI-only protocol preference stays cached per account.\n * After this TTL a request may probe Provider API again, so an upgraded Go\n * account can recover without a restart.\n */\nexport const PROTOCOL_CACHE_TTL_MS = 15 * 60_000\n/** Endpoint protocol selected for one generate call. */\ntype CommandCodeProtocol = 'cli' | 'openai'\n\n/** The entry-plan tier weight (`individual-go` in KNOWN_SUBSCRIPTION_PLANS). */\nconst GO_TIER_WEIGHT = 0\n\n/** Hard cap on account rotations within one request (one attempt per distinct key). */\nconst MAX_ACCOUNT_ROTATIONS = 16\n\n/**\n * Subscription statuses the CLI treats as live (`Mr` in command-code's\n * cli.mjs): the plan gate applies only under one of these.\n */\nconst ACTIVE_SUBSCRIPTION_STATUSES: ReadonlySet<string> = new Set(['active', 'trialing', 'past_due'])\n/** Head-of-request timeout: how long to wait for the first response byte. */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n/** Stream idle timeout: a generation that stalls this long is a dead connection. */\nexport const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000\nconst MODEL_CACHE_VERSION = 1\n\n// ---------------------------------------------------------------------------\n// Small helpers (ported from converters.ts / models.ts)\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction booleanValue(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\n/**\n * Thinking text carried by an OpenRouter-shaped `reasoning_details` array\n * (`[{ type: 'reasoning.text', text, format, index }]`), concatenated in the\n * order the gateway sent it.\n *\n * Entries are read by their `text` member alone rather than filtered on\n * `type === 'reasoning.text'`: the sibling shapes in that protocol carry\n * `summary` or an encrypted blob instead of `text`, so a plain read already\n * ignores them, while a type filter would silently drop a text-bearing variant\n * added later — and losing thinking is the failure this exists to prevent.\n * Returns undefined when the array yields nothing, so the caller's `??` chain\n * keeps falling through instead of treating \"no text\" as a reasoning delta.\n */\nfunction reasoningDetailsText(value: unknown): string | undefined {\n if (!Array.isArray(value)) return undefined\n let text = ''\n for (const entry of value) {\n if (!isRecord(entry)) continue\n text += stringValue(entry.text) ?? ''\n }\n return text === '' ? undefined : text\n}\n\n/** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */\nfunction periodEndValue(value: unknown): number {\n const asNumber = numberValue(value)\n if (asNumber !== undefined) return asNumber\n const asString = stringValue(value)\n if (asString === undefined) return 0\n const parsed = Date.parse(asString)\n return Number.isNaN(parsed) ? 0 : parsed\n}\n\n/**\n * Terminal stream-error markers from the official CLI (`Xw` in command-code's\n * cli.mjs): these always mean \"retrying cannot succeed\", so the adapter must\n * not classify them as transient server errors.\n */\nconst TERMINAL_STREAM_ERROR_MARKERS = [\n 'premium_credits_exhausted',\n 'model_not_in_plan',\n 'insufficient credits',\n]\n\nfunction hasTerminalStreamMarker(message: string): boolean {\n const lower = message.toLowerCase()\n return TERMINAL_STREAM_ERROR_MARKERS.some((marker) => lower.includes(marker))\n}\n\n/**\n * Context-window wording the provider uses to reject a request that outgrew\n * the model's window. `isContextWindowExceededError` is the harness's own\n * provider-neutral classifier — and the contract `CONTEXT_WINDOW_EXCEEDED`\n * exists for — so it decides; the official CLI's `truncated` pattern adds the\n * phrasings Command Code's upstreams emit that the harness helper does not\n * cover (a bare `prompt is too long`, or a complaint about `max_tokens`).\n * The CLI matches these first and answers them by compacting and retrying —\n * never by resending the request unchanged.\n */\nconst CLI_CONTEXT_OVERFLOW_PATTERN = /prompt is too long|context.*(length|window)|max_tokens|maximum.*tokens/i\n\nfunction isContextOverflowDetail(detail: string): boolean {\n return isContextWindowExceededError(detail) || CLI_CONTEXT_OVERFLOW_PATTERN.test(detail)\n}\n\n/**\n * Classify one in-band stream `error` payload into the failure the caller\n * throws. Shared by both transports — the CLI transport delivers it as an\n * `error` event (`{ type: 'error', error }`), the Provider API transport as a\n * top-level `error` member of an SSE chunk — so the two cannot drift apart.\n *\n * The wording decides before the status does, mirroring the official CLI's\n * `classifyKind` (which reads the message first) and the harness helpers\n * (which exist so thrown and in-band delivery share one classifier). Order is\n * load-bearing:\n *\n * - A context-window rejection is terminal for THIS request but recoverable by\n * the harness: `dsh-compaction-basic` listens on `agent/request-error` for\n * `CONTEXT_WINDOW_EXCEEDED` and answers it with a compaction + retry of the\n * reduced surface. That is what lets a long session survive a request that\n * outgrew the model's window, and it is what the official CLI does (its\n * non-retryable `truncated` kind). Reported as retryable `SERVER` — where\n * this wording landed before — the adapter resent the byte-identical\n * oversized request up to `maxRetries` times and the session could never\n * recover, which is exactly the endless-retry-at-long-context report\n * (issue #39).\n * - Credits/plan wording is terminal, so an exhausted balance or a model\n * outside the plan is not retried as if it were a transient rate limit.\n * - Only then does the status/`isRetryable` pair decide, as before.\n */\nfunction streamErrorToLlmError(value: unknown, fallbackMessage?: string): LlmError {\n const record = isRecord(value) ? value : undefined\n const message = record\n ? (stringValue(record.message) ?? JSON.stringify(record))\n : (stringValue(value) ?? fallbackMessage ?? 'Stream error')\n const statusCode = record === undefined\n ? undefined\n : (numberValue(record.statusCode) ?? numberValue(record.status))\n const isRetryable = record === undefined ? undefined : booleanValue(record.isRetryable)\n // Every available provider code/type/message goes to the classifiers: the\n // wording can live in any of them and both harness helpers document their\n // input as the joined detail.\n const detail = [stringValue(record?.code), stringValue(record?.type), message]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\n const statusOption = statusCode !== undefined ? { status: statusCode } : undefined\n\n if (isContextOverflowDetail(detail)) {\n // Bilingual — the harness renders this message verbatim in its retry\n // chrome — and it names the recovery the harness is already performing.\n return new LlmError(\n `Command Code stream error: ${message}`\n + ';Command Code API 拒绝了这次请求:内容超出模型上下文窗口。正在压缩上下文后重试;如仍失败,请新建会话或减少上下文',\n CONTEXT_WINDOW_EXCEEDED_CODE,\n statusOption,\n )\n }\n const terminal = hasTerminalStreamMarker(detail)\n const retryableStatus = statusCode !== undefined && (statusCode === 429 || statusCode >= 500)\n const retryable = isRetryable === true\n || (statusCode !== undefined ? retryableStatus : (isRetryable !== false && !terminal))\n if (!retryable) {\n return new LlmError(\n `Command Code stream error: ${message}`,\n 'PROVIDER_STREAM_ERROR',\n statusOption,\n )\n }\n return new LlmError(\n `Command Code stream error: ${message}`,\n 'SERVER',\n statusOption,\n )\n}\n\nfunction recordOrEmpty(value: unknown): Record<string, unknown> {\n if (isRecord(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed: unknown = JSON.parse(value)\n if (isRecord(parsed)) return parsed\n } catch {\n // Some providers stream incomplete JSON argument fragments.\n }\n }\n return {}\n}\n\n// ---------------------------------------------------------------------------\n// Tool-schema normalization (issue #35)\n// The gateway validates every function schema's ROOT as an object schema and\n// rejects the whole request otherwise (`schema must be a JSON Schema of\n// type: \"object\", got type: null`). Tool schemas do not always come from\n// the harness's own typed builder, which always declares `type: 'object'`: a\n// third-party plugin or an MCP bridge can register a hand-written schema, and\n// a generator can emit a root `$ref`. Neither is this plugin's to correct, but\n// the request is the plugin's to send, so every schema leaving here is\n// normalized to the object root the provider requires. Only the root is\n// touched, and every path returns a copy: the harness may deep-freeze the\n// caller's schema.\n// ---------------------------------------------------------------------------\n\n/** How deep a root `$ref` / combinator chain is followed while normalizing. */\nconst SCHEMA_NORMALIZE_MAX_DEPTH = 4\n\n/**\n * Whether a type-less node is object-shaped enough to be one with the type\n * declared: `properties`/`required`/`additionalProperties` only make sense on\n * an object, and a schema carrying them was meant to be one.\n */\nfunction isObjectShaped(node: Record<string, unknown>): boolean {\n return (\n isRecord(node.properties) ||\n isRecord(node.patternProperties) ||\n Array.isArray(node.required) ||\n node.additionalProperties !== undefined\n )\n}\n\n/** The `required` names of one schema node, ignoring malformed entries. */\nfunction requiredNames(node: Record<string, unknown>): string[] {\n return Array.isArray(node.required) ? node.required.filter((name): name is string => typeof name === 'string') : []\n}\n\n/** Resolve a local `#/...` pointer inside the schema that carried it. */\nfunction resolveLocalRef(root: Record<string, unknown>, ref: string): Record<string, unknown> | undefined {\n if (!ref.startsWith('#/')) return undefined\n let node: unknown = root\n for (const rawSegment of ref.slice(2).split('/')) {\n const segment = rawSegment.replace(/~1/g, '/').replace(/~0/g, '~')\n if (!isRecord(node)) return undefined\n node = node[segment]\n }\n return isRecord(node) ? node : undefined\n}\n\n/**\n * Flatten a type-less combinator node into one object schema, so the model\n * still sees the branch fields instead of an argument-free tool. `allOf`\n * branches must all hold, so their `required` entries are all kept; `anyOf` /\n * `oneOf` branches are alternatives, so only a name required by every branch\n * survives. Returns undefined when no branch describes an object.\n */\nfunction mergeCombinatorBranches(\n node: Record<string, unknown>,\n depth: number,\n): Record<string, unknown> | undefined {\n // A plugin can hand over a self-referential schema object; the bound keeps\n // the walk finite (JSON-parsed schemas are acyclic, JS ones need not be).\n if (depth >= SCHEMA_NORMALIZE_MAX_DEPTH) return undefined\n const properties: Record<string, unknown> = {}\n const required = new Set<string>()\n const alternatives: string[][] = []\n let sawBranch = false\n\n for (const key of ['allOf', 'anyOf', 'oneOf'] as const) {\n const branches = node[key]\n if (!Array.isArray(branches)) continue\n const objectBranches: Record<string, unknown>[] = []\n for (const branch of branches) {\n if (!isRecord(branch)) continue\n objectBranches.push(toolParametersSchema(branch, depth + 1))\n }\n if (objectBranches.length === 0) continue\n sawBranch = true\n // An `anyOf`/`oneOf` group contributes the intersection of its branches;\n // an `allOf` group contributes the union.\n const names = objectBranches.map(requiredNames)\n if (key === 'allOf') for (const name of names.flat()) required.add(name)\n else if (names.length > 0) {\n alternatives.push(names[0]!.filter((name) => names.every((list) => list.includes(name))))\n }\n for (const branch of objectBranches) {\n const branchProperties = isRecord(branch.properties) ? branch.properties : {}\n for (const [name, schema] of Object.entries(branchProperties)) {\n if (!(name in properties)) properties[name] = schema\n }\n }\n }\n if (!sawBranch) return undefined\n // A name must satisfy every group, so each group's intersection joins the\n // union: an allOf-required field and an anyOf-common field are both required.\n for (const group of alternatives) for (const name of group) required.add(name)\n\n const merged: Record<string, unknown> = { type: 'object', properties }\n if (required.size > 0) merged.required = [...required]\n // The merged schema is a superset of the alternatives it replaced, so it\n // stays open unless the node itself closed it.\n if (node.additionalProperties !== undefined) merged.additionalProperties = node.additionalProperties\n for (const key of ['description', 'title'] as const) {\n if (node[key] !== undefined) merged[key] = node[key]\n }\n return merged\n}\n\n/**\n * Normalize one tool's parameters schema to an object-rooted JSON Schema.\n * A schema that already declares an object root is passed through untouched;\n * a type-less object-shaped one gains the type; a root `$ref` or combinator is\n * resolved/merged; anything else (an array/scalar root, or no schema at all)\n * degrades to a permissive free-form object, because a request the provider\n * refuses helps no one and the tool's own description is still in the prompt.\n */\nfunction toolParametersSchema(parameters: unknown, depth = 0): Record<string, unknown> {\n if (!isRecord(parameters)) return { type: 'object', properties: {}, additionalProperties: true }\n if (parameters.type === 'object') return parameters\n // `[\"object\", \"null\"]` is accepted by JSON Schema but not by the provider's\n // validator, which compares the root `type` against the string \"object\".\n if (Array.isArray(parameters.type) && parameters.type.includes('object')) {\n return { ...parameters, type: 'object' }\n }\n\n if (parameters.type === undefined || parameters.type === null) {\n if (typeof parameters.$ref === 'string' && depth < SCHEMA_NORMALIZE_MAX_DEPTH) {\n const target = resolveLocalRef(parameters, parameters.$ref)\n if (target !== undefined) {\n const { $ref: _ref, ...rest } = parameters\n return toolParametersSchema({ ...target, ...rest }, depth + 1)\n }\n }\n if (isObjectShaped(parameters)) return { ...parameters, type: 'object' }\n const merged = mergeCombinatorBranches(parameters, depth)\n if (merged !== undefined) return merged\n // A root `$ref` this plugin cannot resolve still gets the declared type:\n // that is what the provider validates for, and an object is what every\n // schema generator emits one for.\n if (typeof parameters.$ref === 'string') return { ...parameters, type: 'object' }\n }\n\n return { type: 'object', properties: {}, additionalProperties: true }\n}\n\nexport function projectSlugFromPath(pathName: string): string {\n const slug = pathName\n .toLowerCase()\n .replace(/^[a-z]:/i, '')\n .replace(/[^a-z0-9]+/g, '-')\n // Trim leading/trailing separators. This must stay linear: the classic\n // `/^-+|-+$/` form is ambiguous — on `a<200k dashes>b` the unanchored\n // `-+$` retries every start position, giving O(n^2) matching (CodeQL\n // js/polynomial-redos). The negative lookbehind `(?<!-)` restricts `-+$`\n // to the first dash of the trailing run, so only one start position is\n // tried. Verified empirically: ~14.5s -> ~0ms on a 200k-dash input.\n .replace(/^-+|(?<!-)-+$/g, '')\n return slug || 'project'\n}\n\nfunction parseStreamEventLine(line: string): unknown | undefined {\n let trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(':') || trimmed.startsWith('event:')) return undefined\n if (trimmed.startsWith('data:')) trimmed = trimmed.slice(5).trim()\n if (!trimmed || trimmed === '[DONE]') return undefined\n try {\n return JSON.parse(trimmed) as unknown\n } catch {\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential fallback from the official Command Code CLI auth file. Used as\n// the last fallback by the plugin entry, so a user who already logged in with\n// `command-code login` can reuse that credential. Only the official CLI's own\n// file is read — pi/OMP auth files are intentionally not scanned, so their\n// credentials and formats cannot surprise this adapter.\n// ---------------------------------------------------------------------------\n\n/** Extract the key from the CLI's nested credential records (`command-code`). */\nfunction apiKeyFromCredentialRecord(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined\n const type = stringValue(value.type)\n if (type === 'api') return stringValue(value.key)\n if (type === 'oauth') return stringValue(value.access)\n return stringValue(value.key) ?? stringValue(value.access)\n}\n\n/** Read a usable Command Code credential from the official CLI auth file. */\nexport function resolveAuthFileApiKey(): string | undefined {\n const authPath = join(homedir(), '.commandcode', 'auth.json')\n try {\n if (!existsSync(authPath)) return undefined\n const parsed: unknown = JSON.parse(readFileSync(authPath, 'utf-8'))\n if (!isRecord(parsed)) return undefined\n const direct = stringValue(parsed.apiKey) ?? stringValue(parsed.commandcode)\n if (direct) return direct\n const nested =\n apiKeyFromCredentialRecord(parsed.commandcode) ??\n apiKeyFromCredentialRecord(parsed['command-code'])\n return nested\n } catch {\n // Ignore malformed or unreadable auth file.\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog discovery with on-disk cache fallback (ported from models.ts)\n// ---------------------------------------------------------------------------\n\ninterface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n}\n\nfunction parseCatalogResponse(value: unknown): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) {\n throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n }\n const models: CommandCodeModel[] = []\n for (const entry of value.data) {\n if (!isRecord(entry)) continue\n const id = stringValue(entry.id)\n const name = stringValue(entry.name)\n const contextLength = numberValue(entry.context_length)\n if (!id || !name || !contextLength || contextLength <= 0) continue\n models.push({\n id,\n name,\n contextWindow: contextLength,\n maxTokens: Math.min(contextLength, DEFAULT_MAX_OUTPUT_TOKENS),\n })\n }\n if (models.length === 0) {\n throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n }\n return models\n}\n\nasync function readModelsCache(cachePath: string): Promise<CommandCodeModel[]> {\n const parsed: unknown = JSON.parse(await readFile(cachePath, 'utf-8'))\n if (!isRecord(parsed) || parsed.version !== MODEL_CACHE_VERSION || !Array.isArray(parsed.models)) {\n throw new Error(`Invalid model cache at ${cachePath}`)\n }\n return parsed.models as CommandCodeModel[]\n}\n\nasync function writeModelsCache(cachePath: string, models: CommandCodeModel[]): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true })\n const tmp = `${cachePath}.${process.pid}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, models }, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600,\n })\n await rename(tmp, cachePath)\n } finally {\n await rm(tmp, { force: true }).catch(() => undefined)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Message conversion: harness Message[] -> Command Code wire messages.\n// Both transports replay historical reasoning. The CLI transport carries it as\n// a `reasoning` block inside the assistant message (the shape the official\n// CLI's `toWireMessages` emits), the Provider API transport as the\n// `reasoning_content` field, because DeepSeek's thinking-mode contract\n// requires the previous chain of thought to be passed back whenever tool calls\n// are in play (issue #34). Only tool calls with a paired tool result are\n// replayed on both transports.\n// ---------------------------------------------------------------------------\n\n/**\n * Whether an inbound message is a tool RESULT — a `user`-role message the\n * producer tagged with `source: { kind: 'tool' }`.\n *\n * The tag is read defensively because it is PRODUCER-supplied and nothing\n * validates it: dsh-llm's `Message` type declares `source` required, but the\n * runtime never checks it and every adapter shipped before this one ignored the\n * field outright (`dsh-llm-deepseek` never reads it). A third-party plugin that\n * assembles its own history can therefore omit it and run correctly everywhere\n * else — dsh-mneme's memory pipeline did — which made this adapter, the first\n * to actually read the field, the first to crash on such a message with\n * `TypeError: Cannot read properties of undefined (reading 'kind')` in the\n * serialization phase, 0–8 ms in, before any request left the machine and with\n * nothing in the error naming the message or the producer (issue #47).\n *\n * Two rules keep an untagged message from costing the turn:\n *\n * - A PRESENT tag is authoritative. `kind: 'user'`, `'model'`, `'plugin'` or\n * any producer-added kind means \"not a tool result\", whatever the content\n * looks like — the tag answers *who produced this*.\n * - An ABSENT tag falls back to the content shape. A `user` message whose\n * first block is a `tool-result` is a tool result by the harness's own\n * definition (`ToolResultMessage` is exactly that shape with a\n * `ToolMessageSource`), and the fallback is not cosmetic: `pairedToolCalls()`\n * counts a `tool-result` block from ANY message, so classifying such a\n * message as a plain user message would drop it at emission while its call\n * still counted as paired — leaving the assistant's tool call unanswered on\n * the wire, which the gateway rejects outright. FIRST block, not \"any block\":\n * the tool-result branch reads `content[0]` and skips anything else, so\n * claiming a mixed message as a tool result would discard its other blocks\n * instead of sending them.\n */\nfunction isToolResultMessage(message: Message): boolean {\n if (message.role !== 'user') return false\n const kind: string | undefined = message.source?.kind\n if (kind !== undefined) return kind === 'tool'\n return message.content?.[0]?.type === 'tool-result'\n}\n\n/**\n * Collect the tool calls that have a paired tool result, plus each call's\n * name. The name map feeds the `toolName` of replayed tool results: some\n * backends (e.g. Google Gemini `functionResponse`) reject a result whose\n * function name is empty, so the real name must round-trip (the official\n * CLI does the same via its `tool_use_id -> toolName` map).\n */\nfunction pairedToolCalls(messages: readonly Message[]): {\n ids: Set<string>\n names: Map<string, string>\n} {\n const callIds = new Set<string>()\n const names = new Map<string, string>()\n const resultIds = new Set<string>()\n for (const message of messages) {\n for (const block of message.content) {\n if (message.role === 'assistant' && block.type === 'tool-call') {\n callIds.add(block.id)\n names.set(block.id, block.name)\n }\n if (block.type === 'tool-result') resultIds.add(block.toolCallId)\n }\n }\n return { ids: new Set([...callIds].filter((id) => resultIds.has(id))), names }\n}\n\n/**\n * The Command Code gateway rejects tool call ids longer than 64 characters\n * (`input[N].call_id` must be `<= 64`, issue #23). Cross-provider histories\n * can carry longer ids — e.g. switching to Command Code mid-session after\n * another provider issued the call — so overlong paired ids are remapped to\n * short per-request aliases. Correlation only needs to hold within one\n * request (each call travels with its result in the same body), so a\n * sequential alias is enough: no durable state, no cross-request stability,\n * and the harness log keeps the original ids.\n */\nconst MAX_WIRE_TOOL_CALL_ID_LENGTH = 64\n\n/**\n * Map each paired tool-call id to its wire id: ids within the gateway limit\n * pass through verbatim, overlong ids get a collision-free `cc-<n>` alias.\n * Callers must resolve BOTH the tool-call and its paired tool-result through\n * the returned map so the pair stays correlated.\n */\nfunction wireToolCallIds(paired: ReadonlySet<string>): Map<string, string> {\n const wire = new Map<string, string>()\n const taken = new Set<string>()\n for (const id of paired) {\n if (id.length <= MAX_WIRE_TOOL_CALL_ID_LENGTH) {\n wire.set(id, id)\n taken.add(id)\n }\n }\n let seq = 1\n for (const id of paired) {\n if (wire.has(id)) continue\n let alias = `cc-${seq++}`\n while (taken.has(alias)) alias = `cc-${seq++}`\n wire.set(id, alias)\n taken.add(alias)\n }\n return wire\n}\n\nfunction blockText(block: ContentBlock): string {\n return block.type === 'text' || block.type === 'reasoning' ? block.text : ''\n}\n\n/**\n * One paired tool result as the wire needs it: its text and the images the\n * tool returned. Neither wire transport can carry an image inside a tool\n * result (`/provider/v1/chat/completions` forbids non-text `role: 'tool'`\n * content, and the CLI transport's own `tool-result` output is text-only), so\n * those images travel in a user message emitted right after the tool message —\n * the same shape `@deepseek-ai/dsh-llm-deepseek` uses (issue #30).\n */\ninterface ToolResultMedia {\n /** Visible result text; `''` when the result carried images but no text. */\n text: string\n /** Nested image references, in block order, deduplicated by attachment id. */\n images: ImageAttachmentRef[]\n}\n\n/**\n * Collect text and nested images of one tool result. The harness `read_image`\n * tool returns both, so dropping the image half is what made a tool-read image\n * invisible to a Vision model (issue #30). Deduplication keeps a result that\n * repeats one attachment from paying for the same pixels twice.\n */\nfunction toolResultMedia(block: Extract<ContentBlock, { type: 'tool-result' }>): ToolResultMedia {\n const chunks: string[] = []\n const images: ImageAttachmentRef[] = []\n const seen = new Set<string>()\n const walk = (blocks: readonly ContentBlock[]): void => {\n for (const nested of blocks) {\n if (nested.type === 'text' || nested.type === 'reasoning') {\n if (nested.text) chunks.push(nested.text)\n continue\n }\n if (nested.type === 'image') {\n if (!seen.has(nested.attachment.attachmentId)) {\n seen.add(nested.attachment.attachmentId)\n images.push(nested.attachment)\n }\n continue\n }\n if (nested.type === 'tool-result') walk(nested.content)\n }\n }\n walk(block.content)\n return { text: chunks.join('\\n'), images }\n}\n\n/**\n * Result text for the wire's `role: 'tool'` message. A tool that returned only\n * an image (and possibly a nested image-only tool result) has no text at all,\n * and neither transport accepts an empty tool content string, so it gets a\n * descriptor pointing at the user message that follows with the pixels.\n */\nfunction toolResultTextForWire(media: ToolResultMedia): string {\n return media.text || (media.images.length > 0 ? '(image returned; see the attached image)' : '')\n}\n\n/** Leading line of the user message that carries a tool result's images. */\nconst TOOL_RESULT_IMAGE_TEXT = 'Attached image(s) from tool result'\n\n/**\n * The model-visible note introducing the images carried out of one tool\n * result. Neither transport merges them back into the tool result, so this\n * line is what tells the model the image it is about to see belongs to the\n * tool it just ran rather than to the user; it also leads the part list,\n * because an image-first content array is what some gateways reject.\n *\n * The note names the tool call the image came out of, because a turn's\n * carriers are emitted as a group after the whole tool group (issue #33):\n * position alone would have to carry the association, and every `read_image`\n * result renders the same envelope text, so two parallel calls would produce\n * two identical notes. The id is the WIRE id — the one the model saw on the\n * `tool-call` it issued and on the tool message just above — so an overlong\n * cross-provider id is named by the alias that replaced it, not by the\n * harness-side id the model never saw.\n *\n * Count and pixel dimensions are appended when the tool's own text does not\n * already state them (a result that returns the image and nothing else).\n */\nfunction toolResultImageNote(media: ToolResultMedia, toolCallId: string): string {\n const lead = `${TOOL_RESULT_IMAGE_TEXT} (${toolCallId}):`\n const first = media.images[0]\n if (first === undefined) return lead\n const dimensions = `${first.width}x${first.height} px`\n if (first.width <= 0 || first.height <= 0 || media.text.includes(dimensions)) {\n return lead\n }\n const count = media.images.length > 1 ? `${media.images.length} images, ` : ''\n return `${lead} ${count}${dimensions}`\n}\n\nfunction hasImageContent(message: Message): boolean {\n const check = (blocks: readonly ContentBlock[]): boolean =>\n blocks.some(\n (b) => b.type === 'image' || (b.type === 'tool-result' && check(b.content)),\n )\n return check(message.content)\n}\n\n// ---------------------------------------------------------------------------\n// Request image budget (issue #37)\n//\n// Both transports inline EVERY historical image as base64, so a long session\n// — a vision self-check loop reading back dozens of screenshots — keeps\n// growing the body until it crosses the gateway's request cap (measured at\n// ~50.17 MB, undocumented). From that point on every request on this route\n// fails with HTTP 413 for the rest of the session, because history is never\n// reclaimed, even though the same conversation works on another provider.\n//\n// The budget, the two rungs, and the byte accounting below are unchanged. What\n// changed is WHO performs the eviction, because the harness moved it from the\n// adapter to the session surface (issue #43):\n//\n// ≤ 0.1.5 — the adapter projects its own history with\n// `offloadRequestImagesWithPolicy`: the oldest images beyond the\n// budget become placeholder text for THIS request only. The\n// harness never learns that they were omitted.\n// ≥ 0.1.6 — the offload set is a DURABLE surface fact. The adapter renders\n// the surface's `offloaded` marks with `projectOffloadedImages`,\n// and when the history still exceeds the budget it does NOT evict:\n// it fails with `IMAGE_OFFLOAD_REQUIRED` + `offloadImages`, which\n// the default `dsh-compaction-image-offload` plugin turns into one\n// `image/offload` session event and a retry. Every later request on\n// the session then carries the same placeholder text, across\n// restore and fork, and the token meter stops counting the evicted\n// images as context.\n//\n// Both halves are reached through the `dshLlm` namespace and picked at runtime,\n// so one build serves both engine generations. The budget is accounted in the\n// encoded form, because it is the base64 the wire actually carries that has to\n// fit. Nothing anywhere may statically import either generation's helper names.\n// ---------------------------------------------------------------------------\n\n/**\n * Primary image budget for one request body. 32 MiB of base64 images leaves a\n * wide margin under the measured ~50 MB cap for text, tool schemas, and JSON\n * overhead, and the 16 MiB byte quantum means one eviction frees a real block\n * of the budget instead of one image per request.\n */\nconst REQUEST_IMAGE_MAX_BASE64_BYTES = 32 * 1024 * 1024\n/** Primary image-count budget; a long screenshot loop stays well under it. */\nconst REQUEST_IMAGE_MAX_COUNT = 60\n/** Byte step one eviction removes; keeps the removed prefix stable per request. */\nconst REQUEST_IMAGE_BYTE_QUANTUM = 16 * 1024 * 1024\n/** Count step one eviction removes, so the prefix does not creep per request. */\nconst REQUEST_IMAGE_COUNT_QUANTUM = 30\n\n/**\n * The retry rung, used only after the gateway actually answered 413. The cap\n * covers text and tool bytes too, so it cannot be budgeted exactly from here;\n * this rung is aggressive on purpose — the alternative to a smaller request is\n * a session that cannot continue at all.\n */\nconst REQUEST_IMAGE_RETRY_MAX_BASE64_BYTES = 8 * 1024 * 1024\nconst REQUEST_IMAGE_RETRY_MAX_COUNT = 12\nconst REQUEST_IMAGE_RETRY_BYTE_QUANTUM = 8 * 1024 * 1024\nconst REQUEST_IMAGE_RETRY_COUNT_QUANTUM = 12\n\n/** One rung of the image budget ladder: what a request may keep, and in what steps. */\ninterface RequestImageBudget {\n maxBytes: number\n maxImages: number\n byteQuantum: number\n countQuantum: number\n}\n\n/** The budget ladder: the primary rung first, the 413 eviction rung second. */\nconst REQUEST_IMAGE_BUDGETS: readonly RequestImageBudget[] = [\n {\n maxBytes: REQUEST_IMAGE_MAX_BASE64_BYTES,\n maxImages: REQUEST_IMAGE_MAX_COUNT,\n byteQuantum: REQUEST_IMAGE_BYTE_QUANTUM,\n countQuantum: REQUEST_IMAGE_COUNT_QUANTUM,\n },\n {\n maxBytes: REQUEST_IMAGE_RETRY_MAX_BASE64_BYTES,\n maxImages: REQUEST_IMAGE_RETRY_MAX_COUNT,\n byteQuantum: REQUEST_IMAGE_RETRY_BYTE_QUANTUM,\n countQuantum: REQUEST_IMAGE_RETRY_COUNT_QUANTUM,\n },\n]\n\n/**\n * Project request history under one image budget (≤0.1.5 engines only): the\n * oldest images past it become placeholder text in place, the newest keep their\n * bytes, and a history already inside the budget is returned as the SAME array\n * — the caller uses that identity to tell \"nothing evicted\" from \"evicted\".\n *\n * Nested tool-result images ride the same core walk, which is exactly right\n * for this adapter: an evicted `read_image` result surfaces its placeholder as\n * the tool message's own text, so no carrier user message is emitted for it.\n */\nfunction projectRequestImages(\n messages: readonly Message[],\n budget: RequestImageBudget,\n policy: CoreImagePolicy,\n): readonly Message[] {\n const offload = policy.offloadRequestImagesWithPolicy\n // Unreachable while `surfaceImagePolicy` gates this branch; kept so a future\n // engine that drops BOTH shapes surfaces as \"no budget\" rather than a\n // TypeError from calling undefined.\n if (typeof offload !== 'function') return messages\n return offload(messages, {\n representation: 'base64',\n maxBytes: budget.maxBytes,\n maxImages: budget.maxImages,\n byteQuantum: budget.byteQuantum,\n countQuantum: budget.countQuantum,\n // No execution-world path is resolvable from the adapter (it holds no\n // filesystem provider), so the placeholder carries attachment identity and\n // the re-attach advice, which is what the core helper emits for that case.\n placeholder: (ref: ImageAttachmentRef) => offloadedImageText(ref),\n })\n}\n\n/**\n * The request options one budget produced: the caller's own object when the\n * history was already inside the budget, else a copy carrying the projection.\n * The next rung of the ladder is applied to the CURRENT projection, never to\n * the raw history — otherwise a retry could reintroduce images the first rung\n * had already evicted.\n */\nfunction withImageBudget(\n options: GenerateOptions,\n budget: RequestImageBudget,\n policy: CoreImagePolicy,\n): GenerateOptions {\n const projected = projectRequestImages(options.messages, budget, policy)\n return projected === options.messages ? options : { ...options, messages: [...projected] }\n}\n\n// ---------------------------------------------------------------------------\n// The ≥0.1.6 durable-offload contract\n// ---------------------------------------------------------------------------\n\n/**\n * Stable provider-neutral code for \"a request still carries more images than\n * this route will send; offload N of them and retry\". Declared locally rather\n * than imported: the constant does not exist on the 0.1.2–0.1.5 peers this\n * plugin still supports, and importing it statically is the link-time failure\n * described above the budget constants.\n */\nconst IMAGE_OFFLOAD_REQUIRED_CODE = 'IMAGE_OFFLOAD_REQUIRED'\n\n/** One occurrence's exact request-version byte length, as the core counter wants it. */\ntype ImageVersionBytes = (block: { attachment: ImageAttachmentRef }) => number\n\n/**\n * The installed engine's request-image policy, whichever generation it is.\n *\n * Every member is optional because the two generations never coexist: a\n * ≤0.1.5 engine has only `offloadRequestImagesWithPolicy`, a ≥0.1.6 engine has\n * only the other two. `CORE_IMAGE_POLICY` is the namespace object viewed\n * through this shape, and `surfaceImagePolicy()` is the ONE place that decides\n * which contract this process speaks.\n */\nexport interface CoreImagePolicy {\n /** ≤0.1.5: project history under a byte/count budget, adapter-owned and transient. */\n offloadRequestImagesWithPolicy?: (\n messages: readonly Message[],\n policy: Record<string, unknown>,\n ) => readonly Message[]\n /** ≥0.1.6: render the surface's durable offload marks as placeholder text. */\n projectOffloadedImages?: (\n messages: readonly Message[],\n placeholder: (ref: ImageAttachmentRef) => string,\n ) => readonly Message[]\n /** ≥0.1.6: how many more leading retained occurrences must be offloaded. */\n requiredImageOffload?: (\n messages: readonly Message[],\n budget: Record<string, unknown>,\n versionBytes: ImageVersionBytes,\n ) => number\n}\n\n/** The installed engine's image policy; see {@link CoreImagePolicy}. */\nconst CORE_IMAGE_POLICY = dshLlm as unknown as CoreImagePolicy\n\n/** The ≥0.1.6 half, once both members are known to be functions. */\ninterface SurfaceImagePolicy {\n projectOffloadedImages: NonNullable<CoreImagePolicy['projectOffloadedImages']>\n requiredImageOffload: NonNullable<CoreImagePolicy['requiredImageOffload']>\n}\n\n/**\n * The durable-offload contract this engine speaks, or undefined on ≤0.1.5.\n *\n * Both members are required together: a half-populated engine would either\n * lose the surface's marks (re-sending evicted images as pixels) or lose the\n * count (silently sending an over-budget body), and neither is worth a partial\n * opt-in. Absent, the adapter keeps its own transient projection instead.\n */\nexport function surfaceImagePolicy(api: CoreImagePolicy = CORE_IMAGE_POLICY): SurfaceImagePolicy | undefined {\n return typeof api.projectOffloadedImages === 'function' && typeof api.requiredImageOffload === 'function'\n ? { projectOffloadedImages: api.projectOffloadedImages, requiredImageOffload: api.requiredImageOffload }\n : undefined\n}\n\n/**\n * The failure a route raises instead of evicting on its own (≥0.1.6). The\n * count is the ONE thing the harness needs: `dsh-compaction-image-offload`\n * records it as an `image/offload` event, marks that many oldest retained\n * occurrences, and retries the step.\n *\n * Deliberately outside `providerRetryPolicy()`'s whitelist: a byte-identical\n * resend cannot succeed, so the retry belongs to the surface mutation, not to\n * dsh-llm-retry. On a profile that does not mount that plugin the failure is\n * terminal — every shipped profile reaches it through dsh-base.\n */\nfunction imageOffloadRequired(missing: number): LlmError {\n const options: LlmErrorOptions & { offloadImages: number } = { offloadImages: missing }\n return new LlmError(\n `commandcode request images exceed the route budget; ${missing} more oldest occurrence(s) must be offloaded.`,\n IMAGE_OFFLOAD_REQUIRED_CODE,\n options,\n )\n}\n\n/** The budget in the shape the core counter takes (representation + the rung). */\nfunction coreBudget(budget: RequestImageBudget): Record<string, unknown> {\n return { representation: 'base64', ...budget }\n}\n\n/**\n * Exact request-version bytes of one retained occurrence. The declared\n * normalized size IS what this adapter inlines (the body is built from\n * `attachments.readImage`, base64-encoded), so the accounting matches the wire\n * byte for byte, and the core helper expands it for `base64` on its own.\n */\nconst imageVersionBytes: ImageVersionBytes = (block) => block.attachment.bytes\n\n/**\n * ≥0.1.6 request options: the surface's durable marks become placeholder text,\n * and an over-budget history FAILS with the count to offload instead of being\n * evicted here. Throws rather than returning, so no caller can accidentally\n * send a body this route already knows is too large.\n */\nfunction withSurfaceOffload(\n options: GenerateOptions,\n policy: SurfaceImagePolicy,\n budget: RequestImageBudget,\n): GenerateOptions {\n const marked = policy.projectOffloadedImages(options.messages, (ref) => offloadedImageText(ref))\n const messages = marked === options.messages ? options.messages : [...marked]\n const missing = policy.requiredImageOffload(messages, coreBudget(budget), imageVersionBytes)\n if (missing > 0) throw imageOffloadRequired(missing)\n return messages === options.messages ? options : { ...options, messages }\n}\n\n/**\n * One image's bytes for the wire: the attachment service's REQUEST VERSION when\n * it can produce one, else the normalized original.\n *\n * `readImage()` answers the stored original, which is what admission accepted —\n * not what a provider request should carry. `readImageRequest()` re-encodes to\n * the route target in `./image-request.ts` and caches the result under it, so\n * the same attachment costs one encode per target instead of one per occurrence,\n * and the base64 the wire expands is bounded (both the pixel budget and, more to\n * the point here, the encoded bytes). The fallback is for a backend that does\n * not implement the abstract method; every engine this plugin declares support\n * for does.\n */\nasync function readRequestImage(\n attachments: AttachmentStore,\n ref: ImageAttachmentRef,\n): Promise<Uint8Array> {\n if (typeof attachments.readImageRequest === 'function') {\n return (await attachments.readImageRequest(ref, requestImageTarget(ref))).data\n }\n return (await attachments.readImage(ref)).data\n}\n\n/**\n * One occurrence as the token meter hands it over, in either generation's\n * shape: a bare reference (≤0.1.5) or an image block that may also be marked\n * `offloaded` (≥0.1.6).\n */\ntype PricedOccurrence = ImageAttachmentRef | ImageBlock\n\n/**\n * Price one request occurrence.\n *\n * Two cases cost no vision tokens at all, and both are priced as their\n * model-visible TEXT so the caller's estimator can charge that instead: a model\n * that accepts text only (the harness projects those images to placeholder text\n * before the request), and an occurrence the session surface has already\n * offloaded (≥0.1.6 renders the same placeholder text in every later request).\n * A retained occurrence on this route contributes no text at all — the pixels\n * are inlined — so its price is the family's visual-token count and nothing else.\n */\nfunction priceRequestImage(\n occurrence: PricedOccurrence,\n model: string,\n imageCapable: boolean,\n): LlmImageRequestPrice {\n const block = occurrence as { attachment?: ImageAttachmentRef; offloaded?: true }\n const ref = block.attachment ?? (occurrence as ImageAttachmentRef)\n if (!imageCapable) return { visualTokens: 0, text: textOnlyImageText(ref) }\n if (block.offloaded === true) return { visualTokens: 0, text: offloadedImageText(ref) }\n const target = requestImageTarget(ref)\n return { visualTokens: commandCodeImageTokens(model, target.width, target.height), text: '' }\n}\n\n/**\n * Convert one image reference to the Command Code wire format, as the official\n * CLI does: `{ type: 'image', source: { type: 'base64', media_type, data } }`.\n * Bytes come from the durable attachment service; the media type is the one\n * verified at save time.\n */\nasync function imageToCommandCode(\n ref: ImageAttachmentRef,\n readImage: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<{ type: 'image'; source: { type: 'base64'; media_type: string; data: string } }> {\n const data = await readImage(ref)\n return {\n type: 'image',\n source: {\n type: 'base64',\n media_type: ref.mediaType,\n data: Buffer.from(data).toString('base64'),\n },\n }\n}\n\nasync function messagesToCC(\n messages: readonly Message[],\n readImage?: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired, names: toolNames } = pairedToolCalls(messages)\n // Remap cross-provider ids the gateway would reject (issue #23); the\n // result side resolves through the same map so each pair stays correlated.\n const wireIds = wireToolCallIds(paired)\n\n // Tool-returned images ride as user messages after their tool result. The\n // harness can emit several tool calls in one assistant turn, and the\n // gateway expects an assistant's tool blocks to be answered consecutively:\n // a user message interleaved between tool results breaks the pairing and\n // the request is rejected. So image carriers are buffered and flushed only\n // once the whole tool group (or the next non-tool message) has been emitted.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n\n for (const message of messages) {\n if (message.role === 'system') continue // folded into params.system by the caller\n\n if (message.role === 'user' && !isToolResultMessage(message)) {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n // The caller (stream) has already gated image input on model\n // capability and attachment-service availability, so reaching this\n // branch with no resolver is an internal contract violation.\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n parts.push(await imageToCommandCode(block.attachment, readImage))\n }\n }\n // A user message that converted to nothing carries no information, and\n // an empty content array is a needless gateway-compat risk, so it is\n // dropped — the same rule the Provider API converter applies below.\n // (`dsh-llm-deepseek` instead pushes `content: ''`; skipping is the\n // safer half of that divergence to keep.) The flush above has already\n // run, so a pending image carrier is never dropped with it.\n if (parts.length === 0) continue\n out.push({ role: 'user', content: parts })\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n } else if (block.type === 'reasoning') {\n // Replay the thinking block, exactly as the official CLI's\n // `toWireMessages` does (command-code@1.54.0: a `thinking` block\n // becomes `{ type: 'reasoning', text }`). This is not optional\n // politeness: the gateway rebuilds the provider request from these\n // blocks, and a DeepSeek thinking-mode assistant turn whose tool\n // calls arrive without its reasoning is rejected with \"The\n // `reasoning_content` in the thinking mode must be passed back to\n // the API\" — which failed every tool-loop turn (issue #34).\n parts.push({ type: 'reasoning', text: block.text })\n } else if (block.type === 'tool-call' && paired.has(block.id)) {\n parts.push({\n type: 'tool-call',\n toolCallId: wireIds.get(block.id) ?? block.id,\n toolName: block.name,\n input: recordOrEmpty(block.arguments),\n })\n }\n }\n if (parts.length > 0) out.push({ role: 'assistant', content: parts })\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (isToolResultMessage(message)) {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n const media = toolResultMedia(block)\n // Resolved once: the tool message and the carrier note below must name\n // the same call, or the model cannot tie an image back to its result.\n const wireToolCallId = wireIds.get(block.toolCallId) ?? block.toolCallId\n out.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: wireToolCallId,\n // `paired` guarantees a call with this id exists, so the map\n // always hits; `|| 'unknown'` also guards an empty call name\n // (matches the official CLI's `?? \"unknown\"` fallback).\n toolName: toolNames.get(block.toolCallId) || 'unknown',\n output: block.isError\n ? { type: 'error-text', value: toolResultTextForWire(media) }\n : { type: 'text', value: toolResultTextForWire(media) },\n },\n ],\n })\n // Images a tool returned (e.g. `read_image`) cannot ride inside the\n // tool result on this wire, so they follow it as a user message —\n // otherwise a Vision model receives the metadata text and no pixels.\n if (media.images.length > 0) {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireToolCallId) }]\n for (const attachment of media.images) {\n carried.push(await imageToCommandCode(attachment, readImage))\n }\n pendingImages.push({ role: 'user', content: carried })\n }\n }\n }\n flushPendingImages()\n return out\n}\n\n/**\n * Convert one image reference to the OpenAI Chat Completions wire format:\n * `{ type: 'image_url', image_url: { url: 'data:...;base64,...' } }`.\n */\nasync function imageToOpenAI(\n ref: ImageAttachmentRef,\n readImage: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<{ type: 'image_url'; image_url: { url: string } }> {\n const data = await readImage(ref)\n return {\n type: 'image_url',\n image_url: {\n url: `data:${ref.mediaType};base64,${Buffer.from(data).toString('base64')}`,\n },\n }\n}\n\n/**\n * Convert harness messages to the OpenAI Chat Completions request shape.\n *\n * Unlike the Command Code CLI transport, this transport is the documented\n * Provider API surface. DeepSeek's thinking-mode contract requires historical\n * `reasoning_content` to be passed back whenever tools are in play, so this\n * converter intentionally DOES replay reasoning blocks as `reasoning_content`\n * on assistant messages. Only tool calls with a paired tool result are\n * replayed (same policy as the CLI path).\n */\nasync function messagesToOpenAI(\n messages: readonly Message[],\n readImage?: (ref: ImageAttachmentRef) => Promise<Uint8Array>,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired } = pairedToolCalls(messages)\n // Same overlong-id remap as the CLI transport (issue #23): OpenAI\n // `tool_call_id` fields accept longer values, but the remap keeps both\n // transports consistent and correlation only needs to hold per request.\n const wireIds = wireToolCallIds(paired)\n\n // Tool-returned images ride as user messages after their tool result. The\n // harness can emit several tool calls in one assistant turn, and the\n // gateway expects an assistant's tool blocks to be answered consecutively:\n // a user message interleaved between tool results breaks the pairing and\n // the request is rejected. So image carriers are buffered and flushed only\n // once the whole tool group (or the next non-tool message) has been emitted.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n\n for (const message of messages) {\n // System messages are folded into the single top-level system message by\n // the caller, matching the existing adapter's conversation folding.\n if (message.role === 'system') continue\n\n if (message.role === 'user' && !isToolResultMessage(message)) {\n flushPendingImages()\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n parts.push(await imageToOpenAI(block.attachment, readImage))\n }\n }\n // Same rule as the CLI converter: a converted-to-nothing user message is\n // dropped rather than sent as an empty content array. The flush above\n // already ran, so a pending image carrier survives this skip.\n if (parts.length === 0) continue\n const hasImage = parts.some((part) => (part as { type?: string }).type === 'image_url')\n if (!hasImage && parts.length === 1) {\n out.push({ role: 'user', content: (parts[0] as { text: string }).text })\n } else {\n // Preserve separate text/image parts rather than silently joining\n // text blocks together.\n out.push({ role: 'user', content: parts })\n }\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const text = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\n .map((block) => block.text)\n .join('')\n const reasoning = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'reasoning' }> => block.type === 'reasoning')\n .map((block) => block.text)\n .join('')\n const toolCalls = message.content\n .filter((block): block is Extract<ContentBlock, { type: 'tool-call' }> => block.type === 'tool-call' && paired.has(block.id))\n .map((block) => ({\n id: wireIds.get(block.id) ?? block.id,\n type: 'function' as const,\n function: {\n name: block.name,\n arguments: block.arguments,\n },\n }))\n\n if (text === '' && reasoning === '' && toolCalls.length === 0) continue\n const assistant: Record<string, unknown> = {\n role: 'assistant',\n content: text === '' ? null : text,\n }\n // Chat Completions / DeepSeek thinking mode: replay historical reasoning\n // so tool-calling loops can continue from the previous chain of thought.\n if (reasoning !== '') assistant.reasoning_content = reasoning\n if (toolCalls.length > 0) assistant.tool_calls = toolCalls\n out.push(assistant)\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (isToolResultMessage(message)) {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n const media = toolResultMedia(block)\n // Resolved once: the tool message and the carrier note below must name\n // the same call, or the model cannot tie an image back to its result.\n const wireToolCallId = wireIds.get(block.toolCallId) ?? block.toolCallId\n out.push({\n role: 'tool',\n tool_call_id: wireToolCallId,\n content: toolResultTextForWire(media),\n })\n // Chat Completions allows no image part under `role: 'tool'`, so a\n // tool-returned image (e.g. `read_image`) follows as a user message.\n if (media.images.length > 0) {\n if (!readImage) {\n throw new LlmError(\n 'Image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireToolCallId) }]\n for (const attachment of media.images) {\n carried.push(await imageToOpenAI(attachment, readImage))\n }\n pendingImages.push({ role: 'user', content: carried })\n }\n }\n }\n flushPendingImages()\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Adapter\n// ---------------------------------------------------------------------------\n/** Connection facts resolved fresh per request by the plugin entry. */\nexport interface CommandCodeConnectionOptions {\n /** API base; the Provider API lives under it (`/alpha/generate`, `/provider/v1/chat/completions`, `/provider/v1/models`). */\n apiBase: string\n /** Working directory reported to the API (project slug, config block). */\n workingDir: string\n /** Model catalog cache path. */\n modelsCachePath: string\n /**\n * Milliseconds to wait for generate response headers / first byte (default 60s).\n * Must not bound the subsequent body stream — long generations are gated by\n * {@link streamIdleTimeoutMs} and the caller AbortSignal instead.\n */\n requestTimeoutMs: number\n /** Milliseconds a stream may stall before it is treated as a dead connection (default 300s). */\n streamIdleTimeoutMs: number\n /**\n * Whether the picker hides models above the account's subscription tier\n * (default true). The filter fails open: unknown plan, billing-endpoint\n * failure, a positive on-demand credit balance, or an unmapped model all\n * keep the full catalog visible. Set false to always list every model.\n */\n filterModelsByPlan?: boolean\n /**\n * Visible-model allowlist: catalog model ids shown in pickers. Empty or\n * unset means \"show everything\"; applies after the subscription-tier filter.\n * The settings page persists it; the catalog endpoint serves the full\n * catalog regardless so the page can always offer every model.\n */\n visibleModels?: string[] | undefined\n /**\n * Per-model visibility overrides, keyed by catalog id. Written by the\n * terminal settings page, whose checkbox list gives every model its own\n * boolean field: a field writes one value at one path, so membership in\n * {@link visibleModels} cannot be expressed from there, while a flag can.\n * An id present here decides that model on its own (true = listed, false =\n * hidden); an id absent here follows {@link visibleModels} exactly as it did\n * before, so composition configs and the web page are unaffected.\n */\n modelVisibility?: Readonly<Record<string, boolean>> | undefined\n /**\n * Optional protocol hint. `'auto'` (default) uses billing/cache plus\n * Provider API fallback; `'cli'` forces `/alpha/generate`; `'openai'`\n * prefers `/provider/v1/chat/completions` but still falls back to the CLI\n * transport on `upgrade_required` (Go-plan keys have no Provider API\n * access — failing outright would strand them). This is a\n * connection-level test/operator seam and is intentionally not part of\n * the plugin's user settings schema.\n */\n protocol?: 'auto' | CommandCodeProtocol\n}\n\n/**\n * Resolve the durable attachment service, or undefined when the host does not\n * provide one. Called lazily only when a request actually carries images, so a\n * text-only request never depends on the attachment seam.\n */\nexport type ResolveAttachments = () => AttachmentStore | undefined\n\n/** Everything the adapter needs beyond the request itself. */\nexport interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** Resolve the current connection facts (fresh per request, settings-aware). */\n options: () => C\n /**\n * Resolve a usable API key for the given connection facts and the request's\n * model id, or throw `MISSING_CREDENTIAL`. The model is optional: hosts\n * without model-aware routing ignore it.\n */\n resolveApiKey: (connection: C, model?: string) => Promise<string>\n /**\n * Multi-account rotation hook: the request sent with `rejectedKey` was\n * refused with 429 (`rate-limit`) or 401 (`invalid-credential`) before\n * any response body streamed. The host marks that key and returns the next\n * account's key to retry with, or `undefined` to surface the failure.\n * Only pre-stream rejections rotate — a mid-stream failure never replays a\n * partially consumed generation against another account.\n */\n rotateApiKey?: (rejectedKey: string, rejection: 'rate-limit' | 'invalid-credential', connection: C, model?: string) => Promise<string | undefined>\n /** HTTP transport override (tests); defaults to the global `fetch`. */\n fetchImpl?: typeof fetch\n /** Resolve the optional durable attachment service for image input (tests); defaults to none. */\n resolveAttachments?: ResolveAttachments\n /**\n * Request-image policy override (tests); defaults to the installed engine's\n * own helpers, whichever generation they belong to. Injecting it is the only\n * way to exercise the ≥0.1.6 durable-offload contract while this checkout\n * still compiles against the 0.1.2 peers.\n */\n imageOffload?: CoreImagePolicy\n}\n\n/** Account identity from `/alpha/whoami`. */\nexport interface CommandCodeAccount {\n id: string\n name: string\n userName: string\n}\n\n/** Usage summary from `/alpha/usage/summary`. */\nexport interface CommandCodeUsage {\n totalCount: number\n totalCost: number\n successRate: number\n completedCount: number\n failedCount: number\n totalTokensIn: number\n totalTokensOut: number\n totalCredits: number\n periodBasis: string\n}\n\n/** Credit/limit state from `/alpha/billing/credits`. */\nexport interface CommandCodeCredits {\n monthlyCredits: number\n purchasedCredits: number\n freeCredits: number\n /**\n * Whether the endpoint actually published a monthly balance. The scalar\n * above defaults to 0 for shape stability, which is a LIE about an omitted\n * field — and a false \"0 left, fully consumed\" on the dashboard. Consumers\n * that render the figure must check this first: an explicit `false` means\n * \"not reported\", not \"nothing left\".\n *\n * Optional on purpose. `undefined` means the flag itself was never recorded —\n * an older Host half, or a frame from before this field existed — and is read\n * as \"assume reported\", which is the behavior that shipped. Only an explicit\n * `false` from a Host that knows the balance was omitted suppresses the\n * figure, so a cross-version pair does not lose a real balance.\n */\n monthlyReported?: boolean\n purchasedReported?: boolean\n freeReported?: boolean\n /**\n * Five-hour rolling window limits, absent when the endpoint reported no such\n * window. Absence is NOT \"a window with no cap\": a reported window with\n * `cap === 0` is uncapped spend, while an absent one was never reported at\n * all, and only the un-reported case must keep a figure off the dashboard.\n */\n fiveHour?: { used: number; cap: number; exceeded: boolean; resetAt: number }\n /** Weekly window limits; absent under the same rule as {@link fiveHour}. */\n weekly?: { used: number; cap: number; exceeded: boolean; resetAt: number }\n}\n\n/** Subscription plan state from `/alpha/billing/subscriptions`. */\nexport interface CommandCodePlan {\n /** Raw subscription plan id (e.g. `individual-pro`); empty when unreported. */\n planId: string\n /** Display name (e.g. `Pro`); falls back to the raw id for unknown plans. */\n name: string\n /** Raw subscription status (`active`, `trialing`, `past_due`, …); empty when unreported. */\n status: string\n /** The plan's monthly credit total per {@link KNOWN_SUBSCRIPTION_PLANS}; null for unknown plans. */\n monthlyCredits: number | null\n /** Billing period end in millis; 0 when the endpoint did not report one. */\n currentPeriodEnd: number\n}\n\n/**\n * Why every account endpoint failed at once (the report then carries no data\n * at all, so the degraded per-endpoint view would hide the root cause behind\n * a generic \"partial data\" note). Undefined for partial failures.\n */\nexport type UsageBlockReason = 'invalid-key' | 'service-unavailable' | 'network'\n\n/** Account endpoints fetched by one `getUsage()` run (see the classification there). */\nconst USAGE_ENDPOINT_COUNT = 4\n\n/** Everything the usage endpoints report, fetched together. */\nexport interface CommandCodeUsageReport {\n account?: CommandCodeAccount\n usage?: CommandCodeUsage\n credits?: CommandCodeCredits\n plan?: CommandCodePlan\n /** Endpoint failures degrade the report instead of failing it. */\n failures: string[]\n /**\n * The single reason every endpoint failed, when they all did: `invalid-key`\n * (every call rejected with 401 — the stored key is wrong or expired),\n * `service-unavailable` (every call answered 5xx), or `network` (no HTTP\n * response at all). Undefined when any endpoint succeeded.\n */\n blocked?: UsageBlockReason\n}\n\n/**\n * Parse one usage/summary payload into the report's usage section.\n * Returns undefined when the endpoint answered nothing usable.\n */\nfunction parseUsageTotals(usage: Record<string, unknown> | undefined): CommandCodeUsage | undefined {\n // Note: `getUsage` always answers `usage` (200 with `{}` parses to zeros)\n // — undefined here means the endpoint failed or answered non-JSON, which\n // the caller already booked into `failures`.\n if (usage === undefined) return undefined\n return {\n totalCount: numberValue(usage.totalCount) ?? 0,\n totalCost: numberValue(usage.totalCost) ?? 0,\n successRate: numberValue(usage.successRate) ?? 0,\n completedCount: numberValue(usage.completedCount) ?? 0,\n failedCount: numberValue(usage.failedCount) ?? 0,\n totalTokensIn: numberValue(usage.totalTokensIn) ?? 0,\n totalTokensOut: numberValue(usage.totalTokensOut) ?? 0,\n totalCredits: numberValue(usage.totalCredits) ?? 0,\n periodBasis: stringValue(usage.periodBasis) ?? 'billing-period',\n }\n}\n\n/** Parse one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one window block into a window limit, or undefined when the endpoint\n * reported no such window.\n *\n * Returning undefined (rather than a zeroed window) is load-bearing: the panel\n * must not draw a quota row for a window the account never reported, and a\n * zeroed window is indistinguishable from a genuinely uncapped one.\n */\nfunction parseWindowLimit(value: unknown): CommandCodeCredits['fiveHour'] {\n const block = isRecord(value) ? value : undefined\n if (block === undefined) return undefined\n return {\n used: numberValue(block.used) ?? 0,\n cap: numberValue(block.cap) ?? 0,\n exceeded: block.exceeded === true,\n resetAt: numberValue(block.resetAt) ?? 0,\n }\n}\n\n/**\n * Parse one billing/credits payload into the report's credits section.\n * Returns undefined when the endpoint answered nothing usable.\n */\nfunction parseCreditLimits(credits: Record<string, unknown> | undefined): CommandCodeCredits | undefined {\n if (credits === undefined) return undefined\n const creditsData = isRecord(credits.credits) ? credits.credits : undefined\n const windowLimits = isRecord(credits.windowLimits) ? credits.windowLimits : undefined\n const fiveHour = windowLimits !== undefined && isRecord(windowLimits.fiveHour) ? windowLimits.fiveHour : undefined\n const weekly = windowLimits !== undefined && isRecord(windowLimits.weekly) ? windowLimits.weekly : undefined\n if (creditsData === undefined && fiveHour === undefined && weekly === undefined) return undefined\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberValue(creditsData?.monthlyCredits) ?? 0,\n purchasedCredits: numberValue(creditsData?.purchasedCredits) ?? 0,\n freeCredits: numberValue(creditsData?.freeCredits) ?? 0,\n // Recorded separately from the scalar: the panel must not report an\n // omitted balance as a consumed one.\n monthlyReported: numberValue(creditsData?.monthlyCredits) !== undefined,\n purchasedReported: numberValue(creditsData?.purchasedCredits) !== undefined,\n freeReported: numberValue(creditsData?.freeCredits) !== undefined,\n }\n // Optional members are only present when reported, never present-but-undefined\n // (`exactOptionalPropertyTypes`), so an absent window cannot be mistaken for a\n // parsed one with zeroed numbers.\n const fiveHourLimit = parseWindowLimit(fiveHour)\n const weeklyLimit = parseWindowLimit(weekly)\n if (fiveHourLimit !== undefined) parsed.fiveHour = fiveHourLimit\n if (weeklyLimit !== undefined) parsed.weekly = weeklyLimit\n return parsed\n}\n\n/**\n * Parse the account identity from whoami plus the plan identity from the\n * subscriptions/credits payloads. Returns the org id for the subscriptions\n * query alongside, so getUsage fetches whoami first and the rest in parallel.\n */\nfunction parseAccountIdentity(whoami: Record<string, unknown> | undefined): {\n account: CommandCodeAccount | undefined\n orgId: string | undefined\n} {\n const whoamiData = whoami !== undefined && isRecord(whoami.user) ? whoami.user : undefined\n const orgData = whoami !== undefined && isRecord(whoami.org) ? whoami.org : undefined\n return {\n account: whoamiData === undefined ? undefined : {\n id: stringValue(whoamiData.id) ?? '',\n name: stringValue(whoamiData.name) ?? '',\n userName: stringValue(whoamiData.userName) ?? '',\n },\n orgId: orgData === undefined ? undefined : stringValue(orgData.id),\n }\n}\n\n/**\n * Classify a TOTAL failure: when every endpoint failed with one class of\n * error, the degraded per-endpoint view would hide the root cause behind\n * a generic \"partial data\" note — name it instead.\n */\nfunction classifyTotalFailure(\n failures: readonly string[],\n failedStatuses: ReadonlyArray<number | undefined>,\n): UsageBlockReason | undefined {\n // Four endpoints are fetched (whoami, usage/summary, billing/credits,\n // billing/subscriptions; the last may carry an orgId query, so the\n // classification counts endpoints, not paths).\n if (failures.length !== USAGE_ENDPOINT_COUNT) return undefined\n const codes = failedStatuses.filter((status): status is number => status !== undefined)\n if (codes.length === USAGE_ENDPOINT_COUNT && codes.every((code) => code === 401)) {\n return 'invalid-key'\n }\n if (codes.length === USAGE_ENDPOINT_COUNT && codes.every((code) => code >= 500)) {\n return 'service-unavailable'\n }\n if (codes.length === 0) return 'network'\n return undefined\n}\n\n/**\n * The shared facts one generate call needs, computed once up front so the\n * body builders, the connect loop, and the stream pump below all read the\n * same snapshot instead of closing over `stream()` locals.\n */\ninterface GenerateCallFacts {\n /** Resolved API key for the first attempt (rotation may replace it). */\n apiKey: string\n /** maxTokens cap for the request model (in-memory catalog, else default). */\n maxTokens: number\n /** Validated reasoning effort, or undefined when unset/unsupported. */\n reasoningEffort: string | undefined\n /** Folded system text (top-level system + system-role messages). */\n systemText: string\n /** Per-call image byte resolver; set only when the request carries images. */\n readImage: ((ref: ImageAttachmentRef) => Promise<Uint8Array>) | undefined\n}\n\n/** Build the legacy CLI (`/alpha/generate`) request body for one call. */\nasync function buildCliBody(\n options: GenerateOptions,\n connection: CommandCodeConnectionOptions,\n facts: Pick<GenerateCallFacts, 'maxTokens' | 'reasoningEffort' | 'systemText' | 'readImage'>,\n): Promise<Record<string, unknown>> {\n return {\n config: {\n workingDir: connection.workingDir,\n date: new Date().toISOString().split('T')[0],\n environment: `${process.platform}-${process.arch}, Node.js ${process.version}`,\n structure: [],\n isGitRepo: false,\n currentBranch: '',\n mainBranch: '',\n gitStatus: '',\n recentCommits: [],\n },\n memory: null,\n taste: null,\n skills: null,\n params: {\n model: options.model,\n messages: await messagesToCC(options.messages, facts.readImage),\n tools: (options.tools ?? []).map((tool) => ({\n type: 'function',\n name: tool.name,\n description: tool.description,\n input_schema: toolParametersSchema(tool.parameters),\n })),\n system: facts.systemText,\n max_tokens: facts.maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(facts.reasoningEffort ? { reasoning_effort: facts.reasoningEffort } : {}),\n },\n threadId: randomUUID(),\n }\n}\n\n/** Build the documented Provider Chat Completions request body for one call. */\nasync function buildOpenAIBody(\n options: GenerateOptions,\n facts: Pick<GenerateCallFacts, 'maxTokens' | 'reasoningEffort' | 'systemText' | 'readImage'>,\n): Promise<Record<string, unknown>> {\n const openAiMessages = [\n ...(facts.systemText ? [{ role: 'system', content: facts.systemText }] : []),\n ...(await messagesToOpenAI(options.messages, facts.readImage)),\n ]\n const openAiTools = (options.tools ?? []).map((tool) => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: toolParametersSchema(tool.parameters),\n },\n }))\n return {\n model: options.model,\n messages: openAiMessages,\n ...(openAiTools.length > 0 ? { tools: openAiTools } : {}),\n max_tokens: facts.maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(facts.reasoningEffort ? { reasoning_effort: facts.reasoningEffort } : {}),\n }\n}\n\n/**\n * One connect attempt's inputs: everything `connectGenerate` needs beyond\n * the per-attempt key and protocol. Passed explicitly (not closed over) so\n * the rotation loop's mutation of `protocol`/`body` stays visible at the\n * call site.\n */\ninterface GenerateConnectDeps {\n options: GenerateOptions\n connection: CommandCodeConnectionOptions\n fetchImpl: typeof fetch\n}\n\n/**\n * One pre-stream connect attempt: POST the body and wait for response\n * headers only (`requestTimeoutMs` must never bound the body stream — see\n * the caller). Returns the live response plus its cleanup, or the rejection\n * facts for the rotation loop to classify. Every failure path cleans up\n * before returning or throwing; on success the caller-abort listener\n * outlives the connect phase (it aborts a stalled body read), so the\n * streaming tail calls cleanup.\n */\nasync function connectGenerate(\n deps: GenerateConnectDeps,\n key: string,\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n): Promise<{ response: Response; cleanup: () => void } | { status: number; errText: string; retryAfterMs?: number }> {\n const { options, connection, fetchImpl } = deps\n const connectAbort = new AbortController()\n let connectTimedOut = false\n const endpoint = protocol === 'cli'\n ? `${connection.apiBase}/alpha/generate`\n : `${connection.apiBase}/provider/v1/chat/completions`\n const connectTimer = setTimeout(() => {\n connectTimedOut = true\n connectAbort.abort(\n new DOMException(\n `Command Code API request to ${endpoint} did not respond within ${connection.requestTimeoutMs}ms`,\n 'TimeoutError',\n ),\n )\n }, connection.requestTimeoutMs)\n const onCallerAbort = () => {\n connectAbort.abort(options.signal?.reason)\n }\n if (options.signal) {\n if (options.signal.aborted) {\n onCallerAbort()\n } else {\n options.signal.addEventListener('abort', onCallerAbort, { once: true })\n }\n }\n const cleanup = () => {\n clearTimeout(connectTimer)\n if (options.signal) {\n options.signal.removeEventListener('abort', onCallerAbort)\n }\n }\n\n let response: Response\n const headers = protocol === 'cli'\n ? {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n 'x-project-slug': projectSlugFromPath(connection.workingDir),\n 'x-taste-learning': 'true',\n 'x-co-flag': 'false',\n ...attributionHeaders(),\n }\n : {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n Accept: 'text/event-stream',\n // Deliberately no x-command-code-version / x-cli-environment:\n // this is the documented OpenAI-format surface, not the CLI\n // transport — do not \"fix\" these in.\n ...attributionHeaders(),\n }\n try {\n response = await fetchImpl(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: connectAbort.signal,\n })\n clearTimeout(connectTimer)\n } catch (error: unknown) {\n cleanup()\n if (options.signal?.aborted) {\n throw error\n }\n if (connectTimedOut || (error instanceof DOMException && error.name === 'TimeoutError')) {\n throw new LlmError(\n `Command Code API request to ${endpoint} did not respond within ${connection.requestTimeoutMs}ms`\n + `: ${errorChain(error)}`\n + `;Command Code API 请求在 ${connection.requestTimeoutMs} 毫秒内未收到响应——通常是网络或代理问题,请检查后重试`,\n 'TIMEOUT',\n { cause: error },\n )\n }\n // fetch wraps every transport failure (DNS, refused connection, TLS,\n // proxy, reset) in a bare `TypeError: fetch failed` whose actionable\n // detail lives on `cause`. Include the full chain so the failure reason\n // shown in the web UI (which renders only the message, not `cause`)\n // names the real root cause instead of a generic wrapper.\n throw new LlmError(\n `Command Code API request to ${endpoint} failed: ${errorChain(error)}`\n + ';Command Code API 请求连接失败——通常是网络或代理问题,请检查网络或代理设置后重试',\n 'TRANSPORT',\n { cause: error },\n )\n }\n\n if (!response.ok) {\n const errText = await response.text().catch(() => '')\n cleanup()\n const retryAfterMs = parseRetryAfterMs(response.headers.get('retry-after'))\n // exactOptionalPropertyTypes: the key must be absent, not undefined.\n return retryAfterMs === undefined\n ? { status: response.status, errText }\n : { status: response.status, errText, retryAfterMs }\n }\n return { response, cleanup }\n}\n\n/**\n * The StreamChunk block-assembly state shared by both transport handlers:\n * at most one text block and one reasoning block are open at a time (same\n * assumption as the pi plugin).\n */\ninterface BlockAssembler {\n nextIndex: number\n textIndex: number\n textContent: string\n reasoningIndex: number\n reasoningContent: string\n sawContent: boolean\n /** Buffered OpenAI tool-call fragments, flushed at finish. */\n openAiToolCalls: Array<{ index: number; id?: string; name: string; arguments: string }>\n}\n\n/** Fresh block-assembly state for one stream. */\nfunction createBlockAssembler(): BlockAssembler {\n return {\n nextIndex: 0,\n textIndex: -1,\n textContent: '',\n reasoningIndex: -1,\n reasoningContent: '',\n sawContent: false,\n openAiToolCalls: [],\n }\n}\n\nfunction* closeText(asm: BlockAssembler): Generator<StreamChunk> {\n if (asm.textIndex < 0) return\n yield {\n type: 'block-end',\n index: asm.textIndex,\n block: { type: 'text', text: asm.textContent },\n }\n asm.textIndex = -1\n asm.textContent = ''\n}\n\nfunction* closeReasoning(asm: BlockAssembler): Generator<StreamChunk> {\n if (asm.reasoningIndex < 0) return\n yield {\n type: 'block-end',\n index: asm.reasoningIndex,\n block: { type: 'reasoning', text: asm.reasoningContent },\n }\n asm.reasoningIndex = -1\n asm.reasoningContent = ''\n}\n\nfunction* emitOpenAiToolCalls(asm: BlockAssembler): Generator<StreamChunk> {\n for (const call of asm.openAiToolCalls) {\n const id = call.id ?? randomUUID()\n const name = call.name ?? ''\n const args = call.arguments || '{}'\n const index = asm.nextIndex++\n asm.sawContent = true\n yield { type: 'block-start', index, blockType: 'tool-call' }\n yield { type: 'tool-call-delta', index, id: ToolCallId(id), name, argumentsDelta: args }\n yield {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: ToolCallId(id), name, arguments: args },\n }\n }\n asm.openAiToolCalls.length = 0\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private catalog: CommandCodeModel[] = []\n private readonly fetchImpl: typeof fetch\n private readonly resolveAttachments: ResolveAttachments | undefined\n /** The engine's request-image policy, resolved once (tests may inject one). */\n private readonly imagePolicy: CoreImagePolicy\n /**\n * The ≥0.1.6 durable contract, or `undefined` on a ≤0.1.5 engine — where the\n * adapter must evict its own history. Resolved once: the contract a process\n * speaks cannot change while it runs, and resolving here keeps every request\n * on the same branch (see {@link surfaceImagePolicy}).\n */\n private readonly surfaceOffload: SurfaceImagePolicy | undefined\n // Billing facts are per account: with a multi-account pool each key has its\n // own subscription tier, so the cache and the in-flight dedupe are keyed by\n // the resolved API key (process-local only, never logged). Entries are\n // small and bounded by the account count in practice; a changed key simply\n // starts a fresh entry while the orphaned one goes cold (no eviction —\n // transience is intentional, persistence would serve stale tiers).\n private readonly billingAccess = new Map<string, { value: CommandCodeBillingAccess | undefined; at: number }>()\n private readonly billingAccessInflight = new Map<string, Promise<CommandCodeBillingAccess | undefined>>()\n // Protocol preference is per account: the Go plan is the only plan without\n // Provider API access, and that fact is independent of model. A negative\n // result (provider API rejected this key with upgrade_required) is cached so\n // every request does not pay the double TTFT of probing then falling back.\n // Same bounded-by-account-count note as above: no eviction by design.\n private readonly protocolCache = new Map<string, { useCli: boolean; at: number }>()\n\n constructor(private readonly deps: CommandCodeAdapterDeps<C>) {\n super()\n this.fetchImpl = deps.fetchImpl ?? fetch\n this.resolveAttachments = deps.resolveAttachments\n this.imagePolicy = deps.imageOffload ?? CORE_IMAGE_POLICY\n this.surfaceOffload = surfaceImagePolicy(this.imagePolicy)\n }\n\n /**\n * Display metadata for the picker's provider group header. The base class\n * returns the raw route id (`commandcode`, all lowercase) as the name, which\n * is what the model selector shows as this group's sticky title; return the\n * proper display name instead, matching the Models settings page card (the\n * configurable-provider `displayName`). The id must stay equal to the route.\n */\n override providerInfo(provider: string): LlmProviderInfo {\n return { id: provider, name: 'Command Code' }\n }\n\n /**\n * Near-unbounded retry for transient failures only (`mode: 'normal'` with\n * an explicit 1000-attempt cap — opencode-style persistence without the\n * unbounded loop): `RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`/\n * `EMPTY_RESPONSE` retry up to 1000 times with waits doubling from 500 ms\n * and capping at 15 minutes (±10% jitter), so an exhausted 5-hour window\n * recovers in-session instead of failing after two tries. Permanent\n * failures (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`,\n * plan rejections) are absent from the whitelist and surface immediately\n * instead of looping. Waits the pool/adapter attach as\n * `providerRetryAfterMs` are honored verbatim at or below the 15-minute\n * cap and never attached above it (in normal mode a longer attached wait\n * makes the executor abandon the retry outright — see RETRY_MAX_DELAY_MS).\n *\n * Captured once at route registration (dsh-llm snapshots this value), so a\n * future config knob for it would apply on profile restart, not per request.\n */\n override providerRetryPolicy(_provider: string): ResolvedRetryPolicy {\n return resolveRetryPolicy(\n {\n mode: 'normal',\n maxRetries: 1000,\n retryableCodes: ['EMPTY_RESPONSE', 'RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT'],\n backoff: { initialDelayMs: 500, maxDelayMs: RETRY_MAX_DELAY_MS, jitterRatio: 0.1 },\n },\n 'llm-commandcode: retryPolicy',\n )\n }\n\n /**\n * Visual-token pricing for one exact model route (see `./image-tokens.ts`).\n *\n * Without this the token meter prices EVERY image with its structural\n * heuristic — a handful of tokens for a full screenshot — so an image-heavy\n * session reports far less context than it is actually carrying. The price is\n * computed at the dimensions this route would send (the same request target\n * `readImageRequest` encodes to), so the estimate tracks the wire rather than\n * the stored original.\n *\n * Both payload generations are handled, because they disagree: ≤0.1.5 hands\n * over bare `ImageAttachmentRef`s, ≥0.1.6 hands over `ImageBlock`s that also\n * carry the surface's `offloaded` mark. Returning a price per occurrence, in\n * order, is a hard requirement — the meter throws when the counts differ.\n */\n override imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined {\n const imageCapable = KNOWN_IMAGE_MODELS.has(model)\n return {\n priceImages: (images: readonly PricedOccurrence[]) =>\n images.map((image) => priceRequestImage(image, model, imageCapable)),\n }\n }\n\n /** Refresh the catalog (live fetch, cache fallback) and return it. */\n private async loadCatalog(signal?: AbortSignal): Promise<CommandCodeModel[]> {\n const { apiBase, modelsCachePath } = this.deps.options()\n try {\n const response = await this.fetchImpl(`${apiBase}/provider/v1/models`, {\n headers: { accept: 'application/json', ...attributionHeaders() },\n signal: signal ?? AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) {\n throw new Error(`models endpoint returned ${response.status}`)\n }\n this.catalog = parseCatalogResponse(await response.json())\n await writeModelsCache(modelsCachePath, this.catalog).catch(() => undefined)\n } catch (error) {\n if (signal?.aborted) throw error\n // A catalog refresh failure is a degradation, not a request failure:\n // fall back to the last successful catalog on disk (or the in-memory\n // one from an earlier successful load). The adapter still serves any\n // model the user names; only the advisory selector loses entries.\n this.catalog = await readModelsCache(modelsCachePath).catch(() => this.catalog)\n }\n return this.catalog\n }\n\n override async listModels(\n provider: string,\n opts?: { unfiltered?: boolean },\n ): Promise<readonly LlmModelInfo[]> {\n const catalog = await this.loadCatalog()\n const toInfo = (model: (typeof catalog)[number]) => {\n const vision = KNOWN_IMAGE_MODELS.has(model.id)\n return {\n provider,\n id: model.id,\n name: `${model.name} (CC)`,\n // The picker renders `description` under the model name: plan tier,\n // active deal, Image marker for Vision models, and context window.\n description: capabilityDescription(model.id, model.contextWindow),\n inputModalities: vision ? (['text', 'image'] as const) : (['text'] as const),\n }\n }\n // Unfiltered: the settings page's catalog endpoint serves the full catalog\n // so the filter editor can always offer every model.\n if (opts?.unfiltered === true) return catalog.map(toInfo).sort(compareByPlan)\n // Plan filter: hide models above the account's subscription tier. Fails\n // open — a billing-fetch problem, an unknown plan, or a positive\n // on-demand balance all keep the full catalog visible, and the server\n // remains the final gate (403 MODEL_NOT_IN_PLAN). The catalog itself is\n // never filtered: resolveModel still serves every model.\n const access = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadBillingAccess()\n // Visible-model allowlist: empty/unset means \"show everything\".\n const visible = this.deps.options().visibleModels\n const allow = Array.isArray(visible) && visible.length > 0\n ? new Set(visible.filter((id) => typeof id === 'string' && id !== ''))\n : undefined\n // Per-model overrides, written by the terminal settings page's checkboxes\n // (its seam can only give each model its own boolean field, and a boolean\n // cannot express \"this id is in the list\"). An explicit flag decides the\n // model on its own; everything unflagged still follows the array above, so\n // a composition-config allowlist and the web page keep working untouched.\n const overrides = this.deps.options().modelVisibility\n return catalog\n .filter((model) => modelVisibleInPlan(model.id, access))\n .filter((model) => {\n const override = overrides?.[model.id]\n if (typeof override === 'boolean') return override\n return allow === undefined || allow.has(model.id)\n })\n .map(toInfo)\n // The picker renders rows in the order returned: sort by plan tier\n // (Go first, … Provider last) so the models a Go-plan user can actually\n // use lead the list, then alphabetically within each tier.\n .sort(compareByPlan)\n }\n\n override async resolveModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<LlmResolvedModelInfo> {\n const entry =\n this.catalog.find((m) => m.id === model) ??\n (await this.loadCatalog(signal)).find((m) => m.id === model)\n\n const efforts = KNOWN_EFFORTS[model]\n const vision = KNOWN_IMAGE_MODELS.has(model)\n return {\n provider,\n id: model,\n name: entry ? `${entry.name} (CC)` : model,\n description: capabilityDescription(model, entry?.contextWindow),\n inputModalities: vision ? (['text', 'image'] as const) : (['text'] as const),\n ...(entry\n ? {\n context: { contextWindow: entry.contextWindow },\n defaultMaxTokens: Math.min(entry.maxTokens, DEFAULT_GENERATE_MAX_TOKENS),\n }\n : {}),\n // Omit `reasoning` entirely for models without known effort support:\n // the harness then treats the model as having no selectable efforts.\n ...(efforts\n ? {\n reasoning: {\n efforts: efforts.map((effort) => ({\n id: ReasoningEffortId(effort),\n name: effort,\n })),\n },\n }\n : {}),\n }\n }\n\n /** The headers every authenticated account endpoint shares. */\n private async accountHeaders(apiKey?: string): Promise<Record<string, string>> {\n const connection = this.deps.options()\n const key = apiKey ?? (await this.deps.resolveApiKey(connection))\n return {\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n ...attributionHeaders(),\n }\n }\n\n /**\n * Fetch one account endpoint and parse its JSON body. Returns the HTTP\n * status alongside the parsed record so each caller applies its own\n * failure accounting: the billing probe fails open silently, the usage\n * report books failures per endpoint. Non-2xx and non-record bodies come\n * back without a record; only a transport throw propagates to the caller.\n */\n private async fetchEndpointJson(\n url: string,\n headers: Record<string, string>,\n ): Promise<{ status: number; record?: Record<string, unknown> }> {\n const response = await this.fetchImpl(url, {\n headers,\n // A hung account endpoint must not stall the picker / usage card forever.\n signal: AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) return { status: response.status }\n const parsed: unknown = await response.json()\n return { status: response.status, ...(isRecord(parsed) ? { record: parsed } : {}) }\n }\n\n /**\n * The billing facts behind the picker's plan filter, cached for\n * {@link BILLING_ACCESS_TTL_MS} and shared across concurrent callers.\n * `undefined` means \"unknown — show everything\" (fail-open).\n */\n private async loadBillingAccess(): Promise<CommandCodeBillingAccess | undefined> {\n let apiKey: string\n try {\n apiKey = await this.deps.resolveApiKey(this.deps.options())\n } catch {\n return undefined\n }\n const cached = this.billingAccess.get(apiKey)\n if (cached !== undefined && Date.now() - cached.at < BILLING_ACCESS_TTL_MS) return cached.value\n const existing = this.billingAccessInflight.get(apiKey)\n if (existing !== undefined) return existing\n const inflight = this.fetchBillingAccess(apiKey)\n .then((value) => {\n this.billingAccess.set(apiKey, { value, at: Date.now() })\n return value\n })\n .finally(() => {\n this.billingAccessInflight.delete(apiKey)\n })\n this.billingAccessInflight.set(apiKey, inflight)\n return inflight\n }\n\n /**\n * The billing facts behind the picker's plan filter, mirroring the CLI's\n * `createBilling` flow: whoami yields the org id, then the subscriptions\n * and credits endpoints answer in parallel. The plan id is honored only\n * when the subscription reports an active-ish status (the CLI's rule); when\n * the subscriptions endpoint fails entirely, `credits.planId` is the\n * fallback (the CLI stamps plan identity from it too). Any failure resolves\n * to `undefined` (fail-open) rather than breaking the picker.\n */\n private async fetchBillingAccess(apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\n try {\n const connection = this.deps.options()\n const headers = await this.accountHeaders(apiKey)\n const base = connection.apiBase\n // Billing probe fails open silently: any non-record is \"unknown\".\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> =>\n (await this.fetchEndpointJson(`${base}${path}`, headers)).record\n const whoami = await getJson('/alpha/whoami')\n const orgData = whoami && isRecord(whoami.org) ? whoami.org : undefined\n const orgId = orgData === undefined ? undefined : stringValue(orgData.id)\n const [subscription, credits] = await Promise.all([\n getJson(orgId === undefined\n ? '/alpha/billing/subscriptions'\n : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`),\n getJson('/alpha/billing/credits'),\n ])\n const subData = subscription && isRecord(subscription.data) ? subscription.data : undefined\n const creditsData = credits && isRecord(credits.credits) ? credits.credits : undefined\n if (subData === undefined && creditsData === undefined) return undefined\n let planId: string | undefined\n if (subData !== undefined) {\n const status = stringValue(subData.status)\n if (status !== undefined && ACTIVE_SUBSCRIPTION_STATUSES.has(status)) planId = stringValue(subData.planId)\n } else {\n planId = stringValue(creditsData?.planId)\n }\n return {\n tierWeight: planId === undefined ? undefined : subscriptionPlanInfo(planId)?.tierWeight,\n onDemandCredits: (numberValue(creditsData?.purchasedCredits) ?? 0) + (numberValue(creditsData?.freeCredits) ?? 0),\n }\n } catch {\n return undefined\n }\n }\n\n /** Fresh cached billing tier weight for a key, or undefined when not known. */\n private cachedBillingTierWeight(apiKey: string): number | undefined {\n const hit = this.billingAccess.get(apiKey)\n if (hit === undefined || Date.now() - hit.at >= BILLING_ACCESS_TTL_MS) return undefined\n return hit.value?.tierWeight\n }\n\n /** Cached protocol decision for a key, or undefined when expired/unknown. */\n private cachedProtocolUseCli(apiKey: string): boolean | undefined {\n const hit = this.protocolCache.get(apiKey)\n if (hit === undefined || Date.now() - hit.at >= PROTOCOL_CACHE_TTL_MS) return undefined\n return hit.useCli\n }\n\n private rememberProtocol(apiKey: string, useCli: boolean): void {\n this.protocolCache.set(apiKey, { useCli, at: Date.now() })\n }\n\n /**\n * Choose the initial protocol for one request. A fresh protocol cache entry\n * wins; otherwise a cached (not network-fetched) billing tier of Go is\n * treated as CLI-only. Unknown accounts default to Provider API and fall\n * back only after an `upgrade_required` rejection.\n *\n * Models the Provider API serves ONLY through `/provider/v1/messages` (the\n * Claude family — `requiresMessagesEndpoint()`) always take the CLI\n * transport, on any tier and even under a forced `'openai'` preference:\n * that option is documented as \"prefer the Provider API, still fall back\",\n * and the 400 these models answer with is not a preference to be honoured\n * but a hard refusal. `/alpha/generate` routes every one of them, so this\n * costs nothing.\n *\n * That decision is deliberately NOT written to `protocolCache`. The cache is\n * keyed by API key alone, so remembering it would pin the whole ACCOUNT to\n * the CLI transport and drag every other model — DeepSeek, GLM, Qwen, all of\n * which the Provider API serves correctly — off it until the entry expired.\n */\n private resolveProtocol(apiKey: string, model: string): CommandCodeProtocol {\n const forced = this.deps.options().protocol\n if (forced === 'cli') return forced\n if (requiresMessagesEndpoint(model)) return 'cli'\n if (forced === 'openai') return forced\n const cached = this.cachedProtocolUseCli(apiKey)\n if (cached !== undefined) return cached ? 'cli' : 'openai'\n if (this.cachedBillingTierWeight(apiKey) === GO_TIER_WEIGHT) {\n this.rememberProtocol(apiKey, true)\n return 'cli'\n }\n return 'openai'\n }\n\n\n /**\n * Fetch account, usage, credit, and subscription state from the Command\n * Code account endpoints (`/alpha/whoami`, `/alpha/usage/summary`,\n * `/alpha/billing/credits`, `/alpha/billing/subscriptions`).\n * Each endpoint degrades independently: a failed one lands in `failures`\n * while the rest still report, so a transient outage never blanks the whole\n * view. Requires a usable API key (throws `MISSING_CREDENTIAL` otherwise).\n * Pass `apiKey` to report on a specific account of a multi-account pool;\n * the default resolves the currently active account.\n */\n async getUsage(apiKey?: string): Promise<CommandCodeUsageReport> {\n const connection = this.deps.options()\n const base = connection.apiBase\n const headers = await this.accountHeaders(apiKey)\n const failures: string[] = []\n // HTTP status per failed endpoint (undefined for transport failures), in\n // failure order — the all-failed classification below reads it.\n const failedStatuses: Array<number | undefined> = []\n\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> => {\n try {\n const { status, record } = await this.fetchEndpointJson(`${base}${path}`, headers)\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}`)\n failedStatuses.push(status)\n return undefined\n }\n return record\n } catch (error: unknown) {\n failures.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n failedStatuses.push(undefined)\n return undefined\n }\n }\n\n const report: CommandCodeUsageReport = { failures }\n\n // whoami first (account identity + the org id the subscriptions query\n // needs); the other three endpoints are independent once headers exist,\n // so they run in parallel instead of paying 4x the timeout serially.\n const whoami = await getJson('/alpha/whoami')\n const { account, orgId } = parseAccountIdentity(whoami)\n if (account !== undefined) report.account = account\n const [usage, credits, subscription] = await Promise.all([\n getJson('/alpha/usage/summary'),\n getJson('/alpha/billing/credits'),\n getJson(orgId === undefined\n ? '/alpha/billing/subscriptions'\n : `/alpha/billing/subscriptions?orgId=${encodeURIComponent(orgId)}`),\n ])\n\n // usage/summary -> totals.\n const totals = parseUsageTotals(usage)\n if (totals !== undefined) report.usage = totals\n\n // billing/credits -> credit + window limits.\n const limits = parseCreditLimits(credits)\n if (limits !== undefined) report.credits = limits\n\n // billing/subscriptions -> plan identity + billing period. The credits\n // response may also carry a planId; it is the fallback when the\n // subscriptions endpoint fails.\n const subData = subscription !== undefined && isRecord(subscription.data) ? subscription.data : undefined\n const creditsData = credits !== undefined && isRecord(credits.credits) ? credits.credits : undefined\n const planId = stringValue(subData?.planId) ?? stringValue(creditsData?.planId)\n if (subData !== undefined || planId !== undefined) {\n const info = planId === undefined ? undefined : subscriptionPlanInfo(planId)\n report.plan = {\n planId: planId ?? '',\n name: info?.name ?? planId ?? '',\n status: stringValue(subData?.status) ?? '',\n monthlyCredits: info?.monthlyCredits ?? null,\n currentPeriodEnd: periodEndValue(subData?.currentPeriodEnd),\n }\n }\n\n const blocked = classifyTotalFailure(failures, failedStatuses)\n if (blocked !== undefined) report.blocked = blocked\n\n return report\n }\n\n /**\n * Probe one account's five-hour window from `/alpha/billing/credits`. The\n * multi-account pool calls this when every account is marked exhausted: an\n * account whose window no longer reports `exceeded` is revived, and the\n * `resetAt` values feed the \"earliest reset\" error message. Returns\n * `undefined` when the probe itself failed (transport, non-200, or a\n * payload without window limits) — a failed probe never changes pool state.\n */\n async probeFiveHourWindow(apiKey: string): Promise<{ exceeded: boolean; resetAt: number } | undefined> {\n try {\n const connection = this.deps.options()\n const response = await this.fetchImpl(`${connection.apiBase}/alpha/billing/credits`, {\n headers: await this.accountHeaders(apiKey),\n signal: AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) return undefined\n const parsed: unknown = await response.json()\n if (!isRecord(parsed)) return undefined\n const windowLimits = isRecord(parsed.windowLimits) ? parsed.windowLimits : undefined\n const fiveHour = windowLimits && isRecord(windowLimits.fiveHour) ? windowLimits.fiveHour : undefined\n if (fiveHour === undefined) return undefined\n return { exceeded: fiveHour.exceeded === true, resetAt: numberValue(fiveHour.resetAt) ?? 0 }\n } catch {\n return undefined\n }\n }\n\n async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n if (options.stop?.length) {\n // The Command Code wire format has no documented stop field; refuse\n // loudly instead of silently dropping a request field.\n throw new LlmError('Command Code adapter does not support stop sequences', 'UNSUPPORTED_OPTION')\n }\n const hasImages = options.messages.some(hasImageContent)\n // Per-call image byte resolver, set only when this request carries images.\n // Local, not an instance field: concurrent streams must never read each\n // other's resolver.\n let readImage: ((ref: ImageAttachmentRef) => Promise<Uint8Array>) | undefined\n if (hasImages) {\n // Model-capability gate: only models the official registry lists with\n // Vision accept images natively. Command Code's own CLI falls back to a\n // client-side VISION side-call for text-only models; this adapter does\n // not reproduce that interactive feature, so it refuses loudly instead\n // of sending bytes to a model that cannot read them.\n if (!KNOWN_IMAGE_MODELS.has(options.model)) {\n throw new LlmError(\n `Command Code model \"${options.model}\" does not support image input;`\n + ' switch to a Vision-capable model (see the model registry)',\n 'UNSUPPORTED_CONTENT',\n )\n }\n // Attachment seam: images arrive as durable references; resolving them\n // requires the host's attachment service.\n const attachments = this.resolveAttachments?.()\n if (attachments === undefined) {\n throw new LlmError(\n 'Command Code image input requires the durable attachment service',\n 'UNSUPPORTED_CONTENT',\n )\n }\n readImage = (ref) => readRequestImage(attachments, ref)\n }\n\n const connection = this.deps.options()\n // The model id reaches key resolution so hosts with model→account routing\n // rules can pick the account that covers this model.\n let apiKey = await this.deps.resolveApiKey(connection, options.model)\n // Cap maxTokens from the in-memory catalog: it warms via listModels /\n // resolveModel on picker paths, and a fresh-process catalog must not add\n // a models fetch (and its failure modes) in front of every generate.\n const modelMax = this.catalog.find((m) => m.id === options.model)?.maxTokens\n ?? DEFAULT_MAX_OUTPUT_TOKENS\n const maxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n const reasoningEffort =\n effort && effort !== 'off' && supported?.includes(effort) ? effort : undefined\n\n const systemText = [\n options.system ?? '',\n ...options.messages\n .filter((m) => m.role === 'system')\n .map((m) => m.content.map(blockText).filter(Boolean).join('\\n')),\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n // Endpoint protocol: billing/cache may know Go plan -> CLI; unknown\n // accounts default to the documented Provider Chat Completions surface.\n // A Messages-only model (Claude) forces the CLI transport regardless —\n // see `resolveProtocol()`.\n let protocol: CommandCodeProtocol = this.resolveProtocol(apiKey, options.model)\n // Image budget (issue #37): the body is built from the PROJECTED history,\n // never the raw one, so the oldest images past the cap travel as\n // placeholder text instead of a body the gateway refuses outright. Rung 0\n // is the standing budget; a 413 below steps down the ladder.\n //\n // Which projection that is depends on the engine: a ≥0.1.6 harness owns the\n // offload set (this throws `IMAGE_OFFLOAD_REQUIRED` when more must go, and\n // the retry arrives with the surface already updated), while a ≤0.1.5 one\n // has no such ledger and gets the adapter's own transient eviction.\n let requestOptions = this.surfaceOffload === undefined\n ? withImageBudget(options, REQUEST_IMAGE_BUDGETS[0]!, this.imagePolicy)\n : withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!)\n let imageBudgetIndex = 0\n const buildBody = async (target: CommandCodeProtocol): Promise<Record<string, unknown>> =>\n target === 'cli'\n ? buildCliBody(requestOptions, connection, { maxTokens, reasoningEffort, systemText, readImage })\n : buildOpenAIBody(requestOptions, { maxTokens, reasoningEffort, systemText, readImage })\n let body: Record<string, unknown> = await buildBody(protocol)\n\n\n // Account rotation loop: the first attempt uses the pool's active key; a\n // pre-stream 429/401 rotates to the next account (at most one attempt per\n // distinct key, hard-capped so a misbehaving hook cannot loop forever).\n // requestTimeoutMs bounds the headers wait of EACH attempt (see\n // connectGenerate); the body is account-independent, nothing has\n // streamed yet, so the switch is invisible to the caller.\n const tried = new Set<string>()\n const connectDeps: GenerateConnectDeps = { options, connection, fetchImpl: this.fetchImpl }\n let connected: { response: Response; cleanup: () => void } | undefined\n for (;;) {\n tried.add(apiKey)\n const attempt = await connectGenerate(connectDeps, apiKey, protocol, body)\n if ('response' in attempt) {\n connected = attempt\n break\n }\n // Provider API is the preferred surface for non-Go accounts. If the\n // gateway says the key is on the Go plan (the only plan without API\n // access), remember that and retry the same key through /alpha/generate\n // without burning the double TTFT on every later request.\n if (\n protocol === 'openai'\n && isUpgradeRequiredError(attempt.status, attempt.errText)\n ) {\n protocol = 'cli'\n this.rememberProtocol(apiKey, true)\n body = await buildBody('cli')\n continue\n }\n // Request too large (issue #37): the standing budget is only an\n // estimate — the cap also covers text and tool bytes — so one 413 steps\n // the image budget down and resends. Safe like the rotation below:\n // nothing streamed, the same key stays in use, and a request with no\n // images left to evict is not resent (the stricter rung reports nothing\n // more to drop, so this branch cannot loop).\n if (attempt.status === 413 && imageBudgetIndex + 1 < REQUEST_IMAGE_BUDGETS.length) {\n if (this.surfaceOffload !== undefined) {\n // ≥0.1.6: the stricter rung becomes another offload request rather\n // than a local edit, so the extra omissions are recorded on the\n // session and survive the retry. Zero here means the images are\n // already gone and the body is simply too big — fall through to the\n // 413 diagnosis instead of asking for an offload that cannot happen.\n const missing = this.surfaceOffload.requiredImageOffload(\n requestOptions.messages,\n coreBudget(REQUEST_IMAGE_BUDGETS[imageBudgetIndex + 1]!),\n imageVersionBytes,\n )\n if (missing > 0) throw imageOffloadRequired(missing)\n } else {\n const tightened = withImageBudget(requestOptions, REQUEST_IMAGE_BUDGETS[imageBudgetIndex + 1]!, this.imagePolicy)\n if (tightened !== requestOptions) {\n imageBudgetIndex += 1\n requestOptions = tightened\n body = await buildBody(protocol)\n continue\n }\n }\n }\n const rotate = this.deps.rotateApiKey\n if (\n (attempt.status === 429 || attempt.status === 401)\n && rotate !== undefined\n && options.signal?.aborted !== true\n && tried.size < MAX_ACCOUNT_ROTATIONS\n ) {\n const next = await rotate(apiKey, attempt.status === 429 ? 'rate-limit' : 'invalid-credential', connection, options.model)\n if (next !== undefined && !tried.has(next)) {\n apiKey = next\n continue\n }\n }\n throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs)\n }\n if (connected === undefined) {\n // Unreachable: the loop only exits via `break` (connected set) or\n // `throw` above. The guard keeps the narrowing explicit.\n throw new LlmError('Command Code API connection failed without a response', 'TRANSPORT')\n }\n const { response, cleanup } = connected\n if (!response.body) {\n cleanup()\n throw new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR')\n }\n\n // --- SSE/JSONL event stream -> harness StreamChunk protocol ---\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n // Stream idle watchdog: a generation that stalls this long has a dead\n // connection (the API keeps the socket open between reasoning/text\n // bursts). The default (300s) is deliberately generous: frontier\n // reasoning models (xhigh/max effort) can legitimately stay silent for\n // minutes while thinking, and the official CLI sets no idle cap at all —\n // an aggressive cap turns long thinking into spurious TIMEOUTs and\n // retries. reader.cancel() unblocks a pending read(), which the loop then\n // turns into a TIMEOUT failure instead of hanging forever.\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n let idleFired = false\n const armIdle = () => {\n if (idleTimer !== undefined) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleFired = true\n void reader.cancel().catch(() => undefined)\n }, connection.streamIdleTimeoutMs)\n }\n const clearIdle = () => {\n if (idleTimer !== undefined) {\n clearTimeout(idleTimer)\n idleTimer = undefined\n }\n }\n\n const asm = createBlockAssembler()\n const handle = (event: unknown): StreamChunk[] => handleEvent(asm, protocol, event)\n try {\n let finished = false\n for (;;) {\n let read: ReadableStreamReadResult<Uint8Array>\n armIdle()\n try {\n read = await reader.read()\n } catch (error: unknown) {\n // A mid-stream transport failure (connection reset, TLS teardown)\n // surfaces here. Caller cancellation propagates as-is.\n if (options.signal?.aborted) throw error\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} failed while reading: ${errorChain(error)}`\n + ';Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\n 'TRANSPORT',\n { cause: error },\n )\n } finally {\n clearIdle()\n }\n const { done, value } = read\n if (done) {\n // The idle watchdog cancels the reader to unblock a stalled read;\n // cancel() resolves a pending read() as done, so a done here after\n // the watchdog fired is a timeout, not a normal stream end.\n if (idleFired) {\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} was idle for ${connection.streamIdleTimeoutMs}ms`\n + ' (no events) and was treated as a dead connection'\n + `;Command Code API 流式响应已 ${connection.streamIdleTimeoutMs} 毫秒无任何事件,被判定为死连接——长思考模型可在设置中调大流空闲超时`,\n 'TIMEOUT',\n )\n }\n if (buffer.trim()) {\n // The final line may lack its trailing newline: account its\n // chunks exactly like the line loop (a trailing `finish` must\n // set `finished`, or the tail below would emit a second one).\n for (const chunk of handle(parseStreamEventLine(buffer))) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n const chunks = handle(parseStreamEventLine(line))\n for (const chunk of chunks) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n if (finished) break\n }\n if (!finished) {\n // Stream ended without a finish event: close open blocks and\n // terminate according to the adapter contract (usage, then finish).\n yield* closeText(asm)\n yield* closeReasoning(asm)\n if (protocol === 'openai') yield* emitOpenAiToolCalls(asm)\n if (!asm.sawContent) {\n throw new LlmError('Command Code returned an empty response;Command Code 返回了空响应,重试通常可恢复', 'EMPTY_RESPONSE')\n }\n yield { type: 'finish', reason: { kind: 'stop' } }\n }\n } finally {\n clearIdle()\n cleanup()\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n}\n\n/**\n * Map a pre-stream generate HTTP failure onto a stable LlmError. Command\n * Code folds several business rejections into 403 (plan limits, CLI version,\n * model access): prefer the machine-readable `error.code` when present; the\n * status alone cannot distinguish them. The status also decides the failure\n * CODE via {@link httpErrorCode}, which is what the retry policy routes on —\n * a transient 5xx must not be reported as a permanent provider rejection. A\n * 429's `Retry-After` header rides along as\n * `providerRetryAfterMs` so dsh-llm-retry can wait exactly that long instead\n * of guessing at the backoff cadence — capped at RETRY_MAX_DELAY_MS, because\n * in normal mode a longer attached wait makes the executor abandon the retry\n * outright instead of falling back to local backoff.\n *\n * One body is read, not just its status: a client-side rejection whose\n * `error.code`/`type`/`message` names the model context window is reported as\n * `CONTEXT_WINDOW_EXCEEDED` (see the branch below), because that failure has a\n * recovery the harness performs and a generic provider error does not.\n */\nfunction generateHttpError(status: number, errText: string, retryAfterMs?: number): LlmError {\n let providerCode: string | undefined\n let providerDetail = ''\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed) && isRecord(parsed.error)) {\n providerCode = stringValue(parsed.error.code)\n providerDetail = [stringValue(parsed.error.code), stringValue(parsed.error.type), stringValue(parsed.error.message)]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\n }\n } catch {\n // Plain-text bodies: rely on the status mapping below.\n }\n const detail = providerCode ?? `HTTP ${status}`\n // A context-window rejection is not a generic provider failure: the request\n // is well-formed but larger than the model's window, and the harness knows\n // how to recover — dsh-compaction-basic answers CONTEXT_WINDOW_EXCEEDED on\n // `agent/request-error` with a compaction plus a retry of the reduced\n // surface. Reported as a plain provider rejection it failed the turn with no\n // way back but a manual /compact, and the same wording delivered in-band was\n // retried unchanged (issue #39). Checked before the 413 branch so an\n // over-context rejection that happens to carry that status gets the recovery\n // rather than the body-size advice. Only client-side rejections (`status <\n // 500`) are inspected, and the parsed provider fields are preferred over the\n // raw body, so an HTML error page cannot mention its way into a compaction.\n // Bilingual — the harness renders this message verbatim.\n const overflowDetail = providerDetail !== '' ? providerDetail : errText.slice(0, 500)\n if (status < 500 && isContextOverflowDetail(overflowDetail)) {\n return new LlmError(\n `Command Code API error ${status}: the request exceeds the model's context window`\n + ' — this session is being compacted and the request retried'\n + `;Command Code API 返回 ${status}:请求内容超出模型上下文窗口——正在压缩上下文后重试;如仍失败,请新建会话或减少上下文`,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n { status },\n )\n }\n if (status === 401) {\n // An invalid or missing credential is a config problem, not a\n // transport failure: retrying it identically cannot succeed. Bilingual —\n // the harness UI renders this message verbatim in its retry chrome.\n return new LlmError(\n `Command Code API error 401 (${detail}): the API key is missing or invalid — check the`\n + ' key stored for COMMANDCODE_API_KEY (Models page) or the auth file'\n + ';Command Code API 返回 401:API 密钥缺失或无效——请在设置页检查 COMMANDCODE_API_KEY 存储的密钥,或检查 auth 文件',\n 'INVALID_CREDENTIAL',\n { status: 401 },\n )\n }\n if (status === 413) {\n // Request-body cap (issue #37). Command Code documents no 413 at all, so\n // without this branch the reader sees a bare \"HTTP 413\" and no way to tell\n // it apart from a generic provider failure. Reaching here means the\n // adapter already dropped this request's oldest images as far as its\n // budget ladder allows, or the body is large without images at all, so\n // the advice is the only remaining lever the user has. Bilingual — the\n // harness UI renders this message verbatim in its retry chrome.\n return new LlmError(\n 'Command Code API error 413: the request body exceeds the provider\\'s size limit'\n + ' (the cap is undocumented, measured at about 50 MB) — the session history is too large'\n + ' to send, usually because of accumulated image attachments. Start a new session, or'\n + ' drop the image-heavy part of this one, and retry'\n + ';Command Code API 返回 413:请求体超过服务端的体积上限(官方未公开,实测约 50 MB)'\n + '——会话历史过大,通常是历史图片累积所致。请新建会话,或移除本会话中图片较多的部分后重试',\n 'PROVIDER_HTTP_ERROR',\n { status: 413 },\n )\n }\n return new LlmError(\n `Command Code API error ${status}${detail === `HTTP ${status}` ? '' : ` (${detail})`}: ${errText.slice(0, 500)}`,\n httpErrorCode(status),\n {\n status,\n ...(retryAfterMs !== undefined && retryAfterMs > 0 && retryAfterMs <= RETRY_MAX_DELAY_MS\n ? { providerRetryAfterMs: retryAfterMs }\n : {}),\n },\n )\n}\n\n/**\n * Classify a pre-stream HTTP status into the failure code the route's retry\n * policy keys on. dsh-llm-retry matches `retryableCodes` only — never the\n * status, never the provider's `error.type` — so a status that arrives here as\n * a permanent code is never retried, whatever it says about itself.\n *\n * 5xx is the provider's own \"we are temporarily unavailable\" class (Cloudflare's\n * 520-527 included; a 520 body says exactly that in words) and the only sane\n * answer to it is the byte-identical resend the retry policy exists to make.\n * Keeping it on `PROVIDER_HTTP_ERROR` — absent from the whitelist by design, so\n * that a 403 plan rejection or a 400 shape error fails fast — made the one\n * failure that asks to be retried the only one that never was, while the same\n * status arriving as an in-band stream `error` event was classified retryable\n * `SERVER` (see the `error` case of {@link handleCliEvent}). 408 is the same\n * story for the request itself. Everything else stays permanent: a 400/403/404/\n * 409/422 rejection repeats identically on every attempt.\n */\nfunction httpErrorCode(status: number): string {\n if (status === 429) return 'RATE_LIMIT'\n if (status === 408) return 'TIMEOUT'\n if (status >= 500) return 'SERVER'\n return 'PROVIDER_HTTP_ERROR'\n}\n\n\n/**\n * Handle one CLI-transport (`/alpha/generate`) stream event, appending\n * harness StreamChunks. Pure over the passed assembler — no stream() locals.\n */\nfunction handleCliEvent(asm: BlockAssembler, event: unknown): StreamChunk[] {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n\n switch (event.type) {\n case 'text-delta': {\n chunks.push(...closeReasoning(asm))\n if (asm.textIndex < 0) {\n asm.textIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.textIndex, blockType: 'text' })\n }\n const delta = stringValue(event.text) ?? ''\n asm.textContent += delta\n asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: delta })\n break\n }\n case 'reasoning-delta': {\n chunks.push(...closeText(asm))\n if (asm.reasoningIndex < 0) {\n asm.reasoningIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.reasoningIndex, blockType: 'reasoning' })\n }\n const delta = stringValue(event.text) ?? ''\n asm.reasoningContent += delta\n chunks.push({ type: 'reasoning-delta', index: asm.reasoningIndex, text: delta })\n break\n }\n case 'reasoning-start':\n chunks.push(...closeText(asm))\n break\n case 'reasoning-end':\n chunks.push(...closeReasoning(asm))\n break\n case 'tool-call': {\n chunks.push(...closeText(asm), ...closeReasoning(asm))\n const id = stringValue(event.toolCallId) ?? randomUUID()\n const name = stringValue(event.toolName) ?? ''\n const args = JSON.stringify(recordOrEmpty(event.input ?? event.args ?? event.arguments))\n const index = asm.nextIndex++\n asm.sawContent = true\n chunks.push(\n { type: 'block-start', index, blockType: 'tool-call' },\n { type: 'tool-call-delta', index, id: ToolCallId(id), name, argumentsDelta: args },\n {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: ToolCallId(id), name, arguments: args },\n },\n )\n break\n }\n case 'finish': {\n chunks.push(...closeText(asm), ...closeReasoning(asm))\n const usage = isRecord(event.totalUsage) ? event.totalUsage : undefined\n if (usage) {\n const details = isRecord(usage.inputTokenDetails) ? usage.inputTokenDetails : undefined\n const totalInput = numberValue(usage.inputTokens) ?? 0\n const cacheRead = numberValue(details?.cacheReadTokens) ?? 0\n const cacheWrite = numberValue(details?.cacheWriteTokens) ?? 0\n // Harness TokenUsage counts are disjoint: uncached input only.\n const tokenUsage: TokenUsage = {\n inputTokens:\n numberValue(details?.noCacheTokens) ?? Math.max(0, totalInput - cacheRead - cacheWrite),\n outputTokens: numberValue(usage.outputTokens) ?? 0,\n cacheReadTokens: cacheRead,\n cacheWriteTokens: cacheWrite,\n }\n chunks.push({ type: 'usage', usage: tokenUsage })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(event.finishReason) })\n break\n }\n case 'error': {\n // Classification lives in streamErrorToLlmError, shared with the\n // Provider API transport's own in-band error member so the two cannot\n // drift: a stream error that is explicitly non-retryable, carries a\n // terminal marker (quota/plan/credits), or reports a non-retryable HTTP\n // status is a hard failure, and a context-window rejection is the\n // harness's CONTEXT_WINDOW_EXCEEDED (compact and retry). Anything else\n // is a transient mid-stream drop the retry policy should repeat.\n throw streamErrorToLlmError(event.error, stringValue(event.message))\n }\n }\n return chunks\n}\n\n/**\n * Handle one OpenAI-transport (`/provider/v1/chat/completions`) SSE event.\n * Same assembler contract as {@link handleCliEvent}; tool-call fragments\n * buffer on the assembler and flush at finish.\n */\nfunction handleOpenAIEvent(asm: BlockAssembler, event: unknown): StreamChunk[] {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n // The Provider API transport reports a mid-stream failure as an `error`\n // member of an SSE chunk rather than as an event type of its own. Ignoring\n // it — as this handler used to — let the stream end with no finish event, so\n // a context-window or quota rejection surfaced only as a generic\n // EMPTY_RESPONSE (which the retry policy repeats) and the real cause was\n // lost. Route it through the classifier the CLI transport uses.\n if (event.error !== undefined) throw streamErrorToLlmError(event.error, stringValue(event.message))\n const choices = event.choices\n if (!Array.isArray(choices) || choices.length === 0) {\n // A standalone usage chunk (some OpenAI-compatible servers send it\n // before [DONE]) still carries usage.\n if (event.usage !== undefined) {\n chunks.push({ type: 'usage', usage: mapOpenAIUsage(event.usage) })\n }\n return chunks\n }\n const choice = isRecord(choices[0]) ? choices[0] : {}\n const delta = isRecord(choice.delta) ? choice.delta : {}\n\n // Thinking text arrives under a different field per model family, and the\n // gateway does not normalize the spelling: DeepSeek answers with the scalar\n // `reasoning` PLUS an OpenRouter-shaped `reasoning_details` array, while\n // GLM/Qwen/Kimi answer with the DeepSeek-native `reasoning_content`. All\n // three are read here, in that order, so no family's thinking is dropped —\n // measured against the live API 2026-09-16 (see `MESSAGES_ONLY_MODELS` for\n // the same sweep's other finding). The `reasoning_details` branch is a\n // forward guard rather than a live path today: DeepSeek always sends the\n // scalar alongside it, so it only carries the text if that ever stops.\n const reasoningDelta =\n stringValue(delta.reasoning)\n ?? stringValue(delta.reasoning_content)\n ?? reasoningDetailsText(delta.reasoning_details)\n ?? ''\n if (reasoningDelta !== '') {\n chunks.push(...closeText(asm))\n if (asm.reasoningIndex < 0) {\n asm.reasoningIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.reasoningIndex, blockType: 'reasoning' })\n }\n asm.reasoningContent += reasoningDelta\n chunks.push({ type: 'reasoning-delta', index: asm.reasoningIndex, text: reasoningDelta })\n }\n\n const contentDelta = stringValue(delta.content) ?? ''\n if (contentDelta !== '') {\n chunks.push(...closeReasoning(asm))\n if (asm.textIndex < 0) {\n asm.textIndex = asm.nextIndex++\n chunks.push({ type: 'block-start', index: asm.textIndex, blockType: 'text' })\n }\n asm.textContent += contentDelta\n asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: contentDelta })\n }\n\n if (Array.isArray(delta.tool_calls)) {\n asm.sawContent = true\n for (const rawCall of delta.tool_calls) {\n if (!isRecord(rawCall)) continue\n const callIndex = numberValue(rawCall.index) ?? 0\n let existing = asm.openAiToolCalls.find((call) => call.index === callIndex)\n const fn = isRecord(rawCall.function) ? rawCall.function : undefined\n const id = stringValue(rawCall.id)\n const name = fn === undefined ? undefined : stringValue(fn.name)\n const argDelta = fn === undefined\n ? undefined\n : (stringValue(fn.arguments) ?? (fn.arguments === undefined ? '' : JSON.stringify(fn.arguments)))\n if (!existing) {\n existing = {\n index: callIndex,\n name: name ?? '',\n arguments: argDelta ?? '',\n }\n if (id !== undefined) existing.id = id\n asm.openAiToolCalls.push(existing)\n } else {\n if (id !== undefined && existing.id === undefined) existing.id = id\n if (name !== undefined && existing.name === '') existing.name = name\n if (argDelta !== undefined) existing.arguments += argDelta\n }\n }\n }\n\n if (choice.finish_reason !== undefined && choice.finish_reason !== null) {\n chunks.push(...closeText(asm), ...closeReasoning(asm), ...emitOpenAiToolCalls(asm))\n if (event.usage !== undefined) {\n chunks.push({ type: 'usage', usage: mapOpenAIUsage(event.usage) })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(choice.finish_reason) })\n }\n return chunks\n}\n\n/** Dispatch one parsed stream event to the active transport's handler. */\nfunction handleEvent(asm: BlockAssembler, protocol: CommandCodeProtocol, event: unknown): StreamChunk[] {\n return protocol === 'openai' ? handleOpenAIEvent(asm, event) : handleCliEvent(asm, event)\n}\n\n\n/**\n * Parse an HTTP `Retry-After` value (delay-seconds or an HTTP-date) into\n * milliseconds; undefined when absent or unparseable. An HTTP-date in the\n * past yields 0, which the caller drops (LlmError wants a positive delay).\n * A delay-seconds value whose millisecond product is not finite (e.g. `1e308`)\n * also yields undefined: LlmError validates its options and would otherwise\n * replace the provider failure with an internal construction error.\n */\nfunction parseRetryAfterMs(value: string | null | undefined, now = Date.now()): number | undefined {\n if (value === undefined || value === null) return undefined\n const trimmed = value.trim()\n if (trimmed === '') return undefined\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n const ms = seconds * 1000\n return Number.isFinite(ms) ? Math.round(ms) : undefined\n }\n const date = Date.parse(trimmed)\n if (!Number.isNaN(date)) return Math.max(0, date - now)\n return undefined\n}\n\n/**\n * Map a stream finish reason onto the harness taxonomy. The two transports\n * spell tool-calls differently (`tool-calls` on the CLI transport,\n * `tool_calls` on the OpenAI transport) but share every other reason, so\n * one function serves both — a new reason cannot drift between them.\n */\nfunction mapFinishReason(reason: unknown): FinishReason {\n if (reason === 'tool-calls' || reason === 'tool_calls') return { kind: 'tool-calls' }\n if (\n reason === 'length' ||\n reason === 'max_tokens' ||\n reason === 'max-tokens' ||\n reason === 'max_output_tokens'\n ) {\n return { kind: 'max-tokens' }\n }\n return { kind: 'stop' }\n}\n\n/**\n * True when a Provider API pre-stream rejection is Command Code's Go-plan\n * gate (`upgrade_required`). Only this exact class of rejection should fall\n * back to the CLI /alpha/generate transport; other 4xx/5xx must surface as\n * ordinary errors so real account/model problems are not masked.\n */\nfunction isUpgradeRequiredError(status: number, errText: string): boolean {\n if (status !== 403) return false\n const lower = errText.toLowerCase()\n if (lower.includes('upgrade_required')) return true\n if (lower.includes('go plan') && lower.includes('api access')) return true\n if (lower.includes('only plan without api access')) return true\n if (lower.includes('upgrade to goat or higher')) return true\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed)) {\n const error = isRecord(parsed.error) ? parsed.error : parsed\n const code = stringValue(error.code) ?? stringValue(error.type)\n if (code?.toLowerCase() === 'upgrade_required') return true\n const message = stringValue(error.message) ?? ''\n if (message.toLowerCase().includes('go plan') && message.toLowerCase().includes('api access')) return true\n }\n } catch {\n // Already handled via the plain-text substring checks above.\n }\n return false\n}\n\n/** Map an OpenAI Chat Completions usage payload to harness disjoint counts. */\nfunction mapOpenAIUsage(usage: unknown): TokenUsage {\n const source = isRecord(usage) ? usage : {}\n const promptTokens = numberValue(source.prompt_tokens) ?? 0\n const outputTokens = numberValue(source.completion_tokens) ?? 0\n const totalTokens = numberValue(source.total_tokens)\n const promptDetails = isRecord(source.prompt_tokens_details) ? source.prompt_tokens_details : undefined\n const cacheRead = numberValue(promptDetails?.cached_tokens) ?? 0\n const cacheWrite = numberValue(promptDetails?.cache_creation_input_tokens) ?? 0\n const completionDetails = isRecord(source.completion_tokens_details) ? source.completion_tokens_details : undefined\n const reasoningTokens = numberValue(completionDetails?.reasoning_tokens)\n const usageOut: TokenUsage = {\n inputTokens: Math.max(0, promptTokens - cacheRead - cacheWrite),\n outputTokens,\n cacheReadTokens: cacheRead,\n }\n if (cacheWrite > 0) usageOut.cacheWriteTokens = cacheWrite\n if (reasoningTokens !== undefined) usageOut.reasoningTokens = reasoningTokens\n if (totalTokens !== undefined) usageOut.totalTokens = totalTokens\n return usageOut\n}\n","/**\n * Locale copy for the `/commandcode` usage command and the friendly\n * image-gate error rewrite. Distinct from `./client/locales.ts` (the\n * settings-page namespace `settings.commandcode`): the command runs on the\n * Host and has no access to the client's `ctx.locale`, so the dictionaries\n * are exposed as plain constants for direct lookup; the resolver lives in\n * `pickCommandLocale()`. The image-gate wrapper also lives on the client\n * but is reached from a non-React path that has no `t` in scope, so the\n * same dictionaries serve both surfaces.\n *\n * zh is the source of truth for the key set; en must carry the exact same\n * keys — a mismatch is a compile error at the lookup site.\n */\n\n/** Active locale id recognized by the command and the image-gate wrapper. */\nexport type LocaleId = 'zh' | 'en'\n\n/** Dictionary keys used by the `/commandcode` command and the image-gate wrapper. */\nexport type CommandCodeCommandKey =\n | 'title' // top heading of a single-account report\n | 'accountTitle' // per-account heading in the multi-account view\n | 'accountSeparator' // rule between accounts in the multi-account view\n | 'activeBadge' // \"currently serving\" badge\n | 'invalidCredentialBadge' // mark for an account whose key is invalid\n | 'cooldownBadge' // mark for an account in rate-limit cooldown\n | 'rateLimitBadge' // mark when the pool has marked a key rate-limited\n | 'unconfigured' // one-account row when the slot has no key\n | 'blockedInvalidKey' // top-of-report block when the whole account is 401\n | 'blockedServiceUnavailable' // 5xx\n | 'blockedNetwork' // network unreachable\n | 'planLine' // \" 📦 套餐 {name}{status}{period}\"\n | 'planPeriodSuffix' // \" · 账期截止 {date}\" / \" · period ends {date}\"\n | 'usageHeader' // \"── 请求 ─────...\"\n | 'requestsLine' // \" 💬 请求 {n} 次 / 失败 {f} 成功率 {r}%\"\n | 'costLine' // \" 💰 花费 {money} ({credits} credits)\"\n | 'tokensLine' // \" 🔤 Token {in} 入 / {out} 出\"\n | 'creditsHeader' // \"── 信用 ─────...\"\n | 'monthlyLine' // \" 💳 月额度 {monthly} (已购 {purchased} / 赠送 {free})\"\n | 'barLine' // \" └ {bar} {pct}%\"\n | 'windowsHeader' // \"── 窗口用量 ─────...\"\n | 'fiveHourLine' // \" ⏱ 5 小时 {used} / {cap}{warn}\"\n | 'weeklyLine' // \" 📅 每周 {used} / {cap}{warn}\"\n | 'windowBarLine' // \" └ {bar} 重置 {when}\"\n | 'exceededWarning' // the trailing \" ⚠️ 超限!\" / \" ⚠️ exceeded!\"\n | 'resetSuffix' // \"重置 {when}\" (the suffix after the bar)\n | 'partialFailures' // \"⚠️ 部分端点失败: {list}\"\n | 'noData' // \"(no data — check your API key)\"\n | 'errorText' // \"Could not fetch Command Code usage: {message}\"\n\nexport const commandcodeCommand: Record<LocaleId, Record<CommandCodeCommandKey, string>> = {\n zh: {\n title: '📊 Command Code 用量{account}',\n accountTitle: '📊 {label}{badges}',\n accountSeparator: '────────────────────',\n activeBadge: ' ✅ 当前使用',\n invalidCredentialBadge: ' ⛔ 密钥无效',\n cooldownBadge: ' ⏳ 限额冷却中,重置 {when}',\n rateLimitBadge: ' ⏳ 已达限额(等待窗口探测)',\n unconfigured: ' (未配置 API 密钥)',\n blockedInvalidKey:\n '⛔ API 密钥无效或已过期 — 服务端拒绝了全部请求(401),请检查该账户的密钥配置',\n blockedServiceUnavailable:\n '⚠️ Command Code 服务暂时不可用(5xx),稍后重试',\n blockedNetwork:\n '⚠️ 无法连接 Command Code 服务 — 请检查网络或 API 地址',\n planLine: ' 📦 套餐 {name}{status}{period}',\n planPeriodSuffix: ' · 账期截止 {date}',\n usageHeader: '── 请求 ──────────────────────────────',\n requestsLine: ' 💬 请求 {n} 次 / 失败 {f} 成功率 {r}%',\n costLine: ' 💰 花费 {money} ({credits} credits)',\n tokensLine: ' 🔤 Token {in} 入 / {out} 出',\n creditsHeader: '── 信用 ──────────────────────────────',\n monthlyLine: ' 💳 月额度 {monthly} (已购 {purchased} / 赠送 {free})',\n barLine: ' └ {bar} {pct}%',\n windowsHeader: '── 窗口用量 ──────────────────────────',\n fiveHourLine: ' ⏱ 5 小时 {used} / {cap}{warn}',\n weeklyLine: ' 📅 每周 {used} / {cap}{warn}',\n windowBarLine: ' └ {bar} 重置 {when}',\n exceededWarning: ' ⚠️ 超限!',\n resetSuffix: '重置 {when}',\n partialFailures: '⚠️ 部分端点失败: {list}',\n noData: '(无数据 — 请检查 API 密钥)',\n errorText: '获取 Command Code 用量失败:{message}',\n },\n en: {\n title: '📊 Command Code usage{account}',\n accountTitle: '📊 {label}{badges}',\n accountSeparator: '────────────────────',\n activeBadge: ' ✅ active',\n invalidCredentialBadge: ' ⛔ invalid key',\n cooldownBadge: ' ⏳ cooling down, resets {when}',\n rateLimitBadge: ' ⏳ rate-limited (waiting for window probe)',\n unconfigured: ' (no API key configured)',\n blockedInvalidKey:\n '⛔ API key invalid or expired — the server rejected every request (401); check the key configured for this account',\n blockedServiceUnavailable:\n '⚠️ Command Code service temporarily unavailable (5xx); try again later',\n blockedNetwork:\n '⚠️ could not reach the Command Code service — check your network or the API base setting',\n planLine: ' 📦 Plan {name}{status}{period}',\n planPeriodSuffix: ' · period ends {date}',\n usageHeader: '── Requests ──────────────────────────',\n requestsLine: ' 💬 Requests {n} / failed {f} success rate {r}%',\n costLine: ' 💰 Spend {money} ({credits} credits)',\n tokensLine: ' 🔤 Tokens {in} in / {out} out',\n creditsHeader: '── Credits ───────────────────────────',\n monthlyLine: ' 💳 Monthly {monthly} (purchased {purchased} / free {free})',\n barLine: ' └ {bar} {pct}%',\n windowsHeader: '── Window usage ──────────────────────',\n fiveHourLine: ' ⏱ 5-hour {used} / {cap}{warn}',\n weeklyLine: ' 📅 Weekly {used} / {cap}{warn}',\n windowBarLine: ' └ {bar} resets {when}',\n exceededWarning: ' ⚠️ exceeded!',\n resetSuffix: 'resets {when}',\n partialFailures: '⚠️ some endpoints failed: {list}',\n noData: '(no data — check your API key)',\n errorText: 'Could not fetch Command Code usage: {message}',\n },\n}\n\n/**\n * Resolve the active locale for a Host-side command run.\n *\n * Priority: explicit `override` (from `Config.lang`) → `LC_ALL` → `LANG` →\n * the conventional fallback (`'zh'`, matching the existing single-language\n * behavior so unconfigured deployments keep their current output).\n *\n * The values are matched on the leading tag only — `zh_CN.UTF-8`,\n * `zh-Hans`, `zh` all map to `'zh'`; everything starting with `en` maps to\n * `'en'`; anything else falls back to `'zh'` (a non-`en` shell that\n * already has Chinese in the terminal is the closest sensible default;\n * a Western shell that happens to be neither keeps the existing Chinese\n * output rather than swapping to half-translated English).\n */\nexport function pickCommandLocale(\n override: string | undefined,\n env: Readonly<Record<string, string | undefined>> = process.env as Record<string, string | undefined>,\n): LocaleId {\n if (override === 'zh' || override === 'en') return override\n const raw = env.LC_ALL ?? env.LANG ?? ''\n const tag = raw.toLowerCase().split(/[._-]/)[0] ?? ''\n if (tag === 'en') return 'en'\n return 'zh'\n}\n\n/** Look up a key in the active locale, with an internal en fallback. */\nexport function commandCopy(locale: LocaleId, key: CommandCodeCommandKey): string {\n return commandcodeCommand[locale][key] ?? commandcodeCommand.en[key] ?? key\n}\n","/**\n * `/commandcode` slash command — account usage dashboard.\n *\n * /commandcode show account, usage, and credit state\n * /commandcode status same as bare `/commandcode`\n *\n * Backed by the Command Code account endpoints the official CLI uses\n * (`/alpha/whoami`, `/alpha/usage/summary`, `/alpha/billing/credits`),\n * exposed through `CommandCodeAdapter.getUsage()`.\n *\n * The command is Host-side and has no access to the client's `ctx.locale`;\n * the active locale is resolved through `deps.getLocale()` (supplied by the\n * plugin entry from `Config.lang` and the shell's `LC_ALL`/`LANG`, defaulting\n * to `zh`). All user-facing copy lives in `./command-locales.ts`; a missing\n * key in one dictionary falls back to the `en` copy rather than dropping\n * text.\n *\n * @module dsh-commandcode-provider/commands\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only import that loads the module augmentation (`ctx.commands`).\nimport type { CommandDefinition } from '@deepseek-ai/dsh-commands'\nimport { CommandCodeAdapter } from './adapter.ts'\nimport type { CommandCodeConnectionOptions, CommandCodeUsageReport } from './adapter.ts'\nimport type { CommandCodeAccountUsage, CommandCodeAccountsReport } from './usage-wire.ts'\nimport { commandCopy, type LocaleId } from './command-locales.ts'\n\n/** Everything the command needs beyond the adapter itself. */\nexport interface CommandCodeCommandDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** The registered adapter (for getUsage / listModels). */\n adapter: CommandCodeAdapter<C>\n /**\n * Multi-account report source (wired by the plugin entry). Absent in\n * programmatic setups, the command falls back to a single\n * `adapter.getUsage()` report.\n */\n reports?: () => Promise<CommandCodeAccountsReport>\n /**\n * Resolve the active locale for one command run. The plugin entry wires\n * this from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent in\n * programmatic setups (notably the existing test), the command renders\n * with the default locale (`'zh'`) — historically the only language the\n * command ever shipped in.\n */\n getLocale?: () => LocaleId\n}\n\n// ---------------------------------------------------------------------------\n// Number / time formatting (locale-independent; the locale only changes\n// the surrounding labels)\n// ---------------------------------------------------------------------------\n\n/** Format a dollar amount. */\nfunction money(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\n/** Format a dollar amount compactly (2 decimals). */\nfunction moneyShort(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\n/** Format a large token count compactly (1.9M style). */\nfunction tokensCompact(value: number): string {\n if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`\n if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`\n if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`\n return String(value)\n}\n\n/**\n * Format a success-rate percentage (already in percent units): at most two\n * decimals, trailing zeros trimmed — mirrors `formatSuccessRate` in\n * `./client/usage.ts`, which the settings card uses.\n */\nfunction successRateText(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** Format a millis timestamp as a local date; `n/a` when unset. */\nfunction resetLabel(ms: number): string {\n if (ms <= 0) return 'n/a'\n return new Date(ms).toLocaleString()\n}\n\n/**\n * A 10-cell horizontal bar: `██████████` for 100%, `███░░░░░░░` for ~33%.\n * Handles caps of 0 (no limit) and out-of-range values.\n */\nfunction bar(used: number, cap: number): string {\n if (cap <= 0) return '—'\n const ratio = Math.max(0, Math.min(1, used / cap))\n const filled = Math.round(ratio * 10)\n return '█'.repeat(filled) + '░'.repeat(10 - filled)\n}\n\n// ---------------------------------------------------------------------------\n// Report rendering\n// ---------------------------------------------------------------------------\n\n/** Render one account's rotation mark / cooldown as a short badge. */\nfunction markLabel(entry: CommandCodeAccountUsage, locale: LocaleId): string {\n if (entry.mark === 'invalid-credential') return commandCopy(locale, 'invalidCredentialBadge')\n if (entry.cooldownUntil > 0) {\n return commandCopy(locale, 'cooldownBadge').replace('{when}', resetLabel(entry.cooldownUntil))\n }\n if (entry.mark === 'rate-limit') return commandCopy(locale, 'rateLimitBadge')\n return ''\n}\n\n/** Render the usage report as a structured, aligned, bar-chart text view. */\nfunction renderReport(report: CommandCodeUsageReport, locale: LocaleId, title?: string): string {\n const lines: string[] = []\n const account = report.account ? ` (${report.account.userName || report.account.name})` : ''\n\n lines.push(\n title ?? commandCopy(locale, 'title').replace('{account}', account),\n '',\n )\n\n // A total failure names its cause up front; the per-endpoint failure list\n // at the bottom would bury it.\n if (report.blocked === 'invalid-key') {\n lines.push(commandCopy(locale, 'blockedInvalidKey'), '')\n } else if (report.blocked === 'service-unavailable') {\n lines.push(commandCopy(locale, 'blockedServiceUnavailable'), '')\n } else if (report.blocked === 'network') {\n lines.push(commandCopy(locale, 'blockedNetwork'), '')\n }\n\n if (report.plan && report.plan.name !== '') {\n const p = report.plan\n const status = p.status !== '' && p.status !== 'active' ? ` (${p.status})` : ''\n const period = p.currentPeriodEnd > 0\n ? commandCopy(locale, 'planPeriodSuffix').replace('{date}', new Date(p.currentPeriodEnd).toLocaleDateString())\n : ''\n lines.push(commandCopy(locale, 'planLine')\n .replace('{name}', p.name)\n .replace('{status}', status)\n .replace('{period}', period), '')\n }\n\n if (report.usage) {\n const u = report.usage\n lines.push(\n commandCopy(locale, 'usageHeader'),\n commandCopy(locale, 'requestsLine')\n .replace('{n}', String(u.completedCount))\n .replace('{f}', String(u.failedCount))\n .replace('{r}', successRateText(u.successRate)),\n commandCopy(locale, 'costLine')\n .replace('{money}', money(u.totalCost))\n .replace('{credits}', moneyShort(u.totalCredits)),\n commandCopy(locale, 'tokensLine')\n .replace('{in}', tokensCompact(u.totalTokensIn))\n .replace('{out}', tokensCompact(u.totalTokensOut)),\n '',\n )\n }\n\n if (report.credits) {\n const c = report.credits\n const balanceTotal = c.monthlyCredits + c.purchasedCredits\n const ratioKnown = c.monthlyReported !== false && c.purchasedReported !== false && balanceTotal > 0\n lines.push(\n commandCopy(locale, 'creditsHeader'),\n commandCopy(locale, 'monthlyLine')\n .replace('{monthly}', (c.monthlyReported === false ? '—' : moneyShort(c.monthlyCredits)))\n .replace('{purchased}', (c.purchasedReported === false ? '—' : moneyShort(c.purchasedCredits)))\n .replace('{free}', (c.freeReported === false ? '—' : moneyShort(c.freeCredits))),\n ...(ratioKnown ? [commandCopy(locale, 'barLine')\n .replace('{bar}', bar(c.monthlyCredits, balanceTotal))\n .replace('{pct}', ((c.monthlyCredits / balanceTotal) * 100).toFixed(0))] : []),\n '',\n )\n // Only the windows the endpoint actually reported: an unlimited account\n // reports none, and printing two zeroed rows for it would invent limits.\n const windowLines: string[] = []\n if (c.fiveHour !== undefined) {\n windowLines.push(\n commandCopy(locale, 'fiveHourLine')\n .replace('{used}', moneyShort(c.fiveHour.used))\n .replace('{cap}', moneyShort(c.fiveHour.cap))\n .replace('{warn}', c.fiveHour.exceeded ? commandCopy(locale, 'exceededWarning') : ''),\n commandCopy(locale, 'windowBarLine')\n .replace('{bar}', bar(c.fiveHour.used, c.fiveHour.cap))\n .replace('{when}', resetLabel(c.fiveHour.resetAt)),\n )\n }\n if (c.weekly !== undefined) {\n windowLines.push(\n commandCopy(locale, 'weeklyLine')\n .replace('{used}', moneyShort(c.weekly.used))\n .replace('{cap}', moneyShort(c.weekly.cap))\n .replace('{warn}', c.weekly.exceeded ? commandCopy(locale, 'exceededWarning') : ''),\n commandCopy(locale, 'windowBarLine')\n .replace('{bar}', bar(c.weekly.used, c.weekly.cap))\n .replace('{when}', resetLabel(c.weekly.resetAt)),\n )\n }\n if (windowLines.length > 0) lines.push(commandCopy(locale, 'windowsHeader'), ...windowLines, '')\n }\n\n if (report.failures.length > 0) {\n lines.push(commandCopy(locale, 'partialFailures').replace('{list}', report.failures.join('; ')), '')\n }\n if (!report.account && !report.usage && !report.credits) {\n lines.push(commandCopy(locale, 'noData'), '')\n }\n\n return lines.join('\\n').trimEnd()\n}\n\n/** The one registered `/commandcode` command. */\nexport function commandDefinition<C extends CommandCodeConnectionOptions>(\n deps: CommandCodeCommandDeps<C>,\n): CommandDefinition {\n const { adapter } = deps\n return {\n name: 'commandcode',\n description: 'Command Code account usage dashboard',\n input: { hint: '[status]' },\n handler: async () => {\n const locale: LocaleId = deps.getLocale?.() ?? 'zh'\n try {\n if (deps.reports !== undefined) {\n const { accounts } = await deps.reports()\n const sections = accounts.map((entry) => {\n const badges = `${entry.active ? commandCopy(locale, 'activeBadge') : ''}${markLabel(entry, locale)}`\n const title = commandCopy(locale, 'accountTitle')\n .replace('{label}', entry.label)\n .replace('{badges}', badges)\n if (!entry.configured) return `${title}\\n\\n${commandCopy(locale, 'unconfigured')}`\n return renderReport(entry.report, locale, title)\n })\n return { kind: 'success', text: sections.join(`\\n\\n${commandCopy(locale, 'accountSeparator')}\\n\\n`) }\n }\n const report = await adapter.getUsage()\n return { kind: 'success', text: renderReport(report, locale) }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error)\n return {\n kind: 'error',\n text: commandCopy(locale, 'errorText').replace('{message}', message),\n }\n }\n },\n }\n}\n\n/** Register the command on `ctx.commands` (called from the plugin entry). */\nexport function applyCommands<C extends CommandCodeConnectionOptions>(\n ctx: Context,\n deps: CommandCodeCommandDeps<C>,\n): void {\n ctx.commands.register(commandDefinition(deps))\n}\n","/**\n * Shared boundary-validation and Remote-descriptor plumbing for the plugin's\n * hand-rolled Typert wire contracts (`commandcode/report`, `commandcode/models`,\n * `commandcode/login*`).\n *\n * Every Remote this plugin serves crosses the Typert Gateway with a strict\n * result schema: the Host half registers a descriptor against a Cordis service\n * (`src/usage-remote.ts`) and the browser half mounts the matching contribution\n * on `ctx.remote` (`src/client/index.ts`). The wire contract is deliberately\n * dependency-free so the client bundle can inline it — a pure-TS helper module\n * imported by the wire files keeps it that way while removing the schema\n * helpers and descriptor boilerplate they used to duplicate.\n *\n * @module dsh-commandcode-provider/wire-shared\n */\n\nimport type { InvocationDescriptor, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\n\n/** The npm package identity every contribution and descriptor claims. */\nexport const REMOTE_PACKAGE = '@mars-sea/dsh-commandcode-provider'\n\n/** The Cordis service key the Gateway resolves every Command Code Remote from. */\nexport const REMOTE_SERVICE = 'commandcodeUsage'\n\n/** The wire namespace all Command Code endpoints share. */\nexport const REMOTE_NAMESPACE = 'commandcode'\n\n/** The read/validate helpers one boundary codec needs. */\nexport interface BoundaryValidator {\n /** Reject one boundary value with a field-naming error. */\n reject(field: string): never\n /** Narrow an unknown value to a plain record, or reject. */\n record(value: unknown, field: string): Record<string, unknown>\n /** Read one required string field (`field` is the dotted error label). */\n stringField(source: Record<string, unknown>, key: string, field: string): string\n /** Read one required finite number field (`field` is the dotted error label). */\n numberField(source: Record<string, unknown>, key: string, field: string): number\n /** Read one required boolean field (`field` is the dotted error label). */\n booleanField(source: Record<string, unknown>, key: string, field: string): boolean\n}\n\n/**\n * Build the validator helpers one endpoint uses. `prefix` names the\n * endpoint in the rejection message (e.g. `commandcode/report result:`), so\n * each wire file keeps its own diagnostic phrasing while sharing the helper\n * bodies.\n *\n * The helpers return the reject call directly in the failure branch: since\n * `reject` is typed `never`, the ternary's union collapses to the success type\n * without relying on TypeScript's control-flow analysis of a never-returning\n * call (which only recognizes function declarations, not the destructured\n * arrow `reject` callers receive from this factory).\n */\nexport function makeBoundaryValidator(prefix: string): BoundaryValidator {\n const reject = (field: string): never => {\n throw new TypeError(`${prefix} invalid ${field}`)\n }\n const record = (value: unknown, field: string): Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : reject(field)\n const stringField = (source: Record<string, unknown>, key: string, field: string): string =>\n typeof source[key] === 'string' ? source[key] as string : reject(field)\n const numberField = (source: Record<string, unknown>, key: string, field: string): number =>\n typeof source[key] === 'number' && Number.isFinite(source[key] as number)\n ? source[key] as number\n : reject(field)\n const booleanField = (source: Record<string, unknown>, key: string, field: string): boolean =>\n typeof source[key] === 'boolean' ? source[key] as boolean : reject(field)\n return { reject, record, stringField, numberField, booleanField }\n}\n\n/**\n * One strict result codec written in BOTH Typert generations' vocabulary.\n *\n * The protocol changed shape under the same `mode: 'strict'` tag, and each\n * engine generation validates the member it knows while ignoring the other:\n *\n * - Every RELEASED engine (0.1.2-rc.1 … 0.1.6-alpha.1, i.e. all 21 published\n * versions) declares `schema: TypertSchema`; its registry throws\n * `typert: <subject> strict codec has no parse() method` unless\n * `codec.schema.parse` is a function, and its Gateway validates with\n * `codec.schema.parse(value)`.\n * - master after commit `e459e3263` (`perf(typert): materialize generated\n * schemas on first use`) replaced that member with the lazy factory\n * `create: () => TypertSchema`, throws `typert: <subject> strict codec has no\n * create() factory` unless `typeof codec.create === 'function'`, and\n * validates with `codec.create().parse(value)`.\n *\n * So the one codec carries both, which is a version-agnostic fix rather than a\n * probe: neither validator inspects the member it does not know, and the\n * member the running engine does not read is inert. Carrying only one of them\n * breaks half the engines the manifest declares compatible — that is exactly\n * issue #49, whose one-line patch (`schema` → `create`) would have fixed\n * unreleased master by breaking every install that exists today.\n *\n * This interface also stands in for the local typings: no published\n * `@deepseek-ai/dsh-typert-protocol` carries `create` yet, so the two-member\n * shape is stated here and handed to the protocol type by assignment (the\n * older generation's `InvocationDescriptor` requires `schema` and ignores the\n * extra `create`; the newer one requires `create`, so neither needs a cast).\n */\ninterface StrictResultCodec<Output> {\n readonly mode: 'strict'\n readonly typeSymbol: string\n /** Read by released engines (≤ `0.1.6-alpha.1`). */\n readonly schema: TypertSchema<Output>\n /** Read by engines after `e459e3263` — the lazy replacement for `schema`. */\n readonly create: () => TypertSchema<Output>\n}\n\n/**\n * Build one strict invocation descriptor. Every Command Code Remote shares the\n * `commandcode` namespace, the `commandcodeUsage` service, and a strict\n * `mode: 'strict'` result — only the endpoint, method, result type symbol, and\n * schema differ — so the boilerplate lives here once and each endpoint supplies\n * only its own facts.\n */\nexport function makeRemoteDescriptor<Output>(\n endpoint: string,\n method: string,\n typeSymbol: string,\n schema: TypertSchema<Output>,\n): InvocationDescriptor {\n // Both members name the SAME hand-rolled schema: `create()` is the newer\n // generation's lazy accessor for what the older one reads directly, so the\n // two generations can never validate against different rules. Defined as a\n // value (not inline) so the older typings' excess-property check does not\n // reject the member they do not declare.\n const result: StrictResultCodec<Output> = {\n mode: 'strict',\n typeSymbol,\n schema,\n create: () => schema,\n }\n return {\n id: `${REMOTE_PACKAGE}#${endpoint}`,\n service: REMOTE_SERVICE,\n namespace: REMOTE_NAMESPACE,\n method,\n invocation: { kind: 'direct' },\n parameters: [],\n result,\n }\n}","/**\n * Wire contract for the Command Code account-usage Remote\n * (`commandcode/report`).\n *\n * The settings page renders the same account/usage/credit facts the\n * `/commandcode` command prints, but the browser never holds the API key —\n * the report must be produced Host-side and cross the Connection RPC carrier.\n * The harness exposes plugin-defined Host methods through the Typert Gateway:\n * the Host half registers a strict invocation descriptor against a Cordis\n * service (`src/usage-remote.ts`), and the browser half mounts the matching\n * Remote contribution on `ctx.remote` (`src/client/index.ts`).\n *\n * This module is the single source both halves share: the result validator\n * (a hand-rolled {@link TypertSchema}, so neither half needs a schema library)\n * and the exact descriptor object, so the endpoint can never drift apart.\n * It is deliberately dependency-free — the client bundle inlines it, and only\n * `import type` edges leave it (erased at build). The boundary-validator\n * helpers and the descriptor boilerplate live in `./wire-shared.ts`, shared\n * with the login wire contract.\n *\n * @module dsh-commandcode-provider/usage-wire\n */\n\nimport type { CommandCodeCredits, CommandCodeUsageReport, UsageBlockReason } from './adapter.ts'\n\nexport type { CommandCodeUsageReport, UsageBlockReason }\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** One account's usage entry in the multi-account report. */\nexport interface CommandCodeAccountUsage {\n /** Stable slot id (`default`, `account-2`, …). */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Whether an API key resolved for this account. */\n configured: boolean\n /** Whether this account currently serves requests (first usable slot). */\n active: boolean\n /** Rotation mark: `''` (usable), `'rate-limit'`, or `'invalid-credential'`. */\n mark: string\n /** Known cooldown end in millis; 0 when unknown or not cooling down. */\n cooldownUntil: number\n /** The per-account report; `failures`-only when the fetch itself failed. */\n report: CommandCodeUsageReport\n}\n\n/** The settings page's account card data: one entry per configured account. */\nexport interface CommandCodeAccountsReport {\n accounts: CommandCodeAccountUsage[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const USAGE_REMOTE_PACKAGE = REMOTE_PACKAGE\n\n/** Canonical `<namespace>/<method>` endpoint of the usage report Remote. */\nexport const USAGE_REPORT_ENDPOINT = 'commandcode/report'\n\n/**\n * The shared read/validate helpers for the usage report endpoint, prefixed\n * so rejection messages name the offending boundary.\n */\nconst { reject, record, stringField, numberField, booleanField } =\n makeBoundaryValidator('commandcode/report result:')\n\n/** Validate one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one quota window, or undefined when the frame carries no such window.\n *\n * The distinction is load-bearing at this boundary: an ABSENT window means the\n * billing endpoint reported none (an unlimited plan), while a present block with\n * `cap: 0` means uncapped spend that was really reported. Collapsing the two\n * would draw a zeroed quota row for an account that has no such limit.\n */\nfunction windowLimit(\n value: unknown,\n field: string,\n): { used: number; cap: number; exceeded: boolean; resetAt: number } | undefined {\n if (value === undefined) return undefined\n const source = record(value, field)\n return {\n used: numberField(source, 'used', `${field}.used`),\n cap: numberField(source, 'cap', `${field}.cap`),\n exceeded: booleanField(source, 'exceeded', `${field}.exceeded`),\n resetAt: numberField(source, 'resetAt', `${field}.resetAt`),\n }\n}\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeUsageReport}.\n * Optional sections stay optional; every present field is shape-checked so a\n * malformed frame fails the boundary instead of rendering garbage.\n */\nfunction parseUsageReport(value: unknown): CommandCodeUsageReport {\n const source = record(value, 'report')\n const failures = source.failures\n if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== 'string')) reject('failures')\n const report: CommandCodeUsageReport = { failures: failures as string[] }\n\n if (source.blocked !== undefined) {\n const blocked = source.blocked\n // Positive check: TS's never-return control-flow analysis only recognizes\n // function declarations, not the factory's destructured-arrow `reject`, so\n // narrow `blocked` in the positive branch instead.\n if (blocked === 'invalid-key' || blocked === 'service-unavailable' || blocked === 'network') {\n report.blocked = blocked\n } else {\n reject('blocked')\n }\n }\n\n if (source.account !== undefined) {\n const account = record(source.account, 'account')\n report.account = {\n id: stringField(account, 'id', 'account.id'),\n name: stringField(account, 'name', 'account.name'),\n userName: stringField(account, 'userName', 'account.userName'),\n }\n }\n\n if (source.usage !== undefined) {\n const usage = record(source.usage, 'usage')\n report.usage = {\n totalCount: numberField(usage, 'totalCount', 'usage.totalCount'),\n totalCost: numberField(usage, 'totalCost', 'usage.totalCost'),\n successRate: numberField(usage, 'successRate', 'usage.successRate'),\n completedCount: numberField(usage, 'completedCount', 'usage.completedCount'),\n failedCount: numberField(usage, 'failedCount', 'usage.failedCount'),\n totalTokensIn: numberField(usage, 'totalTokensIn', 'usage.totalTokensIn'),\n totalTokensOut: numberField(usage, 'totalTokensOut', 'usage.totalTokensOut'),\n totalCredits: numberField(usage, 'totalCredits', 'usage.totalCredits'),\n periodBasis: stringField(usage, 'periodBasis', 'usage.periodBasis'),\n }\n }\n\n if (source.credits !== undefined) {\n const credits = record(source.credits, 'credits')\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberField(credits, 'monthlyCredits', 'credits.monthlyCredits'),\n purchasedCredits: numberField(credits, 'purchasedCredits', 'credits.purchasedCredits'),\n freeCredits: numberField(credits, 'freeCredits', 'credits.freeCredits'),\n }\n // OPTIONAL on the wire: a Host half that predates this field serves the\n // scalar 0 for an omitted balance, which cannot be told from a real zero.\n // An explicit `false` therefore means \"not reported\" and the panel keeps the\n // figure off the dashboard; an absent flag (an older Host) stays unset and\n // is read as \"assume reported\", so a real balance is not lost cross-version.\n // A PRESENT value must still be a boolean, so a malformed frame is rejected\n // here rather than coerced.\n if (credits.monthlyReported !== undefined) {\n parsed.monthlyReported = booleanField(credits, 'monthlyReported', 'credits.monthlyReported')\n }\n for (const flag of ['purchasedReported', 'freeReported'] as const) {\n if (credits[flag] !== undefined) parsed[flag] = booleanField(credits, flag, `credits.${flag}`)\n }\n // Absent means the endpoint reported no such window. The window parsers\n // return undefined for an absent block, and an optional member is only set\n // when it was really there.\n const fiveHour = windowLimit(credits.fiveHour, 'credits.fiveHour')\n const weekly = windowLimit(credits.weekly, 'credits.weekly')\n if (fiveHour !== undefined) parsed.fiveHour = fiveHour\n if (weekly !== undefined) parsed.weekly = weekly\n report.credits = parsed\n }\n\n if (source.plan !== undefined) {\n const plan = record(source.plan, 'plan')\n const monthly = plan.monthlyCredits\n if (monthly !== null && (typeof monthly !== 'number' || !Number.isFinite(monthly))) reject('plan.monthlyCredits')\n report.plan = {\n planId: stringField(plan, 'planId', 'plan.planId'),\n name: stringField(plan, 'name', 'plan.name'),\n status: stringField(plan, 'status', 'plan.status'),\n monthlyCredits: monthly as number | null,\n currentPeriodEnd: numberField(plan, 'currentPeriodEnd', 'plan.currentPeriodEnd'),\n }\n }\n\n return report\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeAccountUsage}. */\nfunction parseAccountUsage(value: unknown): CommandCodeAccountUsage {\n const source = record(value, 'account')\n return {\n id: stringField(source, 'id', 'account.id'),\n label: stringField(source, 'label', 'account.label'),\n configured: booleanField(source, 'configured', 'account.configured'),\n active: booleanField(source, 'active', 'account.active'),\n mark: stringField(source, 'mark', 'account.mark'),\n cooldownUntil: numberField(source, 'cooldownUntil', 'account.cooldownUntil'),\n report: parseUsageReport(source.report),\n }\n}\n\n/** Parse the wire result into a {@link CommandCodeAccountsReport}. */\nfunction parseAccountsReport(value: unknown): CommandCodeAccountsReport {\n const source = record(value, 'result')\n const accounts = source.accounts\n if (Array.isArray(accounts)) {\n return { accounts: accounts.map(parseAccountUsage) }\n }\n return reject('accounts')\n}\n\n/**\n * The strict result codec both halves attach to the descriptor. Hand-rolled:\n * the client bundle may not require a schema library, and `TypertSchema` is\n * deliberately minimal so one `parse` function satisfies it.\n */\nexport const usageReportSchema: TypertSchema<CommandCodeAccountsReport> = {\n parse: parseAccountsReport,\n}\n\n/**\n * The one invocation descriptor, shared verbatim by the Host registration and\n * the Client mount. `service` names the Cordis key the Gateway resolves the\n * receiver from; `namespace`/`method` name the wire endpoint.\n */\nexport const USAGE_REPORT_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeAccountsReport>(\n USAGE_REPORT_ENDPOINT,\n 'report',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeAccountsReport`,\n usageReportSchema,\n )\n\n/** The Host-face contribution registered on `ctx.typert`. */\nexport const USAGE_HOST_CONTRIBUTION = {\n package: USAGE_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // 0.1.2's Typert registry requires every Host contribution to carry its\n // reflection model. This hand-written Remote deliberately has no generated\n // reflection exports, so use the official empty-model form rather than a\n // cast that leaves registry inspection with `model: undefined`.\n model: { services: [], events: [], objects: [] },\n invocations: [USAGE_REPORT_DESCRIPTOR],\n}\n\n/** The Client-face contribution mounted on `ctx.remote`. */\nexport const USAGE_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [USAGE_REPORT_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog Remote (`commandcode/models`)\n// ---------------------------------------------------------------------------\n\n/** One catalog entry the settings page's model editors offer. */\nexport interface CommandCodeCatalogModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n /**\n * Minimum plan-tier key for this model (a `KNOWN_PLANS` value: `go`,\n * `goat`, `pro`, `provider`, `max`), or undefined for models outside the\n * snapshot. The settings page groups the model-editor dropdowns under\n * tier headings from this — the browser cannot import the Host's\n * capability snapshot, so the Host stamps it per entry.\n */\n tier?: string\n}\n\n/** The model-catalog Remote result: the full catalog, sorted for picking. */\nexport interface CommandCodeCatalog {\n models: CommandCodeCatalogModel[]\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the model-catalog Remote. */\nexport const MODELS_ENDPOINT = 'commandcode/models'\n\n/**\n * The shared read/validate helpers for the model-catalog endpoint — a\n * separate instance so catalog boundary errors name `commandcode/models`,\n * not the report endpoint.\n */\nconst {\n record: catalogRecord,\n stringField: catalogString,\n} = makeBoundaryValidator('commandcode/models result:')\n\n/** Parse one untrusted boundary value into a {@link CommandCodeCatalogModel}. */\nfunction parseCatalogModel(value: unknown): CommandCodeCatalogModel {\n const source = catalogRecord(value, 'model')\n const model: CommandCodeCatalogModel = {\n id: catalogString(source, 'id', 'model.id'),\n name: catalogString(source, 'name', 'model.name'),\n }\n // Tier is optional on the wire (older Hosts predate it); a present\n // non-string is a contract violation, not a silent drop.\n if (source.tier !== undefined) {\n model.tier = catalogString(source, 'tier', 'model.tier')\n }\n return model\n}\n\n/** Parse the wire result into a {@link CommandCodeCatalog}. */\nfunction parseCatalog(value: unknown): CommandCodeCatalog {\n const source = catalogRecord(value, 'result')\n const models = source.models\n if (Array.isArray(models)) {\n return { models: models.map(parseCatalogModel) }\n }\n throw new TypeError('commandcode/models result: invalid models')\n}\n\n/** The strict result codec for the model-catalog Remote. */\nexport const modelsSchema: TypertSchema<CommandCodeCatalog> = {\n parse: parseCatalog,\n}\n\n/**\n * The model-catalog invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the usage report.\n */\nexport const MODELS_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeCatalog>(\n MODELS_ENDPOINT,\n 'models',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeCatalog`,\n modelsSchema,\n )\n\n/** The Client-face contribution for the model-catalog endpoint. */\nexport const MODELS_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [MODELS_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model price table Remote (`commandcode/prices`)\n// ---------------------------------------------------------------------------\n\n/**\n * One model's per-token rates, in USD per 1,000,000 tokens — the unit the\n * official pricing page publishes in.\n */\nexport interface CommandCodeModelRates {\n /** Uncached (billed) input tokens. */\n inputCost: number\n /** Completion tokens. */\n outputCost: number\n /** Input tokens served from the provider's cache. */\n cacheReadCost: number\n /**\n * Input tokens written into the provider's cache. Present for a minority of\n * models — the page publishes no cache-write rate for the rest, whose\n * cache-write tokens are therefore UNPRICED. Do not substitute a multiple of\n * the input rate for a missing value.\n */\n cacheWriteCost?: number\n}\n\n/** One whole-request context band; maxContext is inclusive, absent on the last band. */\nexport interface CommandCodeContextTier extends CommandCodeModelRates {\n maxContext?: number\n}\n\n/** One model's rates plus the peak-hour override for time-of-day models. */\nexport interface CommandCodeModelPrice extends CommandCodeModelRates {\n /**\n * Lookup key: the catalog model id when a catalog model maps to this row,\n * otherwise the pricing page's own slug. A session reports catalog ids, so\n * this is the primary key the browser looks up by.\n */\n id: string\n /** The pricing page's slug for this row — the secondary lookup key. */\n slug: string\n /**\n * Rates charged inside the peak windows. The row's own top-level rates are\n * the off-peak rates, so a row WITH this block is time-of-day priced and a\n * row without it is flat-priced.\n */\n peak?: CommandCodeModelRates\n contextTiers?: CommandCodeContextTier[]\n /**\n * Whether the model costs nothing on every plan right now (a free deal or a\n * `:free` catalog variant). Served explicitly at zero rates so a surface can\n * say \"free\" rather than showing nothing.\n */\n free?: boolean\n}\n\n/** The price-table Remote result: every known model's rates. */\nexport interface CommandCodePriceTable {\n /**\n * Every priced model, keyed by {@link CommandCodeModelPrice.id} (catalog id\n * first, pricing slug as the fallback) and carrying its slug as a second\n * lookup key. A model absent from this list has no known price and must\n * render no cost at all rather than a guess.\n */\n models: CommandCodeModelPrice[]\n /**\n * Peak-pricing windows as `[startHour, endHour)` in UTC, end-exclusive,\n * applying Monday–Friday only. Shipped with the table so the browser prices\n * against the Host snapshot's schedule instead of restating it.\n */\n peakHours: Array<[number, number]>\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the price-table Remote. */\nexport const PRICES_ENDPOINT = 'commandcode/prices'\n\n/**\n * The shared read/validate helpers for the price-table endpoint — its own\n * instance so price boundary errors name `commandcode/prices`.\n */\nconst {\n reject: priceReject,\n record: priceRecord,\n stringField: priceString,\n numberField: priceNumber,\n booleanField: priceBoolean,\n} = makeBoundaryValidator('commandcode/prices result:')\n\n/** Parse one rate block (`rates`, or a model's `peak` override). */\nfunction parseRates(source: Record<string, unknown>, field: string): CommandCodeModelRates {\n const rates: CommandCodeModelRates = {\n inputCost: priceNumber(source, 'inputCost', `${field}.inputCost`),\n outputCost: priceNumber(source, 'outputCost', `${field}.outputCost`),\n cacheReadCost: priceNumber(source, 'cacheReadCost', `${field}.cacheReadCost`),\n }\n // Optional on the wire: only a minority of models publish a cache-write\n // rate, and a present non-number is a contract violation rather than a\n // silent zero.\n if (source.cacheWriteCost !== undefined) {\n rates.cacheWriteCost = priceNumber(source, 'cacheWriteCost', `${field}.cacheWriteCost`)\n }\n return rates\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeModelPrice}. */\nfunction parseModelPrice(value: unknown): CommandCodeModelPrice {\n const source = priceRecord(value, 'model')\n const price: CommandCodeModelPrice = {\n id: priceString(source, 'id', 'model.id'),\n slug: priceString(source, 'slug', 'model.slug'),\n ...parseRates(source, 'model'),\n }\n if (source.peak !== undefined) price.peak = parseRates(priceRecord(source.peak, 'model.peak'), 'model.peak')\n if (source.contextTiers !== undefined) {\n if (!Array.isArray(source.contextTiers) || source.contextTiers.length === 0) priceReject('contextTiers')\n let previous = 0\n price.contextTiers = (source.contextTiers as unknown[]).map((value, index, tiers) => {\n const tier = priceRecord(value, 'contextTier')\n const out: CommandCodeContextTier = parseRates(tier, 'contextTier')\n if (tier.maxContext !== undefined) {\n const max = priceNumber(tier, 'maxContext', 'contextTier.maxContext')\n if (!Number.isSafeInteger(max) || max <= previous || index === tiers.length - 1) priceReject('contextTier.maxContext')\n previous = max\n out.maxContext = max\n } else if (index !== tiers.length - 1) priceReject('contextTier.maxContext')\n return out\n })\n }\n if (source.free !== undefined) price.free = priceBoolean(source, 'free', 'model.free')\n return price\n}\n\n/** Parse the wire result into a {@link CommandCodePriceTable}. */\nfunction parsePriceTable(value: unknown): CommandCodePriceTable {\n const source = priceRecord(value, 'result')\n const models = source.models\n if (!Array.isArray(models)) priceReject('models')\n const peakHours = source.peakHours\n if (!Array.isArray(peakHours)) priceReject('peakHours')\n return {\n models: (models as unknown[]).map(parseModelPrice),\n peakHours: (peakHours as unknown[]).map((window) => {\n if (!Array.isArray(window) || window.length !== 2) priceReject('peakHours[]')\n const [start, end] = window as [unknown, unknown]\n if (typeof start !== 'number' || typeof end !== 'number') priceReject('peakHours[]')\n return [start, end] as [number, number]\n }),\n }\n}\n\n/** The strict result codec for the price-table Remote. */\nexport const pricesSchema: TypertSchema<CommandCodePriceTable> = {\n parse: parsePriceTable,\n}\n\n/**\n * The price-table invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the report and catalog endpoints.\n */\nexport const PRICES_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodePriceTable>(\n PRICES_ENDPOINT,\n 'prices',\n `${USAGE_REMOTE_PACKAGE}#CommandCodePriceTable`,\n pricesSchema,\n )\n\n/** The Client-face contribution for the price-table endpoint. */\nexport const PRICES_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [PRICES_DESCRIPTOR],\n}","/**\n * Wire contract for the Command Code login Remote endpoints\n * (`commandcode/loginBegin`, `commandcode/loginStatus`,\n * `commandcode/loginCancel`).\n *\n * The settings page can start a browser login against the official Command\n * Code Studio (the same loopback flow `command-code login` performs) instead\n * of pasting an API key. The loopback server must live in the Host half — it\n * binds a local port and receives the key — so the page drives it through the\n * Typert Gateway exactly like the usage report.\n *\n * This module is the single source both halves share, deliberately\n * dependency-free (`import type` edges only): the strict status validator the\n * client trusts, the three descriptors both halves register, and the two\n * contribution objects. The state shape mirrors the Host-only flow machine in\n * `src/login.ts` as plain JSON.\n *\n * @module dsh-commandcode-provider/login-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** Why a login attempt ended in `failed` (stable across versions for copy). */\nexport type CommandCodeLoginFailureReason =\n /** The Studio page reported the authorization was denied by the user. */\n | 'denied'\n /** No callback arrived within the flow's timeout window. */\n | 'timeout'\n /** The delivered key failed `/alpha/whoami` validation (401). */\n | 'invalid-key'\n /** The validation request could not reach the API. */\n | 'network'\n /** The key could not be stored (credentials seam unavailable). */\n | 'unavailable'\n /** The attempt was cancelled by the user or torn down with the plugin. */\n | 'cancelled'\n /** Anything else. */\n | 'error'\n\n/** One login attempt's full state face, as carried over the wire. */\nexport interface CommandCodeLoginStatus {\n /**\n * `idle` — no attempt; `waiting` — the loopback server is up and the\n * Studio URL is live; `success` — the key validated and was stored;\n * `failed` — see `reason`/`message`.\n */\n state: 'idle' | 'waiting' | 'success' | 'failed'\n /** The Studio authorization URL while `waiting`. */\n authUrl?: string\n /** The account display name reported by the Studio, on `success`. */\n userName?: string\n /** The key's label from the Studio, on `success`. */\n keyName?: string\n /** Why the attempt failed, when `failed`. */\n reason?: CommandCodeLoginFailureReason\n /** Human-readable failure detail, when `failed` (secondary to `reason`). */\n message?: string\n}\n\n/** The canonical endpoint paths of the three login Remotes. */\nexport const LOGIN_BEGIN_ENDPOINT = 'commandcode/loginBegin'\nexport const LOGIN_STATUS_ENDPOINT = 'commandcode/loginStatus'\nexport const LOGIN_CANCEL_ENDPOINT = 'commandcode/loginCancel'\n\nconst REASONS: readonly CommandCodeLoginFailureReason[] = [\n 'denied', 'timeout', 'invalid-key', 'network', 'unavailable', 'cancelled', 'error',\n]\n\n/** The shared read/validate helpers, prefixed with the login endpoint so\n * rejection messages name the offending boundary. */\nconst { reject, record, stringField } =\n makeBoundaryValidator('commandcode/login result:')\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeLoginStatus}.\n * Every field is shape-checked so a malformed frame fails the boundary\n * instead of leaking into the page.\n */\nexport function parseLoginStatus(value: unknown): CommandCodeLoginStatus {\n const source = record(value, 'status')\n const state = source.state\n // The factory's destructured-arrow `reject` is typed never-returning but\n // TS narrows it only in the positive branch — assign inside the guard.\n if (state === 'idle' || state === 'waiting' || state === 'success' || state === 'failed') {\n const status: CommandCodeLoginStatus = { state }\n if (source.authUrl !== undefined) {\n status.authUrl = stringField(source, 'authUrl', 'authUrl')\n }\n if (source.userName !== undefined) {\n status.userName = stringField(source, 'userName', 'userName')\n }\n if (source.keyName !== undefined) {\n status.keyName = stringField(source, 'keyName', 'keyName')\n }\n if (source.reason !== undefined) {\n const reason = source.reason\n if (typeof reason === 'string' && REASONS.includes(reason as CommandCodeLoginFailureReason)) {\n status.reason = reason as CommandCodeLoginFailureReason\n } else {\n reject('reason')\n }\n }\n if (source.message !== undefined) {\n status.message = stringField(source, 'message', 'message')\n }\n return status\n }\n return reject('state')\n}\n\n/** The strict result codec shared by all three login endpoints. */\nexport const loginStatusSchema: TypertSchema<CommandCodeLoginStatus> = {\n parse: parseLoginStatus,\n}\n\n/** Build one login invocation descriptor (uniform result, no parameters). */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n return makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n}\n\n/** The three login descriptors, shared verbatim by Host registration and Client mount. */\nexport const LOGIN_DESCRIPTORS: readonly InvocationDescriptor[] = [\n loginDescriptor(LOGIN_BEGIN_ENDPOINT, 'loginBegin'),\n loginDescriptor(LOGIN_STATUS_ENDPOINT, 'loginStatus'),\n loginDescriptor(LOGIN_CANCEL_ENDPOINT, 'loginCancel'),\n]\n\n/** The Host-face contribution fragment registered on `ctx.typert`. */\nexport const LOGIN_HOST_CONTRIBUTION = {\n package: REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n invocations: LOGIN_DESCRIPTORS,\n}\n\n/** The Client-face contribution fragment mounted on `ctx.remote`. */\nexport const LOGIN_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REMOTE_PACKAGE,\n descriptors: LOGIN_DESCRIPTORS,\n}\n","/**\n * Host half of the account-usage Remote (`commandcode/report`).\n *\n * The settings page's account card needs the same report the `/commandcode`\n * command prints, but the browser never holds the API key — the fetch must\n * run Host-side. This module exposes `adapter.getUsage()` through the Typert\n * Gateway: a `TypertRemoteService` provides the receiver the Gateway resolves,\n * and the shared strict descriptor (`src/usage-wire.ts`) is registered on the\n * `typert` registry so the Gateway claims the `commandcode/report` endpoint.\n *\n * The whole wiring rides an optional `ctx.inject(['typert'], ...)` fiber: a\n * profile without the web stack (no Typert registry, no Gateway) simply never\n * activates it, exactly like the `/commandcode` command rides `commands`.\n *\n * @module dsh-commandcode-provider/usage-remote\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'\nimport type { CommandCodeAdapter, CommandCodeConnectionOptions } from './adapter.ts'\nimport { USAGE_HOST_CONTRIBUTION } from './usage-wire.ts'\nimport { MODELS_DESCRIPTOR } from './usage-wire.ts'\nimport { PRICES_DESCRIPTOR } from './usage-wire.ts'\nimport type { CommandCodeAccountsReport, CommandCodeCatalog, CommandCodePriceTable } from './usage-wire.ts'\nimport { modelPriceTable } from './model-prices.ts'\nimport { LOGIN_DESCRIPTORS } from './login-wire.ts'\nimport type { CommandCodeLoginStatus } from './login-wire.ts'\n\n/**\n * The browser-login face the usage service exposes (`commandcode/login*`).\n * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry\n * wired one; absent, `status`/`cancel` degrade to the idle status while\n * `begin` rejects with a plain message (so the page's manual paste path\n * stays the fallback instead of hanging).\n */\nexport interface LoginFlowFacade {\n /** Start (or rejoin) an attempt; rejects when it cannot start at all. */\n begin(): Promise<CommandCodeLoginStatus>\n /** The current attempt's status. */\n status(): CommandCodeLoginStatus\n /** Cancel a waiting attempt. */\n cancel(): void\n}\n\n/** Everything the usage service needs beyond its Cordis context. */\nexport interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** The registered adapter (for getUsage). */\n adapter: CommandCodeAdapter<C>\n /**\n * Multi-account report source (wired by the plugin entry). Absent in\n * programmatic setups, the service falls back to a single default-account\n * entry around `adapter.getUsage()`.\n */\n reports?: () => Promise<CommandCodeAccountsReport>\n /**\n * Model-catalog source for the settings page's model editors (the\n * routing-rule editor and the visible-models filter; wired by the plugin\n * entry). Absent, the `models` endpoint answers an empty list — the page's\n * editors degrade to the empty state.\n */\n listModels?: () => Promise<CommandCodeCatalog>\n /**\n * Price-table source for the composer's session-cost figure. Defaults to the\n * vendored snapshot, so the endpoint can never silently serve an empty table\n * — an unpriced cost is the failure this feature is meant to remove. Override\n * only to stub it in a test.\n */\n prices?: () => CommandCodePriceTable\n /**\n * The browser-login flow (wired by the plugin entry). Absent means the\n * login endpoints answer `idle` / reject with a plain message — the page's\n * manual paste path stays the fallback.\n */\n login?: LoginFlowFacade\n}\n\n/**\n * The registry method surface this module uses. `Context['typert']` is typed\n * as the read-only `TypertRegistryContract`; contribution registration lives\n * on the concrete registry service, so the cast is spelled out once here.\n * The contribution is the combined one built below (report + models + login\n * endpoints), so the type is structural rather than tied to the\n * single-endpoint `USAGE_HOST_CONTRIBUTION` shape.\n */\ninterface TypertContributionRegistry {\n register(contribution: {\n package: string\n face: 'host'\n schemas: unknown[]\n model: { services: unknown[]; events: unknown[]; objects: unknown[] }\n invocations: unknown[]\n }): () => void | Promise<void>\n}\n\n/**\n * The Remote receiver: a Cordis service the Gateway resolves by key\n * (`commandcodeUsage`) and binds to the wire namespace (`commandcode`). The\n * base class stamps the `typertRemote` binding the Gateway validates on every\n * dispatch; no decorators are needed because the descriptor is registered\n * explicitly (strict path) rather than discovered from source markers.\n */\nexport class CommandCodeUsageService<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions>\n extends TypertRemoteService {\n private readonly deps: CommandCodeUsageDeps<C>\n\n constructor(ctx: Context, deps: CommandCodeUsageDeps<C>) {\n super(ctx, 'commandcodeUsage', { namespace: 'commandcode' })\n this.deps = deps\n }\n\n /**\n * Account, usage, and credit state for the settings page's account card —\n * one entry per pool account when the plugin entry wired `reports`, a\n * single default-account entry otherwise. Degrades per endpoint like the\n * `/commandcode` command (failures land in `report.failures`); throws\n * `MISSING_CREDENTIAL` when no key resolves, which the Gateway folds into\n * the failure branch the page renders as a hint.\n */\n async report(): Promise<CommandCodeAccountsReport> {\n if (this.deps.reports !== undefined) return this.deps.reports()\n const report = await this.deps.adapter.getUsage()\n return {\n accounts: [{\n id: 'default',\n label: 'Default',\n configured: true,\n active: true,\n mark: '',\n cooldownUntil: 0,\n report,\n }],\n }\n }\n\n /**\n * The full model catalog for the settings page's model editors (the\n * routing-rule editor and the visible-models filter). The browser never\n * calls the Command Code API directly — the Host serves the catalog\n * (already fetched/cached by the adapter) so models can be picked from\n * the live list instead of typed by hand.\n */\n async models(): Promise<CommandCodeCatalog> {\n return this.deps.listModels?.() ?? { models: [] }\n }\n\n /**\n * The model price table the composer prices an in-progress session with.\n * Static vendored data (the official pricing page's rates), served Host-side\n * so the browser bundle never carries a copy that could drift from the\n * snapshot, and so a price update reaches an open page without a rebuild.\n */\n async prices(): Promise<CommandCodePriceTable> {\n return (this.deps.prices ?? modelPriceTable)()\n }\n\n /**\n * Start (or rejoin) a browser-login attempt and return its fresh status —\n * `waiting` carrying the Studio URL. Rejects when the flow cannot start\n * (no free loopback port, disposed plugin); the Gateway folds the throw\n * into the failure branch the page renders.\n */\n async loginBegin(): Promise<CommandCodeLoginStatus> {\n const login = this.requireLogin()\n return login.begin()\n }\n\n /** Poll a login attempt's status. */\n async loginStatus(): Promise<CommandCodeLoginStatus> {\n return this.deps.login?.status() ?? { state: 'idle' }\n }\n\n /** Cancel a waiting attempt; returns the post-cancel status. */\n async loginCancel(): Promise<CommandCodeLoginStatus> {\n this.deps.login?.cancel()\n return this.deps.login?.status() ?? { state: 'idle' }\n }\n\n private requireLogin(): LoginFlowFacade {\n const login = this.deps.login\n if (login === undefined) {\n throw new Error('login flow is not wired in this setup; paste the API key instead')\n }\n return login\n }\n}\n\n/**\n * Provide the usage service and register its Remote descriptor. The registry\n * contribution is tied to this fiber's lifetime: the registry's own\n * `register()` effect would otherwise outlive the plugin.\n */\nexport function applyUsageRemote<C extends CommandCodeConnectionOptions>(\n ctx: Context,\n deps: CommandCodeUsageDeps<C>,\n): void {\n ctx.inject(['typert'], (remoteCtx) => {\n new CommandCodeUsageService(remoteCtx, deps)\n const registry = remoteCtx.typert as unknown as TypertContributionRegistry\n // One registration carries the report endpoint, the models endpoint, and\n // the login endpoints: the descriptors are unique per endpoint, and a\n // single contribution keeps the Host's registry bookkeeping (and the\n // Client mount) 1:1.\n const unregister = registry.register({\n ...USAGE_HOST_CONTRIBUTION,\n invocations: [...USAGE_HOST_CONTRIBUTION.invocations, MODELS_DESCRIPTOR, PRICES_DESCRIPTOR, ...LOGIN_DESCRIPTORS],\n })\n // The registry's own effect would outlive this fiber; withdraw the\n // contribution when the plugin unloads.\n remoteCtx.effect(() => () => void unregister(), 'dsh-commandcode-provider: usage remote')\n })\n}\n","/**\n * Host half of the Command Code browser login (the loopback flow).\n *\n * Mirrors what the official `command-code login` CLI command performs\n * (reverse-engineered from `command-code@1.32.1`, `createAuthFlowController`\n * + `createAuthServer` in its bundle):\n *\n * 1. Bind a temporary HTTP server on `127.0.0.1`, first available port from\n * 5959 upward (10 attempts).\n * 2. Generate a random state token and open\n * `{studio}/studio/auth/cli?callback=http://localhost:{port}/callback&state={state}`.\n * 3. After the user signs in, the Studio page POSTs the credentials JSON\n * `{ apiKey, state, userId, userName, keyName }` to the loopback callback —\n * no OAuth code exchange, the page holds the final API key.\n * 4. The delivered key is validated against `GET {apiBase}/alpha/whoami`\n * before anything is stored.\n *\n * Server behaviour is mirrored exactly: POST-only `/callback`, a 10 KB body\n * cap, JSON responses (`{success:true}` / `{success:false,error}`), CORS for\n * the Studio origins only, and state-token equality as the anti-forgery\n * check. One deliberate hardening over the CLI build: the CORS origin is\n * echoed only when it is allowlisted (the CLI falls back to the first\n * origin), which browsers treat identically.\n *\n * Storage stays out of this module: the plugin entry supplies\n * {@link CommandCodeLoginFlowDeps.storeKey}, which writes through the dsh\n * credentials seam so the next request resolves the new key with no restart.\n * Everything external (fetch, ports, randomness, timing) is injectable for\n * node tests; the tests drive a real loopback server end to end.\n *\n * @module dsh-commandcode-provider/login\n */\n\nimport { createServer as createHttpServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'\nimport { createServer as createNetServer } from 'node:net'\nimport { randomBytes } from 'node:crypto'\nimport { DEFAULT_API_BASE } from './adapter.ts'\nimport type { CommandCodeLoginFailureReason, CommandCodeLoginStatus } from './login-wire.ts'\n\n/** Give up on the browser after this long without a callback (mirrors the CLI). */\nexport const LOGIN_TIMEOUT_MS = 120_000\n\n/** First local port the flow tries (mirrors the CLI). */\nexport const LOGIN_START_PORT = 5959\n\n/** How many consecutive ports to try from {@link LOGIN_START_PORT}. */\nexport const LOGIN_MAX_PORT_ATTEMPTS = 10\n\n/** Reject callback bodies larger than this (mirrors the CLI). */\nexport const LOGIN_BODY_LIMIT_BYTES = 10_000\n\n/** The Studio origins allowed to POST credentials to the loopback server. */\nexport const LOGIN_ALLOWED_ORIGINS: readonly string[] = [\n 'http://localhost:3000',\n 'https://staging.commandcode.ai',\n 'https://commandcode.ai',\n]\n\n/** The Studio route that performs the browser-side login. */\nconst STUDIO_AUTH_PATH = '/studio/auth/cli'\n\n/** Credentials as delivered by the Studio's callback POST. */\nexport interface CommandCodeLoginCredentials {\n apiKey: string\n userId: string\n userName: string\n keyName: string\n}\n\n/** Outcome of validating a delivered key against `/alpha/whoami`. */\nexport type ApiKeyValidation =\n | { valid: true }\n | { valid: false; error: 'invalid_key' | 'server_error' | 'network_error' }\n\nexport interface CommandCodeLoginFlowDeps {\n /**\n * The Provider API base used for `/alpha/whoami` validation; also selects\n * the matching Studio base (staging api → staging studio). A thunk is fine:\n * it is re-read when each attempt starts, so a settings change reaches the\n * next login. Defaults to the public API base.\n */\n apiBase?: string | (() => string | undefined)\n /** Attempt timeout in millis; defaults to {@link LOGIN_TIMEOUT_MS}. */\n timeoutMs?: number\n /** First port to try; defaults to {@link LOGIN_START_PORT}. */\n startPort?: number\n /** Consecutive-port attempts; defaults to {@link LOGIN_MAX_PORT_ATTEMPTS}. */\n maxPortAttempts?: number\n /** Validation fetch seam; defaults to global `fetch`. */\n fetchImpl?: typeof fetch\n /** Randomness seam; defaults to `node:crypto` randomBytes(32) base64url. */\n randomToken?: (byteLength: number) => string\n /**\n * Receives the validated credentials after a successful login. Rejecting\n * fails the attempt with `unavailable`.\n */\n storeKey(credentials: CommandCodeLoginCredentials): Promise<void>\n}\n\n/** Compose the Studio authorization URL (pure, exported for tests). */\nexport function buildCommandAuthUrl(options: { studioBase: string; port: number; state: string }): string {\n const callback = `http://localhost:${options.port}/callback`\n return `${options.studioBase}${STUDIO_AUTH_PATH}?callback=${encodeURIComponent(callback)}&state=${encodeURIComponent(options.state)}`\n}\n\n/** Map an API base onto the Studio base the CLI pairs it with. */\nexport function studioBaseForApiBase(apiBase: string): string {\n if (/^https:\\/\\/staging-api\\.commandcode\\.ai/i.test(apiBase)) return 'https://staging.commandcode.ai'\n if (/^http:\\/\\/localhost(:\\d+)?$/i.test(apiBase)) return 'http://localhost:3000'\n return 'https://commandcode.ai'\n}\n\n/**\n * Validate one candidate key against `/alpha/whoami` (pure, exported for\n * tests). Mirrors the CLI's verdicts: 401 → invalid_key, other non-OK →\n * server_error, transport failure → network_error.\n */\nexport async function validateCommandApiKey(\n fetchImpl: typeof fetch,\n apiBase: string,\n apiKey: string,\n): Promise<ApiKeyValidation> {\n try {\n const response = await fetchImpl(`${apiBase}/alpha/whoami`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },\n })\n if (response.status === 401) return { valid: false, error: 'invalid_key' }\n if (response.ok) return { valid: true }\n return { valid: false, error: 'server_error' }\n } catch {\n return { valid: false, error: 'network_error' }\n }\n}\n\n/** Whether one loopback port is free right now. */\nfunction checkPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const probe = createNetServer()\n probe.once('error', () => resolve(false))\n probe.once('listening', () => probe.close(() => resolve(true)))\n probe.listen(port, '127.0.0.1')\n })\n}\n\n/** Whether a callback body carries every credential field the CLI requires. */\nfunction isCallbackCredentials(value: unknown): value is CommandCodeLoginCredentials & Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n return typeof record.apiKey === 'string' && record.apiKey !== ''\n && typeof record.state === 'string'\n && typeof record.userId === 'string'\n && typeof record.userName === 'string'\n && typeof record.keyName === 'string'\n}\n\n/**\n * One browser-login attempt machine. Single-flight by design: `begin()` while\n * waiting returns the live attempt's status instead of starting a second one;\n * a terminal state makes the next `begin()` start fresh.\n */\nexport class CommandCodeLoginFlow {\n private readonly deps: CommandCodeLoginFlowDeps\n private readonly listeners = new Set<() => void>()\n\n private statusValue: CommandCodeLoginStatus = { state: 'idle' }\n private server: Server | undefined\n private timer: ReturnType<typeof setTimeout> | undefined\n /** Settle hooks of the live attempt's callback promise. */\n private settle: {\n resolve(credentials: CommandCodeLoginCredentials): void\n reject(failure: LoginSettleError): void\n } | undefined\n /**\n * Attempt generation. A delivered callback keeps validating the key\n * asynchronously (`complete()`), and that window is open to a cancel or a\n * fresh `begin()`; the generation lets a late completion recognize that it\n * no longer owns the status face and stop instead of storing a credential\n * the user cancelled and flipping the page back to success.\n */\n private attemptSeq = 0\n private disposed = false\n\n constructor(deps: CommandCodeLoginFlowDeps) {\n this.deps = deps\n }\n\n /** Subscribe to state transitions. @returns the disposer. */\n onChange(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current attempt's status face. */\n status(): CommandCodeLoginStatus {\n return this.statusValue\n }\n\n /**\n * Start an attempt (or rejoin the live one) and resolve with its status —\n * `waiting` carrying the Studio URL once the loopback server is up.\n * Rejects only when the flow cannot start at all (no free port, disposed).\n */\n async begin(): Promise<CommandCodeLoginStatus> {\n if (this.disposed) throw new Error('login flow has been disposed')\n // Rejoin only a live attempt. A `waiting` status whose server is already\n // torn down means the callback was consumed and the key is being\n // validated: that attempt can no longer receive anything, so handing its\n // dead authUrl back would give the user a link to a closed port. Starting\n // fresh retires it (the generation check below drops its late completion).\n if (this.statusValue.state === 'waiting' && this.server !== undefined) return this.statusValue\n this.teardown()\n const attempt = ++this.attemptSeq\n\n const port = await this.findPort()\n const expectedState = this.deps.randomToken?.(32) ?? randomBytes(32).toString('base64url')\n\n // The attempt settles exactly once: fulfilled with delivered credentials,\n // rejected with a tagged failure the mapping below turns into copy.\n const settled = new Promise<CommandCodeLoginCredentials>((resolve, reject) => {\n this.settle = { resolve, reject }\n })\n // A bind failure must surface before the attempt reports `waiting`.\n await this.bindServer(port, expectedState)\n\n const apiBase = this.readApiBase()\n this.setStatus({\n state: 'waiting',\n authUrl: buildCommandAuthUrl({ studioBase: studioBaseForApiBase(apiBase), port, state: expectedState }),\n })\n\n // Watchdog mirrors the CLI's 2-minute window.\n this.timer = setTimeout(() => {\n this.teardown()\n this.setStatus({\n state: 'failed',\n reason: 'timeout',\n message: 'No browser callback arrived within the login window.',\n })\n }, this.deps.timeoutMs ?? LOGIN_TIMEOUT_MS)\n this.timer.unref?.()\n\n void settled.then(\n (credentials) => this.complete(attempt, credentials),\n (failure) => this.failFrom(attempt, failure),\n )\n return this.statusValue\n }\n\n /** Cancel a waiting attempt; terminal states are untouched. */\n cancel(): void {\n if (this.disposed || this.statusValue.state !== 'waiting') return\n this.teardown()\n this.setStatus({ state: 'failed', reason: 'cancelled' })\n }\n\n /** Stop everything; a waiting attempt ends cancelled. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n const wasWaiting = this.statusValue.state === 'waiting'\n this.teardown()\n if (wasWaiting) this.setStatus({ state: 'failed', reason: 'cancelled' })\n }\n\n // -----------------------------------------------------------------------\n // Internals\n // -----------------------------------------------------------------------\n\n private readApiBase(): string {\n const raw = typeof this.deps.apiBase === 'function' ? this.deps.apiBase() : this.deps.apiBase\n return raw ?? DEFAULT_API_BASE\n }\n\n private setStatus(next: CommandCodeLoginStatus): void {\n this.statusValue = next\n for (const listener of [...this.listeners]) listener()\n }\n\n /** First free port among the consecutive candidates. */\n private async findPort(): Promise<number> {\n const startPort = this.deps.startPort ?? LOGIN_START_PORT\n const attempts = this.deps.maxPortAttempts ?? LOGIN_MAX_PORT_ATTEMPTS\n for (let index = 0; index < attempts; index += 1) {\n const candidate = startPort + index\n if (await checkPortAvailable(candidate)) return candidate\n }\n throw new Error(`No available port found after ${attempts} attempts starting from port ${startPort}`)\n }\n\n /**\n * Bind the attempt's loopback server, resolving when the port is live.\n * Pre-bind failures reject (surfacing from `begin()`); a later server error\n * settles the live attempt as a tagged failure instead.\n */\n private bindServer(port: number, expectedState: string): Promise<void> {\n return new Promise((resolve, reject) => {\n let binding = true\n const server = createHttpServer((request, response) => this.handleCallback(request, response, expectedState))\n this.server = server\n server.once('error', (error: NodeJS.ErrnoException) => {\n if (this.server !== server) return\n this.server = undefined\n const tagged = new LoginSettleError(\n 'error',\n `Could not bind the login callback server on port ${port}: ${error.code ?? error.message}`,\n )\n if (binding) {\n binding = false\n reject(tagged)\n } else {\n this.settle?.reject(tagged)\n }\n })\n server.listen(port, '127.0.0.1', () => {\n if (!binding) return\n binding = false\n resolve()\n })\n })\n }\n\n /** One request against the attempt's callback endpoint (CLI-mirrored). */\n private handleCallback(request: IncomingMessage, response: ServerResponse, expectedState: string): void {\n // One-shot responses: the server dies with the attempt, and a client\n // pooling the connection would otherwise race its next request against\n // the close.\n response.setHeader('Connection', 'close')\n response.setHeader('Access-Control-Allow-Origin', corsOrigin(request.headers.origin))\n response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')\n response.setHeader('Access-Control-Allow-Headers', 'Content-Type')\n response.setHeader('Content-Type', 'application/json')\n const json = (code: number, body: Record<string, unknown>) => {\n response.writeHead(code)\n response.end(JSON.stringify(body))\n }\n if (request.method === 'OPTIONS') {\n response.writeHead(204)\n response.end()\n return\n }\n const path = request.url?.split('?')[0] ?? '/'\n if (path !== '/callback') {\n json(404, { success: false, error: 'Not found' })\n return\n }\n if (request.method !== 'POST') {\n json(405, { success: false, error: 'Method not allowed. Use POST.' })\n return\n }\n // The cap is on wire bytes, not JS string length: multibyte bodies\n // (CJK/emoji) would otherwise pass ~1.5-2x the limit before tripping it.\n let bodyBytes = 0\n let body = ''\n request.on('data', (chunk: Buffer) => {\n bodyBytes += chunk.length\n body += chunk.toString()\n if (bodyBytes > LOGIN_BODY_LIMIT_BYTES) request.destroy()\n })\n request.on('end', () => {\n // A destroyed (over-limit) request never processes its partial body.\n if (request.destroyed) return\n let payload: unknown\n try {\n payload = JSON.parse(body)\n } catch {\n json(400, { success: false, error: 'Invalid JSON' })\n return\n }\n // The Studio reports a denied authorization as an error object. The\n // state token is checked FIRST, exactly as the CLI does: a denial is\n // terminal, so an unauthenticated caller that could reach this branch\n // without a state match could kill a live login from any web page (the\n // POST rides as a CORS simple request, which the browser sends\n // regardless of our origin allowlist). Only the holder of the state this\n // attempt generated may end it.\n if (typeof payload === 'object' && payload !== null && 'error' in payload) {\n const denial = payload as Record<string, unknown>\n if (denial.state !== expectedState) {\n json(403, { success: false, error: 'Invalid state token' })\n return\n }\n const description = denial.error_description ?? denial.error\n this.settleAttempt(json, 200, { success: true }, new LoginSettleError(\n denial.error === 'access_denied' ? 'denied' : 'error',\n typeof description === 'string' && description !== '' ? description : 'Authorization failed',\n ))\n return\n }\n if (!isCallbackCredentials(payload)) {\n json(400, { success: false, error: 'Missing required fields' })\n return\n }\n if (payload.state !== expectedState) {\n // Not terminal: a stale tab replaying an old state must not kill the\n // live attempt — answer 403 and keep waiting (the CLI does the same).\n json(403, { success: false, error: 'Invalid state token' })\n return\n }\n this.settleAttempt(json, 200, { success: true }, undefined, { ...payload })\n })\n request.on('error', () => {})\n }\n\n /** Answer a decisive callback, stop listening, and settle the attempt. */\n private settleAttempt(\n json: (code: number, body: Record<string, unknown>) => void,\n code: number,\n body: Record<string, unknown>,\n failure?: LoginSettleError,\n credentials?: CommandCodeLoginCredentials,\n ): void {\n json(code, body)\n // Capture the settle hooks BEFORE teardown clears them.\n const settle = this.settle\n this.teardown()\n if (settle === undefined) return\n if (failure !== undefined) settle.reject(failure)\n else if (credentials !== undefined) settle.resolve(credentials)\n }\n\n /**\n * Post-validation completion: whoami check, then hand-off to storage.\n *\n * Every step re-checks {@link ownsAttempt} first: the whoami round-trip and\n * the credential write are awaits, and the user may cancel (or start another\n * attempt) while one is in flight. A completion that no longer owns the\n * attempt must not write the key or publish a status — otherwise cancel\n * would report \"cancelled\" while the credential landed anyway, and the page\n * would silently flip to success.\n */\n private async complete(attempt: number, credentials: CommandCodeLoginCredentials): Promise<void> {\n if (!this.ownsAttempt(attempt)) return\n const validation = await validateCommandApiKey(\n this.deps.fetchImpl ?? fetch,\n this.readApiBase(),\n credentials.apiKey,\n )\n if (!this.ownsAttempt(attempt)) return\n if (!validation.valid) {\n const reason: CommandCodeLoginFailureReason = validation.error === 'invalid_key'\n ? 'invalid-key'\n : validation.error === 'network_error' ? 'network' : 'error'\n this.setStatus({\n state: 'failed',\n reason,\n message: `/alpha/whoami rejected the delivered key (${validation.error}).`,\n })\n return\n }\n // Last gate before the side effect: a cancel that arrived during the\n // whoami check must win over storing the key.\n if (!this.ownsAttempt(attempt)) return\n try {\n await this.deps.storeKey(credentials)\n } catch (error: unknown) {\n if (!this.ownsAttempt(attempt)) return\n this.setStatus({\n state: 'failed',\n reason: 'unavailable',\n message: error instanceof Error ? error.message : String(error),\n })\n return\n }\n if (!this.ownsAttempt(attempt)) return\n this.clearTimer()\n this.setStatus({ state: 'success', userName: credentials.userName, keyName: credentials.keyName })\n }\n\n /** Whether one attempt still owns the status face (not cancelled, replaced, or disposed). */\n private ownsAttempt(attempt: number): boolean {\n return !this.disposed && this.attemptSeq === attempt && this.statusValue.state === 'waiting'\n }\n\n /** Map a tagged settle rejection onto the status face. */\n private failFrom(attempt: number, failure: unknown): void {\n if (!(failure instanceof LoginSettleError)) return\n if (!this.ownsAttempt(attempt)) return\n this.setStatus({ state: 'failed', reason: failure.reason, message: failure.message })\n }\n\n private clearTimer(): void {\n if (this.timer !== undefined) {\n clearTimeout(this.timer)\n this.timer = undefined\n }\n }\n\n /** Close the server and watchdog without touching the published status. */\n private teardown(): void {\n this.clearTimer()\n this.server?.close()\n this.server = undefined\n this.settle = undefined\n }\n}\n\n/** A tagged settle failure carrying the stable copy reason. */\nclass LoginSettleError extends Error {\n constructor(public readonly reason: CommandCodeLoginFailureReason, message: string) {\n super(message)\n this.name = 'LoginSettleError'\n }\n}\n\n/** Echo the Origin header only when the Studio allowlist contains it. */\nfunction corsOrigin(origin: string | undefined): string {\n return origin !== undefined && LOGIN_ALLOWED_ORIGINS.includes(origin) ? origin : ''\n}\n","/**\n * dsh-commandcode-provider — Command Code web search provider over `ctx.web`.\n *\n * The official Command Code CLI ships a built-in `web_search` tool that POSTs\n * `{ query, numResults, allowedDomains?, blockedDomains? }` to\n * `{apiBase}/alpha/web-search` and reads `{ results: [{ title, url, snippet }] }`\n * back. It authenticates with the SAME `Authorization: Bearer <key>` header and\n * `x-command-code-version` the model adapter uses, so this provider reuses the\n * plugin's existing credential chain (`COMMANDCODE_API_KEY` → credentials seam →\n * `~/.commandcode/auth.json`) — no separate DeepSeek key, no extra endpoint.\n *\n * This mirrors the host-side `@deepseek-ai/dsh-web-search-deepseek` provider in\n * shape: a cordis-free class registered into the web seam, resolving its key per\n * search, mapping each server-side result to the harness's normalized\n * `WebSearchSource`. The web seam owns `maxResults` truncation.\n *\n * @module dsh-commandcode-provider/web-search\n */\n\nimport { WebError, type WebSearchProvider, type WebSearchRequest, type WebSearchResult, type WebSearchSource } from '@deepseek-ai/dsh-web'\nimport type { WebRuntime } from '@deepseek-ai/dsh-web'\nimport { attributionHeaders, type HarnessError } from '@deepseek-ai/dsh-llm'\nimport { COMMAND_CODE_CLI_VERSION } from './adapter.ts'\n\n/** Stable id this provider registers under in `ctx.web`. */\nexport const COMMANDCODE_SEARCH_PROVIDER_ID = 'commandcode'\n\n/**\n * The factory-declared search provider id dsh ships by default (from\n * `dsh-base`'s cordis patch `web.config.searchProvider`). Kept as a\n * documented reference only: disabling this plugin's `webSearch` toggle\n * restores the previously selected backend (see\n * {@link applyCommandCodeSearchSelection}) — it never forces this default,\n * because forcing it is what used to silence sibling search plugins such as\n * modsearch even with Command Code search turned off (issue #26).\n */\nexport const DEFAULT_WEB_SEARCH_PROVIDER_ID = 'deepseek-official'\n\n/**\n * A structurally-typed view of `WebRuntime`'s private selection field.\n *\n * `searchProviderId` is declared `private readonly` on the class, but the\n * compiled runtime property is a plain writable field read per search call\n * (`web.search()` reads `this.searchProviderId` on every invocation). dsh\n * offers no public API to change the selected search provider at runtime, so\n * this seam mutates the instance field directly. That is a deliberate, bounded\n * dependency on the runtime shape: if dsh ever makes the field `#private` or\n * caches it in a closure, this write silently stops applying and the plugin\n * falls back to its provider remaining registered-but-unselected (the boot-time\n * `searchProvider: commandcode` cordis patch is the durable alternative).\n */\ninterface WebRuntimeSearchField {\n /** The selected search provider id; read per call by `search()`. */\n searchProviderId: string | undefined\n}\n\n/**\n * Point the web seam's search selection at this plugin's provider (`commandcode`).\n * Sets the runtime field; the next search call honours it because `search()`\n * re-reads `searchProviderId` each time. Returns the prior id (or undefined).\n * Never throws: a hardened/frozen runtime shape must not break the\n * settings-save path that calls this — the provider simply stays\n * registered-but-unselected (the boot-time `searchProvider: commandcode`\n * cordis patch is the durable alternative).\n *\n * @deprecated Prefer {@link applyCommandCodeSearchSelection}: this overload\n * always overwrites the displaced backend with the factory default on\n * disable, so turning Command Code search off silences whichever provider\n * was selected before (e.g. modsearch) instead of restoring it (issue #26).\n */\nexport function selectCommandCodeSearchProvider(web: WebRuntime, enable: boolean): string | undefined {\n try {\n const field = web as unknown as WebRuntimeSearchField\n const prior = field.searchProviderId\n field.searchProviderId = enable ? COMMANDCODE_SEARCH_PROVIDER_ID : DEFAULT_WEB_SEARCH_PROVIDER_ID\n return prior\n } catch {\n return undefined\n }\n}\n\n/**\n * Tracked web-search selection state for one mounted `WebRuntime`.\n *\n * `owner` marks whether this plugin currently owns the selection (i.e. it\n * wrote `commandcode` and has not given it back yet). `displaced` is the\n * backend id the plugin displaced when it took over — restored when the\n * toggle turns off or the plugin unloads. `undefined` means \"nothing was\n * configured, leave auto-select\" and must round-trip untouched: writing the\n * factory default instead would still override a sibling plugin's own\n * constructor-time pin.\n */\nexport interface CommandCodeSearchSelection {\n owner: boolean\n displaced: string | undefined\n}\n\n/** Fresh selection state: the plugin starts out not owning the selection. */\nexport function commandCodeSearchSelection(): CommandCodeSearchSelection {\n return { owner: false, displaced: undefined }\n}\n\n/**\n * Reach one end of the `webSearch` toggle without trampling sibling search\n * providers (issue #26).\n *\n * - Enabling writes `commandcode` and remembers whatever it displaced. When\n * the plugin already owns the selection (e.g. a settings save while still\n * on), the original `displaced` value is kept — the field currently holds\n * our own id, which must never be mistaken for the user's backend.\n * - Disabling hands the selection back to the remembered backend. When the\n * state holds no memory (a fresh boot straight into `webSearch: false`),\n * the field is left alone: the runtime's current value — a sibling's\n * cordis pin such as `searchProvider: modsearch`, or unset for\n * auto-select — already says what the user wants.\n * - When the field already reads `commandcode` at first touch (e.g. a\n * surviving runtime the plugin did not set, or a manual\n * `searchProvider: commandcode` pin), `displaced` stays undefined so the\n * later disable is a no-op rather than a guess at the factory default.\n *\n * Never throws: like the low-level rewrite, a hardened runtime shape degrades\n * to registered-but-unselected.\n */\nexport function applyCommandCodeSearchSelection(\n web: WebRuntime,\n state: CommandCodeSearchSelection,\n enable: boolean,\n): void {\n try {\n const field = web as unknown as WebRuntimeSearchField\n if (enable) {\n if (state.owner) {\n // Still on across a re-apply: re-assert without forgetting whom we displaced.\n field.searchProviderId = COMMANDCODE_SEARCH_PROVIDER_ID\n return\n }\n const prior = field.searchProviderId\n state.displaced = prior === COMMANDCODE_SEARCH_PROVIDER_ID ? undefined : prior\n field.searchProviderId = COMMANDCODE_SEARCH_PROVIDER_ID\n state.owner = true\n return\n }\n if (state.owner) {\n state.owner = false\n field.searchProviderId = state.displaced\n return\n }\n // Off without ever having taken over: nothing of ours to give back.\n } catch {\n // Hardened/frozen runtime: stay registered-but-unselected.\n }\n}\n\n/** Command Code's lower/upper bound on `numResults` (from the CLI's `web_search` schema). */\nconst MIN_NUM_RESULTS = 1\nconst MAX_NUM_RESULTS = 10\n/** CLI default when the caller sets no result cap. */\nconst DEFAULT_NUM_RESULTS = 5\n\n/** The endpoint the search POST goes to; `{apiBase}` is prepended. */\nconst SEARCH_ROUTE = '/alpha/web-search'\n\n/** Per-request facts the provider needs, all injected so the class stays cordis-free and testable. */\nexport interface CommandCodeSearchProviderDeps {\n /** Resolve one usable Command Code key (credential seam → env → auth file), or undefined when none. */\n resolveKey(): Promise<string | undefined>\n /** The API base host (defaults to `https://api.commandcode.ai`). */\n apiBase(): string\n /** Injectable fetch for tests; defaults to the global fetch. */\n fetchImpl?: typeof fetch\n}\n\n/**\n * Clamp a DSH `maxResults` bound into Command Code's 1–10 range, applying the\n * CLI default of 5 when the caller supplied none.\n */\nfunction clampNumResults(maxResults: number | undefined): number {\n return maxResults === undefined\n ? DEFAULT_NUM_RESULTS\n : Math.max(MIN_NUM_RESULTS, Math.min(MAX_NUM_RESULTS, Math.round(maxResults)))\n}\n\n/** Build a `WebSearchSource` from one raw `{ title, url, snippet }` result, omitting empty optional fields. */\nfunction toSource(result: { url?: string; title?: string; snippet?: string }): WebSearchSource | undefined {\n const url = result.url?.trim()\n if (url === undefined || url.length === 0) return undefined\n const title = result.title?.trim()\n const snippet = result.snippet?.trim()\n return {\n url,\n ...title !== undefined && title.length > 0 ? { title } : {},\n ...snippet !== undefined && snippet.length > 0 ? { snippet } : {},\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError'\n}\n\n/** Build the provider's stable cancellation error while retaining the caller's reason. */\nfunction searchAborted(signal: AbortSignal | undefined, fallback: unknown): WebError {\n return new WebError('Command Code web search aborted', 'WEB_ABORTED', {\n cause: signal?.aborted === true ? signal.reason : fallback,\n })\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted === true) throw searchAborted(signal, undefined)\n}\n\n/**\n * A `ctx.web` search provider backed by the Command Code Provider API. Reuses\n * the plugin's credential chain and `apiBase`, so search \"just works\" with the\n * existing key — the model-facing `web_search` tool needs no separate\n * configuration. Selection between multiple search providers is the web seam's\n * job (pin `searchProvider: commandcode` if ambiguous).\n */\nexport class CommandCodeSearchProvider implements WebSearchProvider {\n readonly id = COMMANDCODE_SEARCH_PROVIDER_ID\n\n constructor(private readonly deps: CommandCodeSearchProviderDeps) {}\n\n /** Cheap local check; must not make network calls. Presence of a parseable base is enough. */\n available(): boolean {\n const base = this.deps.apiBase()\n return base.length > 0 && URL.canParse(base)\n }\n\n async search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult> {\n throwIfAborted(signal)\n const apiBase = this.deps.apiBase()\n if (!URL.canParse(apiBase)) {\n throw new WebError(\n `Command Code web search is misconfigured: apiBase ${JSON.stringify(apiBase)} is not a valid URL`,\n 'WEB_PROVIDER_ERROR',\n )\n }\n const key = await this.resolveKey(signal)\n throwIfAborted(signal)\n const endpoint = `${apiBase.replace(/\\/$/, '')}${SEARCH_ROUTE}`\n\n const body = {\n query: request.query,\n numResults: clampNumResults(request.maxResults),\n }\n\n let response: Response\n try {\n response = await (this.deps.fetchImpl ?? fetch)(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n ...signal !== undefined ? { signal } : {},\n })\n } catch (error: unknown) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n throw new WebError(\n `Command Code web search request failed: ${error instanceof Error ? error.message : String(error)}`,\n 'WEB_PROVIDER_ERROR',\n { cause: error },\n )\n }\n\n if (!response.ok) {\n let message = `Command Code web search failed (HTTP ${response.status})`\n try {\n const parsed: unknown = await response.json()\n const detail = typeof parsed === 'object' && parsed !== null\n ? (parsed as { error?: unknown })?.error\n : undefined\n if (typeof detail === 'string' && detail.length > 0) message += `: ${detail}`\n else if (typeof detail === 'object' && detail !== null) {\n const code = (detail as { code?: unknown })?.code\n const inner = (detail as { message?: unknown })?.message\n if (typeof code === 'string' || typeof inner === 'string') {\n message += `: ${typeof code === 'string' ? code : ''}${typeof code === 'string' && typeof inner === 'string' ? ' — ' : ''}${typeof inner === 'string' ? inner : ''}`\n }\n }\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n // Non-JSON error bodies (proxy/gateway HTML): keep a truncated slice\n // so the status line still says something actionable.\n const text = await response.text().catch(() => '')\n const slice = text.trim().slice(0, 200)\n if (slice !== '') message += `: ${slice}`\n }\n throw new WebError(message, 'WEB_PROVIDER_ERROR')\n }\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n throw new WebError('Command Code web search returned an unparseable response body', 'WEB_PROVIDER_ERROR', { cause: error })\n }\n\n const results = (payload as { results?: unknown })?.results\n if (!Array.isArray(results)) {\n throw new WebError(\n 'Command Code web search returned no results array (the server may have rejected the query)',\n 'WEB_PROVIDER_ERROR',\n )\n }\n\n const sources: WebSearchSource[] = []\n const seen = new Set<string>()\n for (const item of results) {\n if (typeof item !== 'object' || item === null) continue\n const source = toSource(item as { url?: string; title?: string; snippet?: string })\n if (source === undefined || seen.has(source.url)) continue\n seen.add(source.url)\n sources.push(source)\n }\n\n return { sources, truncated: false }\n }\n\n private async resolveKey(signal: AbortSignal | undefined): Promise<string> {\n let key: string | undefined\n try {\n key = await this.deps.resolveKey()\n } catch (error) {\n if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error)\n // Preserve the plugin's structured credential/usage taxonomy so the web\n // tool surfaces the real cause (e.g. every account exhausted, key\n // invalid) instead of a generic provider failure. The actionable\n // \"no key configured\" case maps to WEB_PROVIDER_CREDENTIAL_MISSING;\n // real rejection causes (INVALID_CREDENTIAL / RATE_LIMIT) keep their\n // message but ride the provider-error code the tool understands.\n if (error instanceof Error && typeof (error as HarnessError).code === 'string') {\n const code = (error as HarnessError).code\n if (code === 'MISSING_CREDENTIAL') throw new WebError(error.message, 'WEB_PROVIDER_CREDENTIAL_MISSING', { cause: error })\n if (code === 'INVALID_CREDENTIAL' || code === 'RATE_LIMIT') {\n throw new WebError(error.message, 'WEB_PROVIDER_ERROR', { cause: error })\n }\n }\n throw new WebError(\n `Command Code web search credential resolution failed: ${error instanceof Error ? error.message : String(error)}`,\n 'WEB_PROVIDER_ERROR',\n { cause: error },\n )\n }\n if (key === undefined || key.length === 0) {\n throw new WebError(\n 'Command Code web search has no API key; store COMMANDCODE_API_KEY through the credentials service (the web Models page writes it), export it in the launching environment, set config.apiKey, or run `command-code login` to write ~/.commandcode/auth.json',\n 'WEB_PROVIDER_CREDENTIAL_MISSING',\n )\n }\n return key\n }\n}\n","/**\n * dsh-TUI settings section (`tuiSettingsSections`).\n *\n * The terminal front door (dsh-TUI) owns its settings screen and asks plugins\n * only to DECLARE what is editable: a section over the plugin's own settings\n * namespace, which the screen renders and writes through the dsh settings\n * service. Without such a declaration a TUI-only user cannot enter the Command\n * Code API key at all — the web Models page is the only surface that writes\n * it, and dsh-TUI's own `/provider` wizard manages its `llm-pi-ai` routes\n * exclusively (issue #28).\n *\n * The seam is third-party, so this module carries LOCAL structural types\n * instead of importing `@deepseek-harness-tui/dsh-tui`: the plugin keeps zero\n * dependency on a terminal front door it may never meet, and an unmeet seam\n * degrades to \"no section\" rather than to a failed import. Registration rides\n * `ctx.inject(['tuiSettingsSections'], …)` in the plugin entry, so a profile\n * without dsh-TUI never activates the fiber — the same optional-service shape\n * `commands`, `web` and `typert` already use.\n *\n * The API-key field is a **secret** field: dsh-TUI keeps the literal out of\n * the settings document and writes the draft through the credentials seam\n * under the declared reference — the same guarantee the web card provides.\n * The reference must not collide with a host-owned one; dsh-TUI rejects\n * `DEEPSEEK_*`/`DSH_*` refs from plugin sections, and this plugin's default\n * (`COMMANDCODE_API_KEY`) is its own namespace.\n *\n * The model allowlist is a **checkbox per catalog model**, grouped by plan\n * tier — the terminal counterpart of the web page's searchable dropdown, and\n * the reason this page does not ask anyone to type 60+ model ids from memory.\n * dsh-TUI's seam has no multi-select kind (only `text | number | boolean |\n * select`) and no array element path a checkbox could own, so each model is\n * its own `boolean` field that WRITES THE WHOLE ARRAY through its `parse`:\n * the seam lets a field's write carry any value, which is what makes a\n * per-model checkbox express set membership. Two rules keep that honest.\n * (1) `parse` reads the allowlist LIVE through its thunk instead of the value\n * the field was built with, and rebuilds the array from THAT: the screen\n * stages several toggles into one save, so a captured base would let two\n * quick toggles resurrect each other's stale list. (2) An empty allowlist\n * means \"show every model\" to the adapter, so the checkboxes render the\n * EFFECTIVE set — unset shows everything checked, and checking a box only\n * records an explicit list once something is excluded.\n *\n * @module dsh-commandcode-provider/tui-settings\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n\nimport {\n KNOWN_PLANS,\n capabilityDescription,\n isFreeModel,\n} from './capabilities.ts'\n\n/** Provider-owned translations for one title, label, or hint. */\nexport interface TuiLocalizedText {\n readonly zh?: string\n readonly en?: string\n}\n\n/** Control kinds the dsh-TUI settings screen knows how to render. */\nexport type TuiSettingsFieldKind = 'text' | 'number' | 'boolean' | 'select'\n\n/** One choice of an options-bearing field. */\nexport interface TuiSettingsFieldOption {\n /** Stored value. */\n readonly value: string\n /** Display label (English; also the fallback). */\n readonly label: string\n /** Provider-owned translations for the label. */\n readonly descriptions?: TuiLocalizedText\n}\n\n/** The write one field's draft stages when the section is saved. */\nexport type TuiSettingsFieldWrite =\n | { readonly kind: 'set'; readonly value: unknown }\n | { readonly kind: 'clear' }\n\n/** One editable field inside a section. */\nexport interface TuiSettingsField {\n /** Key path from the section root, in the settings service's `mutate` vocabulary. */\n readonly path: readonly string[]\n /** Short field label (English; also the fallback). */\n readonly label: string\n /** Provider-owned translations for the label. */\n readonly descriptions?: TuiLocalizedText\n /** Optional one-line help rendered under the field. */\n readonly hint?: string\n /** Provider-owned translations for the hint. */\n readonly hintDescriptions?: TuiLocalizedText\n /** Optional group id; grouped fields render on that group's subpage. */\n readonly group?: string\n readonly kind: TuiSettingsFieldKind\n /**\n * Choices for an options-bearing field. A `text` field that carries options\n * is the TUI's own \"preset plus custom value\" shape: `←`/`→` cycle the\n * presets while Enter opens the text editor.\n */\n readonly options?: readonly TuiSettingsFieldOption[]\n /** Input placeholder for `kind: 'text' | 'number'`. */\n readonly placeholder?: string\n /**\n * Credential control: the literal never rides the settings document — the\n * draft starts blank on every open, a blank draft writes nothing, and a\n * typed draft writes through the credentials seam under `ref`.\n */\n readonly secret?: { readonly ref: string }\n /** Render a stored value as draft text. */\n readonly format?: (value: unknown) => string\n /** The write a draft text stages; `undefined` marks the draft invalid. */\n readonly parse?: (text: string) => TuiSettingsFieldWrite | undefined\n}\n\n/** Optional navigation group inside one section. */\nexport interface TuiSettingsGroup {\n /** Stable identifier, unique inside the section. */\n readonly id: string\n /** Group title (English; also the fallback). */\n readonly title: string\n /** Provider-owned translations for the title. */\n readonly descriptions?: TuiLocalizedText\n}\n\n/** One plugin's section inside the dsh-TUI settings screen. */\nexport interface TuiSettingsSection {\n /** Settings namespace this section edits. */\n readonly ns: string\n /** Section title (English; also the fallback). */\n readonly title: string\n /** Provider-owned translations for the title. */\n readonly descriptions?: TuiLocalizedText\n /** Optional navigation groups, in display order. */\n readonly groups?: readonly TuiSettingsGroup[]\n /** Editable fields, in display order. */\n readonly fields: readonly TuiSettingsField[]\n}\n\n/** The slice of the `tuiSettingsSections` service this module uses. */\nexport interface TuiSettingsSectionsService {\n /** Declare a section; the returned disposer withdraws it. */\n register(section: TuiSettingsSection): () => void\n}\n\n/** The selector value meaning \"no pinned account — follow rotation order\". */\nexport const ACTIVE_ACCOUNT_AUTO = 'auto'\n\n/** The selector value meaning \"no language override — follow the shell locale\". */\nexport const LANG_AUTO = 'auto'\n\n/** Tier display names, mirroring the web dropdown's headings (`model-select.ts`). */\nconst TIER_TITLES: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/** Tiers in picker order; a model outside this set joins the \"Other\" group. */\nconst TIER_ORDER: readonly string[] = ['go', 'goat', 'pro', 'provider', 'max']\n\n/** The group holding models this build's catalog does not know. */\nconst OTHER_GROUP_ID = 'models-other'\n\n/** One catalog model offered as a checkbox. */\nexport interface TuiModelChoice {\n /** Catalog model id, e.g. `deepseek/deepseek-v4-pro`. */\n readonly id: string\n /** Minimum plan tier key from `KNOWN_PLANS`. */\n readonly tier: string\n /** Whether the model is currently free, so it leads its group. */\n readonly free: boolean\n /** Footer hint for the focused row: plan tier · deal · peak · `Image`. */\n readonly hint: string\n}\n\n/**\n * Every model this build knows, in checkbox order: plan tier (Go first), then\n * free before paid inside a tier, then by id.\n *\n * The list is the static capability snapshot rather than a live catalog read\n * on purpose — a settings page must draw synchronously, and the snapshot is\n * synced from the same upstream table the picker's tier headings come from.\n * A model added upstream after this build still reaches the user: an empty\n * allowlist shows everything, and a model named in the allowlist but absent\n * here is rendered by the \"Other\" group instead of disappearing.\n */\nexport function commandCodeTuiModelChoices(): readonly TuiModelChoice[] {\n return Object.keys(KNOWN_PLANS)\n .map((id) => ({\n id,\n tier: KNOWN_PLANS[id] ?? '',\n free: isFreeModel(id),\n hint: capabilityDescription(id),\n }))\n .sort((a, b) => {\n const tierDelta = tierRank(a.tier) - tierRank(b.tier)\n if (tierDelta !== 0) return tierDelta\n if (a.free !== b.free) return a.free ? -1 : 1\n return a.id.localeCompare(b.id)\n })\n}\n\n/** Sort rank of a tier key; unknown tiers trail every known one. */\nfunction tierRank(tier: string): number {\n const rank = TIER_ORDER.indexOf(tier)\n return rank === -1 ? TIER_ORDER.length : rank\n}\n\n/** The stored allowlist as a clean id list (non-strings and blanks dropped). */\nfunction storedIds(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((id): id is string => typeof id === 'string' && id !== '')\n : []\n}\n\n/** Everything the section needs from the plugin entry. */\nexport interface CommandCodeTuiSettingsDeps {\n /** The plugin's settings namespace (`llm-commandcode`). */\n ns: string\n /** Section title; defaults to `Command Code`. */\n title?: string\n /**\n * The credential reference the API-key field writes through, read per\n * registration so a `Config.apiKeyEnv` change re-targets the field instead\n * of silently writing to the old reference.\n */\n apiKeyRef: () => string\n /**\n * Account slots for the active-account selector, in rotation order, read\n * per registration. A changed list re-registers the section (see\n * {@link applyCommandCodeTuiSettings}).\n */\n accountSlots: () => readonly { id: string; label: string }[]\n /**\n * The stored model allowlist, read LIVE at save time. A checkbox judges its\n * inherited state against this, so it must be read when the write runs, not\n * captured when the section was registered. An empty list means \"every model\n * is visible\" (the adapter's rule).\n */\n visibleModels: () => readonly string[]\n /**\n * The per-model override map the checkboxes write, read per registration so\n * ids this build's catalog does not know still get a row of their own. Same\n * live-read rule as {@link visibleModels}.\n */\n modelVisibility?: () => Readonly<Record<string, boolean>> | undefined\n /** The models to offer as checkboxes; defaults to the static snapshot. */\n modelChoices?: () => readonly TuiModelChoice[]\n}\n\n/**\n * Build the section descriptor. Pure, so tests can pin the exact fields\n * without a dsh-TUI host.\n *\n * Field choices worth keeping: the two option-bearing fields (`activeAccount`,\n * `lang`) are `text` + `options` rather than `select`, because a `select`\n * cannot express \"unset\" — cycling only ever lands on a declared option, so a\n * `select` would strand the user on a pinned value with no way back to\n * automatic. The `auto` sentinel plus a `parse` that clears the path keeps the\n * unset state reachable. `filterModelsByPlan` formats its EFFECTIVE default\n * (unset means true at the adapter), so a fresh install reads true instead of\n * the screen's \"(empty)\".\n */\nexport function buildCommandCodeTuiSection(\n deps: CommandCodeTuiSettingsDeps,\n): TuiSettingsSection {\n const ref = deps.apiKeyRef()\n const slots = deps.accountSlots()\n const choices = (deps.modelChoices ?? commandCodeTuiModelChoices)()\n const catalogIds = choices.map((choice) => choice.id)\n const known = new Set(catalogIds)\n // An empty allowlist means \"show every model\" at the adapter, so an\n // unchecked-for-no-reason model reads as visible. The stored facts are read\n // live by each field, never captured here.\n const stored = storedIds(deps.visibleModels())\n const overrides = deps.modelVisibility?.() ?? {}\n // Models this build's catalog cannot place (retired or renamed upstream, or\n // added after this snapshot) plus stored-but-unknown ids. They get their own\n // group so they stay visible and switchable instead of silently sticking.\n const extras = [...new Set([...stored, ...Object.keys(overrides)])].filter((id) => !known.has(id))\n\n const tierGroups = TIER_ORDER\n .filter((tier) => choices.some((choice) => choice.tier === tier))\n .map((tier) => ({\n id: `models-${tier}`,\n title: `${TIER_TITLES[tier] ?? tier} models`,\n descriptions: { zh: `${TIER_TITLES[tier] ?? tier} 模型` },\n }))\n // Models this snapshot cannot place (a tier added upstream) share the group\n // with the stored-but-unknown allowlist entries.\n const unranked = choices.filter((choice) => tierRank(choice.tier) === TIER_ORDER.length)\n const otherGroup = unranked.length > 0 || extras.length > 0\n ? [{ id: OTHER_GROUP_ID, title: 'Other models', descriptions: { zh: '其他模型' } }]\n : []\n\n /**\n * One checkbox: a boolean at a path of its OWN (`modelVisibility.<id>`).\n *\n * The path must be unique per model. dsh-TUI keys a staged draft by the\n * field's path (`fieldKey`), so N checkboxes sharing `visibleModels` share\n * ONE draft: every one of them then parses that same draft on save, all N\n * write ops address the same path, and only the LAST field's op survives —\n * which silently rewrote the allowlist from the last catalog model instead\n * of the one that was toggled. A per-model key is what makes a checkbox\n * express one model's state.\n *\n * An override equal to what the array already says is written as a CLEAR, so\n * toggling a model back to its inherited state leaves no residue and the\n * document stays minimal.\n */\n const modelField = (id: string, hint: string, group: string): TuiSettingsField => ({\n path: ['modelVisibility', id],\n group,\n kind: 'boolean',\n label: id,\n ...(hint === '' ? {} : { hint }),\n format: (value) => {\n if (typeof value === 'boolean') return String(value)\n // No override: the model follows the array allowlist, where empty or\n // unset means \"everything is visible\".\n const listed = storedIds(deps.visibleModels())\n return String(listed.length === 0 || listed.includes(id))\n },\n parse: (text) => {\n const on = text.trim() === 'true'\n // Read the array LIVE, not at registration time: the screen stages a\n // toggle and saves it later, and the inherited state must be judged\n // against what the document holds when the write runs.\n const listed = storedIds(deps.visibleModels())\n const inherited = listed.length === 0 || listed.includes(id)\n return on === inherited ? { kind: 'clear' } : { kind: 'set', value: on }\n },\n })\n\n return {\n ns: deps.ns,\n title: deps.title ?? 'Command Code',\n descriptions: { zh: 'Command Code(非官方)' },\n groups: [\n { id: 'connection', title: 'Connection', descriptions: { zh: '连接' } },\n { id: 'models', title: 'Models', descriptions: { zh: '模型' } },\n ...tierGroups,\n ...otherGroup,\n { id: 'advanced', title: 'Advanced', descriptions: { zh: '高级' } },\n ],\n fields: [\n {\n path: ['apiKey'],\n group: 'connection',\n kind: 'text',\n label: 'API key',\n descriptions: { zh: 'API 密钥' },\n secret: { ref },\n hint: `Stored in the credential store as ${ref}, never in settings.yaml.`,\n hintDescriptions: { zh: `保存在凭据库(${ref}),不会写入 settings.yaml。` },\n },\n {\n path: ['apiBase'],\n group: 'connection',\n kind: 'text',\n label: 'API base',\n descriptions: { zh: 'API 地址' },\n placeholder: 'https://api.commandcode.ai',\n hint: 'Leave empty for the public Command Code Provider API.',\n hintDescriptions: { zh: '留空即使用官方 Command Code Provider API。' },\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n },\n {\n path: ['filterModelsByPlan'],\n group: 'models',\n kind: 'boolean',\n label: 'Hide out-of-plan models',\n descriptions: { zh: '隐藏套餐外的模型' },\n hint: 'Keeps models above your subscription tier out of the picker. Fails open.',\n hintDescriptions: { zh: '在选择器里隐藏超出当前订阅档位的模型;判断不出来时全部显示。' },\n // Unset means \"filter\" at the adapter, so render the effective default\n // rather than letting the raw boolean format report an empty value.\n format: (value) => (value === false ? 'false' : 'true'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\n },\n ...choices\n .filter((choice) => tierRank(choice.tier) !== TIER_ORDER.length)\n .map((choice) => modelField(choice.id, choice.hint, `models-${choice.tier}`)),\n ...unranked.map((choice) => modelField(choice.id, choice.hint, OTHER_GROUP_ID)),\n ...extras.map((id) => modelField(id, capabilityDescription(id), OTHER_GROUP_ID)),\n {\n path: ['activeAccount'],\n group: 'advanced',\n kind: 'text',\n label: 'Active account',\n descriptions: { zh: '当前账号' },\n hint: 'A pinned account id, or auto to follow the rotation order.',\n hintDescriptions: { zh: '固定使用某个账号的 id;auto 表示按轮换顺序自动选择。' },\n options: [\n {\n value: ACTIVE_ACCOUNT_AUTO,\n label: 'Automatic (rotation order)',\n descriptions: { zh: '自动(按轮换顺序)' },\n },\n ...slots.map((slot) => ({\n value: slot.id,\n label: slot.label,\n descriptions: { zh: slot.label },\n })),\n ],\n format: (value) => (typeof value === 'string' && value.trim() !== '' ? value : ACTIVE_ACCOUNT_AUTO),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' || trimmed === ACTIVE_ACCOUNT_AUTO\n ? { kind: 'clear' }\n : { kind: 'set', value: trimmed }\n },\n },\n {\n path: ['lang'],\n group: 'advanced',\n kind: 'text',\n label: 'Command language',\n descriptions: { zh: '命令语言' },\n hint: 'Language of the /commandcode dashboard; auto follows the shell locale.',\n hintDescriptions: { zh: '/commandcode 用量面板的语言;auto 跟随终端 locale。' },\n options: [\n { value: LANG_AUTO, label: 'Automatic (shell locale)', descriptions: { zh: '自动(跟随终端 locale)' } },\n { value: 'zh', label: '中文' },\n { value: 'en', label: 'English' },\n ],\n format: (value) => (value === 'zh' || value === 'en' ? value : LANG_AUTO),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' || trimmed === LANG_AUTO\n ? { kind: 'clear' }\n : { kind: 'set', value: trimmed }\n },\n },\n ],\n }\n}\n\n/**\n * The `tuiSettingsSections` service, read defensively.\n *\n * The service name is declared by dsh-TUI's own module augmentation, which\n * this package deliberately does not import, so the typed `Context` has no\n * such property. The read goes through the REFLECTIVE `ctx.get` rather than a\n * bare property access: cordis refuses a property read for a service the fiber\n * never declared in `inject` (`cannot get property … without inject`), and an\n * unmeet seam must degrade to \"no section\" instead of throwing out of the\n * plugin's boot.\n */\nfunction tuiSettingsService(ctx: Context): TuiSettingsSectionsService | undefined {\n let candidate: unknown\n try {\n candidate = ctx.get('tuiSettingsSections')\n } catch {\n return undefined\n }\n if (typeof candidate !== 'object' || candidate === null) return undefined\n const register = (candidate as { register?: unknown }).register\n if (typeof register !== 'function') return undefined\n return {\n register: (register as (section: TuiSettingsSection) => () => void)\n .bind(candidate) as TuiSettingsSectionsService['register'],\n }\n}\n\n/**\n * Identity of everything in the section that can change at runtime: the\n * credential reference behind the API-key field, the account slots behind the\n * active-account selector, and the stored-but-unknown allowlist entries that\n * get a checkbox of their own. Re-registration is skipped while this matches,\n * so ordinary settings writes never churn the screen's section list — the\n * checkboxes themselves read their state live and need no re-declaration.\n */\nfunction sectionSignature(section: TuiSettingsSection): string {\n const active = section.fields.find((field) => field.path.join('.') === 'activeAccount')\n return JSON.stringify({\n secret: section.fields.find((field) => field.secret !== undefined)?.secret?.ref ?? '',\n options: active?.options?.map((option) => option.value) ?? [],\n // Only this group's membership can change the field LIST: every catalog\n // checkbox reads its own state live, so an ordinary toggle needs no\n // re-declaration.\n other: section.fields\n .filter((field) => field.group === OTHER_GROUP_ID)\n .map((field) => field.label),\n })\n}\n\n/**\n * Register the Command Code section on a dsh-TUI host.\n *\n * @param ctx - the context of an activated `tuiSettingsSections` injection.\n * @param deps - plugin-owned facts the section reads.\n * @returns a refresh function that re-registers the section when a fact it\n * renders changed (the plugin entry calls it from its settings `onChange`\n * hook), or `undefined` when the seam is unusable. The returned function is\n * inert after the fiber is torn down.\n */\nexport function applyCommandCodeTuiSettings(\n ctx: Context,\n deps: CommandCodeTuiSettingsDeps,\n): (() => void) | undefined {\n const service = tuiSettingsService(ctx)\n if (service === undefined) return undefined\n let disposed = false\n let current: { signature: string; dispose: () => void } | undefined\n const refresh = (): void => {\n if (disposed) return\n const section = buildCommandCodeTuiSection(deps)\n const signature = sectionSignature(section)\n if (current?.signature === signature) return\n // Withdraw before re-declaring: dsh-TUI keeps one section per namespace,\n // so a second register would otherwise be refused (or shadow the first,\n // depending on the host build) instead of replacing it.\n current?.dispose()\n current = undefined\n try {\n current = { signature, dispose: service.register(section) }\n } catch (error: unknown) {\n // A host that rejects the declaration (a shadow-mode capability policy,\n // a future contract change) must not take the plugin down with it: the\n // terminal simply keeps no Command Code page, and the web page plus\n // settings.yaml stay the fallback.\n ctx.logger?.warn(\n `llm-commandcode: could not register the dsh-TUI settings section: ${\n error instanceof Error ? error.message : String(error)\n }`,\n )\n }\n }\n refresh()\n ctx.effect(() => () => {\n disposed = true\n current?.dispose()\n current = undefined\n }, 'dsh-commandcode-provider: tui settings section')\n return refresh\n}\n","/**\n * A bounded retry budget for `TRANSPORT` failures (issue #39, second report).\n *\n * The route's retry policy (`providerRetryPolicy` in `./adapter.ts`) is\n * deliberately near-unbounded: 1000 attempts with waits doubling to a 15-minute\n * cap. That shape exists for the failures a provider ASKS to have retried — an\n * exhausted 5-hour window, a Cloudflare 520 — where the wait is the point.\n *\n * A transport failure is not that. The reporter's second event at ~710k\n * context was `Connect Timeout Error ... timeout: 10000ms` (undici's own\n * connect timeout; this plugin's `requestTimeoutMs` is 60s) and, on another\n * attempt, `read ECONNRESET` against `/alpha/generate`. Because `TRANSPORT` is\n * in the whitelist, each of those entered the same 1000-attempt loop: with\n * `initialDelayMs: 500` doubling, the wait before attempt 11 alone is 512 s and\n * the cumulative wait before it is ~500 s — the \"模型请求重试已取消(11/1000)·\n * 482s\" the reporter photographed is that 512 s countdown, 30 s into it — and\n * those waits are counted BEFORE each retry attempt, not after it.\n *\n * A connection that cannot be established is either a sub-second blip (the\n * first few attempts recover it, invisibly) or an outage that no amount of\n * waiting inside one request will fix. So transport failures get their own\n * budget, and when it is exhausted the failure is surfaced with the diagnosis\n * instead of manufacturing a multi-minute stall. Waiting out a real outage is\n * the user's call — the next send starts a fresh budget — and\n * `dsh-llm-retry`'s window for rate limits is untouched.\n *\n * Deliberately NOT counted here: the pre-stream recovery the ADAPTER performs\n * inside one `stream()` call (account rotation on 429/401, the 413 image-budget\n * step-down, the Provider-API → CLI protocol switch). Those are invisible to\n * the caller and bounded on their own; this budget caps only the harness's\n * retry loop.\n *\n * Reset rule: the budget clears at each new STEP — one step is exactly one\n * model request (`step/start` is appended immediately before the call) — so the\n * cap is per logical request and the next step of the same turn gets its own\n * grace. `agent/status` → `idle` is NOT the reset signal even though it looks\n * like the natural one: the agent loop's `setPhase` emits it only on a status\n * CHANGE, and a turn's steps all run inside one `running` phase, so it never\n * fires between them — a budget reset only there would be per-turn, and an\n * outage would fail every later step of that turn immediately instead of\n * retrying each. `assistant/attempt` is wrong for the opposite reason: the loop\n * appends it for the FAILED attempt itself, *before* dispatching\n * `agent/request-error`, so resetting on it would clear the budget on every\n * failure and restore the very loop this module exists to stop.\n *\n * @module\n */\n\n/** Failure code this budget covers. */\nexport const TRANSPORT_FAILURE_CODE = 'TRANSPORT'\n\n/**\n * Transport failures to absorb before surfacing the failure, by default.\n *\n * The waits between the attempts come from the route policy's cadence\n * (`initialDelayMs: 500` doubling): the retries this setting buys are scheduled\n * 0.5 s, 1 s, 2 s, 4 s and 8 s after the failures that preceded them, so the\n * default absorbs an ordinary blip for ~15.5 s and then reports the failure\n * instead of continuing into the 16 s, 32 s … 15-minute waits. (Those figures\n * are the waits BEFORE each retry attempt, which is how the harness's own retry\n * chrome counts them — the `· 482s` on the reporter's row is one such wait.)\n */\nexport const DEFAULT_TRANSPORT_MAX_RETRIES = 5\n\n/**\n * Ceiling for {@link DEFAULT_TRANSPORT_MAX_RETRIES}'s setting.\n *\n * Deliberately far above the default rather than near it: raising the budget is\n * a legitimate answer to a genuinely flaky link, and the cap is a plausibility\n * bound, not a recommendation. The same number is mirrored in `Config`'s schema\n * and in the settings page's field bound (the client bundle cannot import this\n * node-side module); `tests/transport-retry.test.ts` pins the schema's bound\n * against this constant, which is what makes a drift visible.\n */\nexport const MAX_TRANSPORT_MAX_RETRIES = 50\n\n/** Why {@link absorbTransportFailure} answered the way it did. */\nexport type TransportRetryDecision = 'retry' | 'exhausted' | 'ignored'\n\n/** One agent's live transport-failure count, keyed weakly so a dropped agent cannot leak. */\nconst counts = new WeakMap<object, number>()\n\n/**\n * Count one attempt's outcome against the transport budget.\n *\n * @param agent - the identity the budget is scoped to (the agent object).\n * @param failureCode - the failed attempt's `LlmFailure.code`.\n * @param maxRetries - transport retries to absorb before the failure surfaces.\n * @returns `'ignored'` for any non-transport code (the route policy decides\n * those, unchanged), `'retry'` while the budget has room, `'exhausted'` once\n * it does not.\n */\nexport function absorbTransportFailure(\n agent: object,\n failureCode: string,\n maxRetries: number,\n): TransportRetryDecision {\n if (failureCode !== TRANSPORT_FAILURE_CODE) return 'ignored'\n const used = counts.get(agent) ?? 0\n if (used >= maxRetries) return 'exhausted'\n counts.set(agent, used + 1)\n return 'retry'\n}\n\n/** Clear one agent's transport budget (a new step starts, or the turn ended). */\nexport function resetTransportFailures(agent: object): void {\n counts.delete(agent)\n}\n\n/**\n * What one session event means for the transport budget.\n *\n * Exported and pure on purpose: the choice of event is the part of this design\n * that is easy to get plausibly wrong (`agent/status` → `idle` looks like the\n * natural reset and is not one — see the module comment), so it is stated once,\n * here, where a test can pin it, instead of being implied by a listener body.\n *\n * @param type - the appended session event's type.\n * @returns `'reset'` for a new step (one model request), `'forget'` when the\n * turn ended and the session → agent mapping is no longer needed, otherwise\n * `'none'`.\n */\nexport function transportResetAction(type: string): 'reset' | 'forget' | 'none' {\n if (type === 'step/start') return 'reset'\n if (type === 'turn/end') return 'forget'\n return 'none'\n}\n\n/**\n * The diagnosis a capped turn ends with. Bilingual, because the harness renders\n * a failed turn's message verbatim and this plugin's other user-facing failures\n * are bilingual too (see the adapter's error builders). It names the retry\n * budget and the checks that actually help, instead of the bare \"fetch failed\"\n * chain the retry chrome would otherwise show.\n */\nexport function transportBudgetMessage(failureMessage: string, maxRetries: number): string {\n return `${failureMessage}`\n + ';Command Code API 连接在连续重试后仍失败——已停止重试以免整轮卡死。'\n + `插件已自动重试 ${maxRetries} 次。通常说明当前网络到 api.commandcode.ai 的连接不通,`\n + '常见原因是代理未生效:DSH 只读取环境变量 HTTPS_PROXY/HTTP_PROXY(系统代理/PAC 不会被读取),'\n + '请确认启动 DSH 的终端里已导出代理,或先关闭代理直连后重试。网络恢复后直接重发即可'\n + ` — Command Code API transport still failed after ${maxRetries} automatic retries, which were`\n + ' stopped so the turn could not stall for minutes. This is a connectivity problem between this'\n + ' machine and api.commandcode.ai, not a context-window or request-size rejection. Common cause:'\n + ' the proxy is not reaching the harness — DSH reads HTTPS_PROXY/HTTP_PROXY from the environment'\n + ' only (a Windows system proxy/PAC setting is not consulted), so export it in the launching'\n + ' shell, or turn the proxy off and retry. Resend when the network recovers; the budget is per'\n + ' request and has been reset'\n}\n","/**\n * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command\n * Code (unofficial; ported from pi-commandcode-provider@0.5.1).\n *\n * Registers the `commandcode` provider route on `ctx.llm` and declares it in\n * the configurable-provider directory, so the web Models page shows a\n * \"Command Code\" card with an API-key field and the model picker lists the\n * live Command Code model catalog. Connection facts resolve per request over\n * the optional `llm-commandcode` user-settings section and the credential\n * seam, so a changed key, endpoint, or cache path reaches the next request\n * without a restart.\n *\n * ```yaml\n * - id: llm-commandcode\n * name: \"@mars-sea/dsh-commandcode-provider\"\n * config:\n * apiKeyEnv: COMMANDCODE_API_KEY\n * ```\n *\n * The `name` is the full package specifier as installed in the profile's\n * node_modules: the loader imports it as a module, and pnpm links packages by\n * their true (scoped) name — a bare `dsh-commandcode-provider` fails to\n * resolve (ERR_MODULE_NOT_FOUND) and crashes the app on boot. The value must\n * be quoted in YAML: an unquoted scalar starting with `@` fails to parse.\n *\n * @module dsh-commandcode-provider\n */\n\nimport { installCostProjection } from './cost-projection.ts'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { RequestErrorAction } from '@deepseek-ai/dsh-agent'\nimport type { WebRuntime } from '@deepseek-ai/dsh-web'\nimport z from '@deepseek-ai/schemastery'\nimport { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'\nimport { assertUsableApiKey, LlmError } from '@deepseek-ai/dsh-llm'\nimport { credentialRef, type CredentialRef } from '@deepseek-ai/dsh-credentials'\nimport { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'\nimport type {} from '@deepseek-ai/dsh-settings'\nimport { CommandCodeAdapter, DEFAULT_API_BASE, resolveAuthFileApiKey } from './adapter.ts'\nimport { DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS } from './adapter.ts'\nimport type { CommandCodeConnectionOptions, CommandCodeUsageReport } from './adapter.ts'\nimport { CommandCodeAccountPool, accountUsable, selectActiveAccount } from './accounts.ts'\nimport type { CommandCodeAccountConfig, CommandCodeAccountSlot, CommandCodeModelAccountRule } from './accounts.ts'\nimport { applyCommands } from './commands.ts'\nimport { applyUsageRemote } from './usage-remote.ts'\nimport type { CommandCodeAccountsReport, CommandCodeCatalog } from './usage-wire.ts'\nimport { CommandCodeLoginFlow } from './login.ts'\nimport type { CommandCodeLoginCredentials } from './login.ts'\nimport { pickCommandLocale, type LocaleId } from './command-locales.ts'\nimport { CommandCodeSearchProvider, applyCommandCodeSearchSelection, commandCodeSearchSelection } from './web-search.ts'\nimport { applyCommandCodeTuiSettings } from './tui-settings.ts'\nimport {\n DEFAULT_TRANSPORT_MAX_RETRIES,\n MAX_TRANSPORT_MAX_RETRIES,\n TRANSPORT_FAILURE_CODE,\n absorbTransportFailure,\n resetTransportFailures,\n transportBudgetMessage,\n transportResetAction,\n} from './transport-retry.ts'\nimport { KNOWN_PLANS } from './capabilities.ts'\n\nexport {\n COMMAND_CODE_CLI_VERSION,\n DEFAULT_API_BASE,\n DEFAULT_GENERATE_MAX_TOKENS,\n DEFAULT_MAX_OUTPUT_TOKENS,\n DEFAULT_REQUEST_TIMEOUT_MS,\n DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n CommandCodeAdapter,\n BILLING_ACCESS_TTL_MS,\n projectSlugFromPath,\n resolveAuthFileApiKey,\n} from './adapter.ts'\nexport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n KNOWN_THINKING_MODELS,\n KNOWN_PLANS,\n KNOWN_SUBSCRIPTION_PLANS,\n KNOWN_DEALS,\n KNOWN_PEAK_PRICING,\n PLAN_LABELS,\n PLAN_ORDER,\n capabilityDescription,\n compareByPlan,\n dealLabel,\n formatContext,\n modelVisibleInPlan,\n peakPricingLabel,\n peakPricingState,\n planLabel,\n subscriptionPlanInfo,\n} from './capabilities.ts'\nexport type { CommandCodeAdapterDeps, CommandCodeConnectionOptions, CommandCodeUsageReport, ResolveAttachments } from './adapter.ts'\nexport type { CommandCodeBillingAccess } from './capabilities.ts'\nexport { applyCommands, commandDefinition } from './commands.ts'\nexport type { CommandCodeCommandDeps } from './commands.ts'\nexport { applyUsageRemote, CommandCodeUsageService } from './usage-remote.ts'\nexport type { CommandCodeUsageDeps, LoginFlowFacade } from './usage-remote.ts'\nexport { USAGE_REPORT_ENDPOINT, usageReportSchema } from './usage-wire.ts'\nexport type { CommandCodeAccountUsage, CommandCodeAccountsReport } from './usage-wire.ts'\nexport {\n LOGIN_BEGIN_ENDPOINT,\n LOGIN_STATUS_ENDPOINT,\n LOGIN_CANCEL_ENDPOINT,\n parseLoginStatus,\n loginStatusSchema,\n} from './login-wire.ts'\nexport type {\n CommandCodeLoginStatus,\n CommandCodeLoginFailureReason,\n} from './login-wire.ts'\nexport {\n LOGIN_TIMEOUT_MS,\n LOGIN_START_PORT,\n LOGIN_MAX_PORT_ATTEMPTS,\n LOGIN_BODY_LIMIT_BYTES,\n LOGIN_ALLOWED_ORIGINS,\n buildCommandAuthUrl,\n studioBaseForApiBase,\n validateCommandApiKey,\n CommandCodeLoginFlow,\n} from './login.ts'\nexport type {\n CommandCodeLoginCredentials,\n CommandCodeLoginFlowDeps,\n ApiKeyValidation,\n} from './login.ts'\nexport { CommandCodeAccountPool, accountUsable, selectActiveAccount, matchModelRule, selectAccountForModel } from './accounts.ts'\nexport type { CommandCodeAccountConfig, CommandCodeAccountSlot, CommandCodeAccountState, CommandCodeModelAccountRule } from './accounts.ts'\nexport { CommandCodeSearchProvider, COMMANDCODE_SEARCH_PROVIDER_ID, DEFAULT_WEB_SEARCH_PROVIDER_ID, applyCommandCodeSearchSelection, commandCodeSearchSelection, selectCommandCodeSearchProvider } from './web-search.ts'\nexport type { CommandCodeSearchSelection } from './web-search.ts'\nexport type { CommandCodeSearchProviderDeps } from './web-search.ts'\nexport { ACTIVE_ACCOUNT_AUTO, LANG_AUTO, applyCommandCodeTuiSettings, buildCommandCodeTuiSection } from './tui-settings.ts'\nexport type {\n CommandCodeTuiSettingsDeps,\n TuiSettingsField,\n TuiSettingsFieldOption,\n TuiSettingsFieldWrite,\n TuiSettingsGroup,\n TuiSettingsSection,\n TuiSettingsSectionsService,\n} from './tui-settings.ts'\n\nexport const name = 'llm-commandcode'\nexport const inject = ['llm']\n\nconst NS = 'llm-commandcode'\nconst DEFAULT_API_KEY_ENV = 'COMMANDCODE_API_KEY'\n\n/** The single provider route this plugin owns. */\nexport const PROVIDER = 'commandcode'\n/** Default models cache path (mirrors the pi plugin's on-disk cache). */\nexport const DEFAULT_MODELS_CACHE_PATH = join(homedir(), '.commandcode', 'models-cache.json')\n\n/**\n * Plugin config, validated by the same-named schemastery schema and doubling\n * as the `llm-commandcode` settings-section shape. Every field is optional:\n * a missing API key resolves through {@link Config.apiKeyEnv} at each request\n * (the web Models page writes it), with the official Command Code CLI auth\n * file (`~/.commandcode/auth.json`) as the last fallback.\n */\nexport interface Config {\n /** Credential reference (environment-variable name) resolved per request; defaults to `COMMANDCODE_API_KEY`. */\n apiKeyEnv?: string\n /** Literal API key override (composition config only); takes precedence over `apiKeyEnv`. */\n apiKey?: string\n /** API base; defaults to the public Command Code Provider API. */\n apiBase?: string\n /** Working directory reported to the API; defaults to the process cwd. */\n workingDir?: string\n /** Model catalog cache path; defaults to `~/.commandcode/models-cache.json`. */\n modelsCachePath?: string\n /** Milliseconds to wait for the generate response's first byte; defaults to 60s. */\n requestTimeoutMs?: number\n /** Milliseconds a stream may stall before being treated as a dead connection; defaults to 300s. */\n streamIdleTimeoutMs?: number\n /**\n * Transport failures one request absorbs before the failure is surfaced;\n * defaults to 5. The route's retry policy is near-unbounded on purpose (1000\n * attempts, waits doubling to 15 minutes) because that shape is for the\n * failures a provider asks to have retried — an exhausted rate-limit window,\n * a gateway 520. A transport failure is not one of those: the first attempts\n * recover an ordinary blip (the default 5 retries are scheduled 0.5/1/2/4/8 s\n * after the failures before them, so ~15.5 s of grace), and after that the\n * wait is pure stall, so the retries are capped here. Raise it on a genuinely\n * flaky link; 0 surfaces every transport failure immediately.\n */\n transportMaxRetries?: number\n /**\n * Whether the model picker hides models above the account's subscription\n * tier; defaults to true. The filter fails open (unknown plan, billing\n * endpoint failure, or a positive on-demand credit balance all keep the\n * full catalog visible). Set false to always list every model.\n */\n filterModelsByPlan?: boolean\n /**\n * Visible-model allowlist: catalog model ids shown in pickers. Empty or\n * unset means \"show everything\". Persisted by the settings page's model\n * filter card; applies after the subscription-tier filter.\n */\n visibleModels?: string[]\n /**\n * Per-model visibility overrides from the terminal settings page's checkbox\n * list, keyed by catalog id (`true` = listed, `false` = hidden). An id here\n * decides that model on its own; an id absent here follows `visibleModels`.\n * dsh-TUI keys a staged edit by the field's path, so the checkboxes need one\n * path per model — a map — because a boolean field cannot express \"this id\n * is a member of the array\".\n */\n modelVisibility?: Record<string, boolean>\n /**\n * Extra accounts for multi-account rotation. The top-level\n * `apiKey`/`apiKeyEnv` (plus the CLI auth file) always form the first\n * (`default`) account; each entry here adds one more. When a request is\n * rejected pre-stream with 429 (usage window exhausted) or 401, the next\n * account's key retried transparently; when every account is exhausted the\n * request fails with a `RATE_LIMIT` error naming the earliest window\n * reset. Entries without `apiKey` or `apiKeyEnv` are ignored.\n */\n accounts?: CommandCodeAccountConfig[]\n /**\n * Manually selected active account: a slot id — `default`, or an extra\n * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). The\n * selected account serves whenever it is usable; an unknown id or an\n * exhausted selected account falls back to the first usable slot (automatic\n * rotation still applies). Unset means \"first usable account\".\n */\n activeAccount?: string\n /**\n * Model → account routing rules. Each rule lists catalog model ids to an\n * account slot id (`default`, or an extra account's credential reference).\n * When a request's model is in a rule's list and the routed account is\n * usable, that account serves — before the manual {@link activeAccount} and\n * the passive rotation order. A routed account that is exhausted or invalid\n * falls back to the normal selection, so the router is a hint, never a hard\n * gate. The first matching rule wins.\n */\n modelAccountRules?: CommandCodeModelAccountRule[]\n /**\n * Whether to use Command Code as the backend for dsh's model-facing\n * `web_search` tool. When enabled, the plugin registers a `commandcode`\n * search provider on `ctx.web` AND selects `commandcode` in the web seam\n * (so it wins over the shipped `deepseek-official` or a sibling search\n * plugin's pin), using the SAME Command Code API key/base as chat. When\n * disabled, the selection is handed back to whichever backend was there\n * before — turning it off never forces the factory default, so a sibling\n * search plugin (e.g. modsearch) keeps working (issue #26). The rewrite\n * rides dsh's internal `searchProviderId`, which is read per search call,\n * so a setting change lands on the next search without a restart.\n * Defaults to true.\n */\n webSearch?: boolean\n /**\n * Whether the Web sidebar shows the plans & quota card\n * (`sidebar.footer.action`). Defaults to false: the card is opt-in, so an\n * unset document renders no quota surface in the sidebar and mounts no\n * background usage poll for it. Only the sidebar entry is affected — the\n * dashboard cell behind it stays registered, it simply has no trigger until\n * the toggle is on. Read by the browser client; the adapter ignores it.\n */\n showSidebarQuota?: boolean\n /**\n * Language override for the `/commandcode` Host-side command's user-facing\n * copy. Host commands cannot read the client's `ctx.locale`, so this is\n * the explicit knob: `'zh'` or `'en'`. Unset means the command reads\n * `LC_ALL`/`LANG` from the launching shell, falling back to `'zh'`. The\n * web settings page is unaffected — it follows the browser's language\n * preference on its own. Two surfaces, two independent locales. The\n * declared type is `string` (the schemastery `pattern` cannot narrow\n * literal types); an unknown value is treated as \"unset\" by\n * `pickCommandLocale`.\n */\n lang?: string\n}\n\nexport const Config: z<Config> = z.object({\n apiKeyEnv: z.string().role('credential-ref').default(DEFAULT_API_KEY_ENV),\n // `role('secret')` is load-bearing, not decoration: a literal key is the one\n // credential path this plugin cannot keep out of a settings document (the\n // page writes through the credentials seam instead), so the harness must\n // strip it from every descriptor read (`settings.describe()` runs with\n // `redactSecrets: true`). Without the role the literal rides back to the\n // browser verbatim — including on a remote-Host setup, where that is another\n // machine. Same declaration as the official providers' `apiKey` field.\n apiKey: z.string().role('secret'),\n apiBase: z.string(),\n workingDir: z.string(),\n modelsCachePath: z.string(),\n requestTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),\n streamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),\n transportMaxRetries: z.number().min(0).max(MAX_TRANSPORT_MAX_RETRIES),\n filterModelsByPlan: z.boolean(),\n visibleModels: z.array(z.string()),\n /**\n * Per-model visibility overrides for the terminal settings page's checkbox\n * list, keyed by catalog id. dsh-TUI addresses a staged edit by its field\n * PATH, so two checkboxes sharing one path would overwrite each other's\n * draft and the section's last model would decide every write; a map gives\n * each checkbox a path of its own. An id listed here wins over\n * {@link visibleModels}; ids absent here keep following it.\n */\n modelVisibility: z.dict(z.boolean()),\n webSearch: z.boolean().default(true),\n showSidebarQuota: z.boolean().default(false),\n accounts: z.array(z.object({\n label: z.string(),\n apiKeyEnv: z.string().role('credential-ref'),\n /** Literal key for one extra slot; see the top-level `apiKey` secret note. */\n apiKey: z.string().role('secret'),\n })),\n activeAccount: z.string(),\n modelAccountRules: z.array(z.object({\n models: z.array(z.string()),\n account: z.string(),\n })),\n lang: z.string().pattern(/^(zh|en)$/).default('zh' as const),\n})\n\n/** One resolution's complete request facts: connection plus credential reference. */\nexport interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {\n apiKeyEnv: CredentialRef\n}\n\n/**\n * The one explicit resolve step from raw config to validated connection\n * facts. Programmatic construction may bypass Schemastery normalization, so\n * every default is re-judged here — for the composition entry at load and for\n * each settings snapshot at its first use.\n */\nexport function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions {\n return {\n apiKeyEnv: credentialRef(config.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n apiBase: config.apiBase ?? DEFAULT_API_BASE,\n workingDir: config.workingDir ?? process.cwd(),\n modelsCachePath: config.modelsCachePath ?? DEFAULT_MODELS_CACHE_PATH,\n requestTimeoutMs: config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,\n streamIdleTimeoutMs: config.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS,\n filterModelsByPlan: config.filterModelsByPlan ?? true,\n visibleModels: Array.isArray(config.visibleModels)\n ? config.visibleModels.filter((id) => typeof id === 'string' && id !== '')\n : undefined,\n // Only real booleans survive: a hand-edited document can carry anything,\n // and a malformed flag must fall back to the array rather than hide a\n // model. An all-empty map is the same as no map.\n modelVisibility: readModelVisibility(config.modelVisibility),\n }\n}\n\n/**\n * Per-model visibility overrides, cleaned for the adapter. Programmatic\n * construction may bypass Schemastery normalization, so a non-object or a\n * non-boolean entry is dropped here instead of reaching the picker filter.\n * @param raw - The `modelVisibility` value from any config source.\n * @returns A frozen id → boolean map, or undefined when nothing is set.\n */\nfunction readModelVisibility(raw: unknown): Readonly<Record<string, boolean>> | undefined {\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return undefined\n const entries = Object.entries(raw).filter(\n (entry): entry is [string, boolean] => entry[0] !== '' && typeof entry[1] === 'boolean',\n )\n return entries.length === 0 ? undefined : Object.fromEntries(entries)\n}\n\nexport function apply(ctx: Context, config: Config): void {\n installCostProjection(ctx)\n let current: () => Config = () => config\n let lastRaw: Config | undefined\n let lastGood: ResolvedCommandCodeOptions | undefined\n const options = (): ResolvedCommandCodeOptions => {\n const raw = current()\n if (raw === lastRaw && lastGood !== undefined) return lastGood\n const next = resolveAdapterOptions(raw)\n lastRaw = raw\n lastGood = next\n return next\n }\n options()\n\n // The account slots, rebuilt from the live config on every resolution so\n // a settings-page accounts change reaches the very next request. The\n // top-level apiKey/apiKeyEnv (+ the CLI auth file) form the default\n // account; each config.accounts entry adds one more.\n const slots = (): CommandCodeAccountSlot[] => {\n const raw = current()\n const list: CommandCodeAccountSlot[] = [{\n id: 'default',\n label: 'Default',\n ref: credentialRef(raw.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n literal: raw.apiKey,\n allowAuthFile: true,\n }]\n for (const [index, account] of (raw.accounts ?? []).entries()) {\n const refName = typeof account.apiKeyEnv === 'string' && account.apiKeyEnv.trim() !== ''\n ? account.apiKeyEnv.trim()\n : undefined\n const literal = typeof account.apiKey === 'string' && account.apiKey !== '' ? account.apiKey : undefined\n if (refName === undefined && literal === undefined) continue\n list.push({\n // Slot ids must survive account-list edits: an extra's id is its\n // credential reference (stable across reorders/removals), falling\n // back to the positional id only for literal-only composition\n // entries, which no settings document can name anyway.\n id: refName ?? `account-${index + 2}`,\n label: typeof account.label === 'string' && account.label.trim() !== ''\n ? account.label.trim()\n : `Account ${index + 2}`,\n ref: refName === undefined ? undefined : credentialRef(refName),\n literal,\n allowAuthFile: false,\n })\n }\n return list\n }\n\n // The manually selected account (settings page / config), re-read per\n // resolution like every other settings-backed fact.\n const preferredId = (): string | undefined => {\n const raw = current().activeAccount\n return typeof raw === 'string' && raw.trim() !== '' ? raw.trim() : undefined\n }\n\n const resolveRef = async (ref: ReturnType<typeof credentialRef>): Promise<string | undefined> => {\n const credentials = ctx.get('credentials')\n if (credentials !== undefined) {\n // The credentials seam layers the process environment, the\n // provider-managed store, and `.env` files itself — a miss here is\n // genuinely unconfigured, not \"not in the store\".\n const hit = await credentials.resolve(ref)\n return hit?.value\n }\n const ambient = launchEnvironmentOf(ctx).get(ref)\n return ambient !== undefined && ambient.value.length > 0 ? ambient.value : undefined\n }\n\n // The multi-account pool: passive rotation only — a key is marked when a\n // request using it is actually rejected (429/401), and the marks are\n // re-checked against the live window limits only once every account is\n // marked, so the steady state costs zero extra API calls.\n // Explicit annotations break the pool↔adapter inference cycle (the pool's\n // probe calls the adapter; the adapter's rotation hook calls the pool).\n const pool: CommandCodeAccountPool = new CommandCodeAccountPool({\n slots,\n resolveRef,\n authFileKey: resolveAuthFileApiKey,\n // The adapter reference is assigned right below; the probe runs only at\n // request time, never during plugin startup.\n probeWindow: (apiKey: string) => adapter.probeFiveHourWindow(apiKey),\n preferredId,\n // Model → account routing rules, re-read per resolution like every\n // settings-backed fact.\n modelAccountRules: (): readonly CommandCodeModelAccountRule[] => current().modelAccountRules ?? [],\n })\n\n const resolveApiKey = async (connection: ResolvedCommandCodeOptions, model?: string): Promise<string> => {\n const resolved = await pool.resolveKey(model === undefined ? {} : { model })\n if (resolved !== undefined) {\n return assertUsableApiKey(resolved.key, 'llm-commandcode', resolved.slot.ref ?? `${resolved.slot.label} (config.apiKey)`)\n }\n const ref = connection.apiKeyEnv\n throw new LlmError(\n `llm-commandcode: no API key for provider route \"${PROVIDER}\"; store ${ref} through the`\n + ' credentials service (the web Models page writes it), export it in the launching'\n + ' environment, set config.apiKey, or run `command-code login` to write'\n + ' ~/.commandcode/auth.json',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter: CommandCodeAdapter<ResolvedCommandCodeOptions> = new CommandCodeAdapter({\n options,\n resolveApiKey,\n // Pre-stream 429/401: mark the rejected key and hand the adapter the next\n // account's key. When every account is exhausted the pool throws the\n // RATE_LIMIT/INVALID_CREDENTIAL error that names the earliest reset —\n // that error, not the raw 429, is what the caller sees.\n rotateApiKey: async (rejectedKey: string, rejection: 'rate-limit' | 'invalid-credential', _connection: ResolvedCommandCodeOptions, model?: string): Promise<string | undefined> => {\n pool.markRejected(rejectedKey, rejection)\n // Exclude the just-rejected key from probe-revival: a probe clearing its\n // window must not re-offer the same key within this request (the\n // adapter refuses already-tried keys); the next request picks it up.\n // The model rides along so model-routing rules pick the next account\n // for the same model.\n const resolved = await pool.resolveKey(\n model === undefined ? { exclude: rejectedKey } : { exclude: rejectedKey, model },\n )\n // Normalize like the initial resolution does: the pool keys its state\n // by the resolved key, so the adapter must send (and report back) the\n // same normalized form or the marks would miss.\n return resolved === undefined\n ? undefined\n : assertUsableApiKey(resolved.key, 'llm-commandcode', resolved.slot.ref ?? `${resolved.slot.label} (config.apiKey)`)\n },\n // The durable attachment service carries image bytes referenced by\n // ImageBlock; resolved lazily only when a request actually has images.\n resolveAttachments: () => {\n const attachments = ctx.get('attachments')\n return attachments === undefined ? undefined : attachments\n },\n })\n // The Models page card: a configurable provider with a settings address.\n // settingsPath [] means the whole `llm-commandcode` section configures it.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n // The live route: this is what makes models requestable under `commandcode`.\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n // Bounded retry for TRANSPORT failures (issue #39, second report). The route\n // policy is near-unbounded on purpose (see `providerRetryPolicy`), because\n // an exhausted rate-limit window or a gateway 520 is a failure that ASKS to\n // be retried — but a connection that cannot be established is not, and at the\n // long-context sizes this plugin serves the unbounded cadence turned a\n // 10-second TCP connect timeout into an ~8-minute stall (the reporter's\n // 11/1000 row, whose \"482s\" is the wait before the 11th attempt). So the\n // first few transport failures are absorbed here and the rest surface with a\n // diagnosis. `dsh-llm-retry` keeps its window for every other code.\n //\n // The failure is surfaced by THROWING out of the waterfall: the agent loop\n // wraps the rejection into the turn's error, so the retry chain stops here.\n // The failure's own message is carried in the thrown message (the loop may\n // re-wrap with the original), and the diagnostic also goes to the log, which\n // nothing can rewrite.\n const transportMaxRetries = (): number => {\n const value = current().transportMaxRetries\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) return DEFAULT_TRANSPORT_MAX_RETRIES\n return Math.min(Math.trunc(value), MAX_TRANSPORT_MAX_RETRIES)\n }\n // `async` is a type-level requirement, not a behavior change: the waterfall's\n // listener contract is `=> Promise<RequestErrorAction>`, so a handler that\n // returns `next()`'s promise on one path and a bare decision on another does\n // not type-check (`Promise<RequestErrorAction> | { kind: 'retry' }` is not\n // assignable, even though the runtime accepts both).\n //\n // The session → agent map exists for the reset below: `session/event` carries\n // the session, and the agent is the natural budget key (it is what the\n // request-error payload hands over). Weak on BOTH sides so a long-lived Host\n // cannot be held open by sessions whose turn never appended a `turn/end`.\n const sessionAgents = new WeakMap<object, object>()\n ctx.on('agent/request-error', async ({ agent, failure, signal }, next) => {\n // Checked BEFORE the budget: a cancelled turn is the user's own stop, so it\n // must neither be answered with a retry nor consume the slot a later live\n // failure needs.\n if (signal.aborted) return next()\n const session: unknown = Reflect.get(agent, 'session')\n if (typeof session === 'object' && session !== null) sessionAgents.set(session, agent)\n const decision = absorbTransportFailure(agent, failure.code, transportMaxRetries())\n if (decision === 'ignored') return next()\n // The literal is spelled as the event's own decision type; the union this\n // handler returns (`RequestErrorAction | Promise<RequestErrorAction>`) is\n // what the waterfall accepts, and `{ kind: 'retry' }` alone widens to\n // `string` and stops matching it.\n if (decision === 'retry') return { kind: 'retry' } satisfies RequestErrorAction\n const message = transportBudgetMessage(failure.message, transportMaxRetries())\n ctx.logger.warn(`llm-commandcode: transport retry budget exhausted for ${PROVIDER} (${TRANSPORT_FAILURE_CODE})`)\n throw new Error(message)\n })\n // Reset the budget at each new STEP — one step is exactly one model request\n // (`step/start` is appended immediately before the call), so this is what\n // makes the cap \"per logical request\" and gives the next step of the same\n // turn its own grace. `agent/status` → `idle` is deliberately NOT the reset\n // signal: `setPhase` emits it only on a status CHANGE, and a turn's steps run\n // inside one `running` phase, so it never fires between them — a budget reset\n // only there would be per-turn, and a network outage would fail every later\n // step of that turn instantly instead of retrying each. `assistant/attempt`\n // is wrong for the opposite reason: the loop appends it for the FAILED\n // attempt before dispatching `agent/request-error`, so resetting on it would\n // clear the budget on every failure. `idle` still clears the agent's count,\n // and the WeakMap drops a finished session on its own.\n ctx.on('session/event', (session, event) => {\n const action = transportResetAction(event.type)\n if (action === 'forget') {\n sessionAgents.delete(session)\n return\n }\n if (action !== 'reset') return\n const agent = sessionAgents.get(session)\n if (agent !== undefined) resetTransportFailures(agent)\n })\n ctx.on('agent/status', ({ agent, status }) => {\n if (status === 'idle') resetTransportFailures(agent)\n })\n\n // Per-account usage for the /commandcode dashboard and the settings\n // page's account card: every pool account (configured or not) gets one\n // entry, each fetched with its own key so plan/credit facts never mix.\n const usageReports = async (): Promise<CommandCodeAccountsReport> => {\n // describeAccounts (not deduped) so two slots sharing one credential are\n // both reported as configured; the active badge follows the deduped\n // serving selection.\n const described = await pool.describeAccounts()\n const byId = new Map(described.map((account) => [account.slot.id, account]))\n const active = selectActiveAccount(await pool.resolvedAccounts(), preferredId())\n const entries = await Promise.all(slots().map(async (slot) => {\n const account = byId.get(slot.id)\n let report: CommandCodeUsageReport\n if (account === undefined) {\n report = { failures: [] }\n } else {\n try {\n report = await adapter.getUsage(account.key)\n } catch (error: unknown) {\n report = { failures: [error instanceof Error ? error.message : String(error)] }\n }\n }\n const state = account?.state\n // The mark mirrors servability: a usable account (never marked, or a\n // cooldown whose reset passed) shows no mark; a cooldown without a\n // known reset still shows \"rate-limit\" (it is not serving).\n const usable = accountUsable(state)\n return {\n id: slot.id,\n label: slot.label,\n configured: account !== undefined,\n active: account !== undefined && active?.slot.id === slot.id,\n mark: usable ? '' : state?.kind === 'disabled' ? 'invalid-credential' : 'rate-limit',\n cooldownUntil: !usable && state?.kind === 'cooldown' ? state.until : 0,\n report,\n }\n }))\n return { accounts: entries }\n }\n\n // The /commandcode usage command rides the optional `commands` service: a\n // child fiber injects it, so it registers whenever the profile mounts\n // dsh-commands and the fiber simply never activates when it does not.\n // The command runs Host-side and has no access to the client's locale\n // service, so its language is resolved here from `Config.lang` (explicit\n // override) and the launching shell's `LC_ALL`/`LANG` (inferred default);\n // resolved per invocation so a settings change reaches the next command\n // run without a restart.\n const commandLocale = (): LocaleId => pickCommandLocale(current().lang)\n ctx.inject(['commands'], (commandCtx) => {\n applyCommands(commandCtx, { adapter, reports: usageReports, getLocale: commandLocale })\n })\n\n // The settings page's account card: getUsage exposed to the browser through\n // the Typert Gateway (`commandcode/report`). Rides the optional `typert`\n // registry service, so profiles without the web stack never activate it.\n // The same service also exposes the browser-login flow: the Host binds a\n // loopback callback server (the official `command-code login` dance) and\n // stores the delivered key through the credentials seam under the same\n // reference the default slot resolves — no restart, no settings document.\n const loginFlow = new CommandCodeLoginFlow({\n apiBase: () => options().apiBase,\n storeKey: async ({ apiKey }: CommandCodeLoginCredentials): Promise<void> => {\n const ref = credentialRef(current().apiKeyEnv ?? DEFAULT_API_KEY_ENV)\n const credentials = ctx.get('credentials')\n if (credentials === undefined) {\n throw new Error('the credentials service is unavailable in this profile; paste the key manually')\n }\n await credentials.set(ref, apiKey)\n },\n })\n ctx.effect(() => () => loginFlow.dispose(), 'dsh-commandcode-provider: login flow')\n // The full model catalog for the settings page's model editors (the\n // routing-rule editor and the visible-models filter): served Host-side\n // from the adapter's cached/fetched catalog (sorted for picking), so the\n // browser never calls the Command Code API directly. Unfiltered, so an\n // editor never loses its own options — e.g. a rule can route a GOAT-only\n // model while the picker (plan-filtered + allowlisted) hides it. Each\n // entry carries its plan-tier key so the editors can group under tier\n // headings without importing the Host's capability snapshot.\n const catalogForEditors = async (): Promise<CommandCodeCatalog> => {\n const models = await adapter.listModels(PROVIDER, { unfiltered: true })\n return {\n models: models.map((model) => {\n const tier = KNOWN_PLANS[model.id]\n return {\n id: model.id,\n name: model.name.replace(/\\s*\\(CC\\)$/, ''),\n ...(tier === undefined ? {} : { tier }),\n }\n }),\n }\n }\n applyUsageRemote(ctx, { adapter, reports: usageReports, login: loginFlow, listModels: catalogForEditors })\n\n // Web search over the Command Code Provider API, exposed through the web\n // capability seam (`ctx.web`). Rides the optional `web` service: a child\n // fiber injects it, so the provider registers whenever the profile mounts\n // the web stack and the fiber never activates when it does not (profiles\n // without web remain an LLM-provider-only plugin). It reuses the SAME\n // credential chain as the model adapter (pool.resolveKey → env → auth file)\n // and the same apiBase, so DSH's model-facing web_search tool needs no\n // separate key or endpoint config — a Command Code key works as-is.\n //\n // Whether the `commandcode` provider WINS over the shipped `deepseek-official`\n // (or a sibling search plugin's pin, e.g. modsearch) is controlled by\n // `Config.webSearch` (default on). The web seam has no public runtime\n // selector, so the plugin writes its private `searchProviderId` field (read\n // per call) via `applyCommandCodeSearchSelection`. A settings change lands\n // on the next search without a restart. See src/web-search.ts for why this\n // runtime write is safe and what it depends on.\n //\n // The tracked selection remembers whichever backend was displaced, so\n // turning the toggle off hands the selection back to it (issue #26) — the\n // disable path never forces the factory default. Disposing the fiber (the\n // plugin unloads) restores it the same way: without that, the stale\n // `commandcode` pin would outlive its unregistered provider and every\n // search would fail with WEB_PROVIDER_CONFIGURED_MISSING.\n const searchSelection = commandCodeSearchSelection()\n const applySearchSelection = (enabled: boolean): void => {\n if (webRuntime !== undefined) {\n applyCommandCodeSearchSelection(webRuntime, searchSelection, enabled)\n }\n }\n let webRuntime: WebRuntime | undefined\n ctx.inject(['web'], (webCtx) => {\n webRuntime = webCtx.web\n webCtx.web.registerSearchProvider(new CommandCodeSearchProvider({\n resolveKey: async () => {\n const resolved = await pool.resolveKey()\n return resolved === undefined ? undefined : resolved.key\n },\n apiBase: () => options().apiBase,\n }))\n // Apply the selection at boot too, so a profile WITHOUT the manual\n // `searchProvider: commandcode` cordis patch still routes web search to\n // Command Code once this plugin loads (default `webSearch` on).\n applySearchSelection(current().webSearch ?? true)\n // The fiber's disposer restores the displaced backend the same way the\n // toggle-off path does (`webCtx.effect` registers the inner function as\n // the fiber's teardown; a bare `return` from the inject callback would\n // not). Without this, the stale `commandcode` pin would outlive its\n // unregistered provider and every search would fail with\n // WEB_PROVIDER_CONFIGURED_MISSING.\n webCtx.effect(() => () => {\n webRuntime = undefined\n applyCommandCodeSearchSelection(webCtx.web, searchSelection, false)\n }, 'dsh-commandcode-provider: web search selection')\n })\n\n // The terminal front door (dsh-TUI) settings page. dsh-TUI owns its own\n // settings screen and only asks plugins to DECLARE what is editable, so\n // without this a TUI-only user has no way to enter the API key — the web\n // Models page is the only other surface that writes it, and dsh-TUI's\n // `/provider` wizard manages its own `llm-pi-ai` routes exclusively\n // (issue #28). The seam is an optional service, exactly like `commands`\n // and `web`: on a profile without dsh-TUI the fiber never activates, and\n // the plugin stays a plain LLM-provider bundle. The API-key field is a\n // secret field, so the literal goes to the credentials seam and never into\n // a settings document.\n let refreshTuiSettings: (() => void) | undefined\n ctx.inject(['tuiSettingsSections'], (tuiCtx) => {\n refreshTuiSettings = applyCommandCodeTuiSettings(tuiCtx, {\n ns: NS,\n // Read per registration, so a `Config.apiKeyEnv` change re-targets the\n // key field instead of leaving it writing to the previous reference.\n apiKeyRef: () => current().apiKeyEnv ?? DEFAULT_API_KEY_ENV,\n // The account slots behind the active-account selector. The section is\n // re-registered when this list changes (the refresh call below), since\n // the host renders a fixed option list per declaration.\n accountSlots: () => slots().map((slot) => ({ id: slot.id, label: slot.label })),\n // The model allowlist is read LIVE on every toggle: a checkbox judges\n // its inherited state against the current document, not against\n // whatever the declaration happened to be registered with. The override\n // map is read here too, so an id this build's catalog does not place\n // still gets a row of its own.\n visibleModels: () => options().visibleModels ?? [],\n modelVisibility: () => options().modelVisibility,\n })\n tuiCtx.effect(() => () => {\n refreshTuiSettings = undefined\n }, 'dsh-commandcode-provider: tui settings handle')\n })\n\n // Settings became an optional service in dsh 0.1.2. Register the section\n // through its provider when present; profiles without settings continue to\n // use the composition entry captured by `current` above.\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.settings.installSection(ctx, NS, Config, config, {\n setSource: (source) => {\n current = source\n },\n // Re-apply the web search selection on every settings change so the\n // `webSearch` toggle reaches the web seam's next search without a\n // restart. The tracked state remembers the displaced backend (issue\n // #26), so flipping the toggle is a handoff, not an overwrite. The\n // adapter's own facts are resolved per request, so nothing else needs\n // registration-level action here.\n //\n // The dsh-TUI section is refreshed from the same hook: its key field\n // follows `apiKeyEnv` and its account selector follows `accounts`, and\n // both are frozen into the declaration the host renders. The refresh is\n // a no-op unless one of those facts actually moved, so ordinary writes\n // (the key itself, the model filters) never churn the screen.\n onChange: () => {\n applySearchSelection(current().webSearch ?? true)\n refreshTuiSettings?.()\n },\n })\n })\n}\n"],"mappings":"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"}
|