@mars-sea/dsh-commandcode-provider 0.11.14 → 0.11.16

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/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["record","finite","record","stringField","reject","createNetServer","createHttpServer","isAbortError"],"sources":["../src/capabilities.ts","../src/model-prices.ts","../src/cost-facts.ts","../src/cost-projection.ts","../src/response-encoding.ts","../src/accounts.ts","../src/image-request.ts","../src/image-tokens.ts","../src/stream-trace.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/systemone.ts","../src/command-guard.ts","../src/config-volatile.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.62.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 // The 1.58.0 -> 1.62.0 train added `xai/grok-4.7` (command-code@1.59.0) and\n // `stepfun/Step-5-Preview` (1.60.0) — the only two effort-map changes across\n // those releases, re-verified against the 1.62.0 table; every existing entry,\n // and every effort-less automatic-reasoning model, is unchanged.\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 // command-code@1.56.0 added Qwen 3.8 Omni Flash — the only model-registry\n // change across 1.54.0 -> 1.56.0, and the only catalog model with no local\n // snapshot entry before this. Omni-modal (text+image), 1M context, reasoning\n // with the same ['low', 'medium', 'xhigh'] set as its Qwen 3.8 siblings.\n 'Qwen/Qwen3.8-Omni-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 // command-code@1.60.0 added Step 5 Preview (StepFun's 600B sparse-MoE agentic\n // coding model, 1M context, text+image) with ['low', 'medium', 'high']\n // efforts — the same three-level set as its Step 3.x Flash siblings, which\n // still reason automatically with no levels and so stay out of this map.\n 'stepfun/Step-5-Preview': ['low', 'medium', 'high'],\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 // command-code@1.59.0 added Grok 4.7 (\"Add Grok 4.7\") with the same\n // four-level set as Grok 4.6; 1.61.0 then put it on a 40% off launch deal\n // (see KNOWN_DEALS).\n 'xai/grok-4.7': ['low', 'medium', 'high', 'xhigh'],\n 'z-ai/glm-5.3-flash': ['low', 'high', 'max'],\n // command-code@1.57.0 added GLM-5.3 FlashX — the only model-registry change\n // across 1.56.0 -> 1.57.0 — with the same three-level effort set as its\n // `z-ai/glm-5.3-flash` sibling.\n 'z-ai/glm-5.3-flashx': ['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 // The 1.62.0 -> 1.64.0 train (1.63.0 and 1.64.0; neither has a changelog\n // entry yet — the official changelog page still tops out at 1.62.0, so this\n // was read from the 1.64.0 bundle and the public sources) is additive again:\n // the registry grows 83 -> 86 with exactly three additions — Claude Opus 5.5\n // and the GPT-6 Sol / GPT-6 Luna pair — all three text+image, reasoning with\n // the same five-level set as `gpt-6-astra`, and no edit to any existing row.\n // They are also the only three models the public catalog gained (77 -> 80).\n 'claude-opus-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-6-sol': ['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 // command-code@1.65.0 added `stealth/space-bunny-alpha` (Space Bunny Alpha) —\n // the only model-registry change in the release (no official changelog entry\n // exists for it yet; read from the 1.65.0 bundle and the public catalog,\n // which now serves it). OpenRouter-served (`chatComplete`), text+image, 1M\n // context, reasoning with the three-level set. It is free during the stealth\n // preview (see KNOWN_DEALS) and is NOT routed under ZDR (see\n // KNOWN_NON_ZDR_MODELS).\n 'stealth/space-bunny-alpha': ['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 // command-code@1.56.0 added Qwen 3.8 Omni Flash; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'Qwen/Qwen3.8-Omni-Flash',\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 // command-code@1.64.0 added Claude Opus 5.5; Vision per the official registry\n // and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page also\n // carries caps.vision: true).\n 'claude-opus-5-5',\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.64.0 added the GPT-6 Sol / GPT-6 Luna pair; Vision per the\n // official registry and the CLI's inputModalities:[\"text\",\"image\"] (the\n // pricing page also carries caps.vision: true).\n 'gpt-6-luna',\n 'gpt-6-sol',\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 // command-code@1.65.0 added Space Bunny Alpha; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n // command-code@1.60.0 added Step 5 Preview; Vision per the official registry\n // (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"] (the pricing page also carries\n // caps.vision: true).\n 'stepfun/Step-5-Preview',\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 // command-code@1.59.0 added Grok 4.7; Vision per the official registry\n // (\"Text input, Vision, Reasoning\"), the CLI's\n // inputModalities:[\"text\",\"image\"] and the pricing page's caps.vision: true.\n 'xai/grok-4.7',\n 'xiaomi/mimo-v2.5',\n // command-code@1.62.0 added the MiMo V2.6 family (Flash, Pro, Pro\n // UltraSpeed); all three are Vision per the official registry (\"Text input,\n // Vision\"), the CLI's inputModalities:[\"text\",\"image\"] and the pricing\n // page's caps.vision: true. None of them carries a reasoning flag in any\n // source, so they are plain non-thinking models — no effort or\n // automatic-reasoning entry belongs beside these.\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n 'z-ai/glm-5.3-flash',\n // command-code@1.57.0 added GLM-5.3 FlashX; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'z-ai/glm-5.3-flashx',\n])\n\n/**\n * Models WITHOUT a zero-data-retention upstream, per the official CLI's own\n * registry (`command-code@1.65.0` `dist/cli.mjs`: `modelSupportsZdr(id)` is\n * exactly `!nonZdrSet.has(canonicalize(id))`, and `knownModelSupportsZdr`\n * carries the same membership in the sibling route table — the union is this\n * set). The official docs (commandcode.ai/docs/resources/zdr) put it in prose\n * — \"99% of our models have ZDR-capable upstreams … only a small handful of\n * models are affected\" — so the CLI's exclusion list is the only per-model\n * evidence there is; a ZDR request naming one of these fails with HTTP 422\n * `cmd_zdr_no_providers` instead of routing through a provider that retains.\n *\n * Why a NEGATIVE set, and why \"not listed\" answers TRUE: 99% of the catalog is\n * covered, so the maintained difference is the exception list. This helper is\n * informational; the adapter sends the ZDR header for EVERY request when the\n * switch is on. The provider remains the routing authority and refuses an\n * unsupported model rather than silently dropping the privacy guarantee.\n *\n * `minimax/minimax-m3-free` is the one entry the public catalog\n * (`/provider/v1/models`) does not serve (it is CLI/pricing-visible and hidden\n * from the picker); it stays listed because the CLI carries it and a Go-plan\n * request can still name it.\n *\n * Keep in sync via the dsh-commandcode-upstream skill: the CLI's registry data\n * (its `zdr:{only:[…]}` provider routes and the per-provider `zdr`/`noTraining`\n * flags) is upstream-internal routing, not a per-model contract, so this table\n * is the snapshot of the exclusion set and nothing more. The 1.62.0 → 1.64.0\n * diff of that union is EMPTY: both anchors were extracted from both bundles\n * during the 2026-09-23 check and each carries the same 20 members — which is\n * how rare a change here is expected to be. The 1.64.0 → 1.65.0 diff (2026-09-24)\n * is the counterexample that proves the check still runs: exactly one member\n * joins (`stealth/space-bunny-alpha`), and it is in both anchors. `meituan/\n * LongCat-2.0` is the one member the two anchors disagree about (it is in\n * `modelSupportsZdr`'s set in both releases and in neither `knownModelSupportsZdr`\n * set), so the union is\n * what this table follows; reading only the sibling route table would drop it.\n */\nexport const KNOWN_NON_ZDR_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.8-Max-0902',\n 'meituan/LongCat-2.0',\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 'minimax/minimax-m3-free',\n 'poolside/laguna-s-2.1-free',\n 'sakana/fugu-ultra',\n // command-code@1.65.0 added `stealth/space-bunny-alpha` — the first change to\n // this set since the 1.62.0 check. It is in BOTH anchors of the 1.65.0 bundle\n // and the pricing page's own tip says it: \"Free while the preview lasts. Not\n // routed under ZDR.\"\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n 'stepfun/Step-5-Preview',\n 'xai/grok-4.5',\n 'xai/grok-4.6',\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n 'z-ai/glm-5.3-flashx',\n 'zai-org/GLM-5.2-Fast',\n])\n\n/**\n * Whether the CLI snapshot lists a ZDR-capable upstream for `modelId`. This is\n * informational, never a reason to omit the header when ZDR is enabled: the\n * provider may add coverage or lack capacity after this snapshot was taken.\n */\nexport function supportsZeroDataRetention(modelId: string): boolean {\n return !KNOWN_NON_ZDR_MODELS.has(modelId)\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 LongCat 2.0 (then\n * `meituan/LongCat-2.0:free`, now the paid `meituan/LongCat-2.0`; reasoning:!0,\n * 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 text-only with automatic reasoning. The free promo\n // ended 2026-09-19 and the backend catalog renamed it from\n // `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`. The rename is\n // billing-only, so the new id keeps this entry: the pricing page still\n // carries `caps.reasoning: true` with no efforts, and command-code@1.58.0 —\n // the CLI release that retired the free tier — carries the new id with\n // `reasoning:!0` and no `reasoningEfforts`, one release after the backend\n // rename the 1.57.0 sync recorded here.\n 'meituan/LongCat-2.0',\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 * LongCat 2.0 (Go — a free promo until 2026-09-19, when the backend renamed\n * `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`); 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); command-code@1.56.0 added\n * `Qwen/Qwen3.8-Omni-Flash` (Go); command-code@1.57.0 added\n * `z-ai/glm-5.3-flashx` (Go); command-code@1.59.0 added `xai/grok-4.7` (GOAT)\n * and 1.60.0 added `stepfun/Step-5-Preview` (Go); command-code@1.62.0 added the\n * MiMo V2.6 family — `xiaomi/mimo-v2.6-flash` + `xiaomi/mimo-v2.6-pro` (Go) and\n * `xiaomi/mimo-v2.6-pro-ultraspeed` (GOAT) — so the 1.58.0 -> 1.62.0 window's\n * only tier changes are additions and the superset chain still holds. The\n * 1.62.0 -> 1.65.0 window continues the pattern: 1.64.0 added\n * `claude-opus-5-5` (Provider/Max), `gpt-6-sol` (Pro) and `gpt-6-luna` (Go),\n * and 1.65.0 added `stealth/space-bunny-alpha` (Go, every tier) — additions\n * only, no tier moves.\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 (50) ---\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.56.0 added Qwen 3.8 Omni Flash; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro) — the\n // same \"all\":true shape as the rest of the Qwen 3.8 family.\n 'Qwen/Qwen3.8-Omni-Flash': '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.64.0 added GPT-6 Luna on every plan including Go (the\n // opensource-category GPT-6 sibling): the pricing page's availability sets\n // individual-go true and the Go plan page lists it, while its premium-category\n // siblings Sol (Pro) and Astra (Provider/Max) do not.\n 'gpt-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). That\n // promo ended 2026-09-19: the pricing page dropped the deal and the free\n // slug, the public catalog renamed the id to `meituan/LongCat-2.0` (paid,\n // $0.30/$1.20/$0.006), and the docs list the new id. command-code@1.58.0\n // followed the backend: it adds the paid id and marks the retired `:free`\n // sibling `hidden` (\"LongCat 2.0 (Free)\"), so the CLI registry now agrees\n // with the catalog this map is keyed by.\n 'meituan/LongCat-2.0': '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 // command-code@1.60.0 added Step 5 Preview; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro), and the\n // Go plan page's rendered table lists it — while GOAT/Pro/Max list it too,\n // which is the superset chain this map encodes.\n 'stepfun/Step-5-Preview': 'go',\n // command-code@1.65.0 added Space Bunny Alpha; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro, the same\n // \"all\":true shape as the Qwen 3.8 family), so it is a Go model that every\n // higher plan also serves. Free during the stealth preview (see KNOWN_DEALS).\n 'stealth/space-bunny-alpha': '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 // command-code@1.62.0 added MiMo V2.6 Flash and MiMo V2.6 Pro on every tier;\n // the Go plan page lists both, and the GOAT-tier Pro UltraSpeed sibling does\n // NOT appear there — the pricing page's availability is what separates them\n // (individual-go: true for these two, false for UltraSpeed).\n 'xiaomi/mimo-v2.6-flash': 'go',\n 'xiaomi/mimo-v2.6-pro': 'go',\n 'z-ai/glm-5.3-flash': 'go',\n // command-code@1.57.0 added GLM-5.3 FlashX; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro) — the\n // same \"all\":true shape as its `z-ai/glm-5.3-flash` sibling.\n 'z-ai/glm-5.3-flashx': '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 (8 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 // command-code@1.59.0 added Grok 4.7 on GOAT and above: the pricing page's\n // availability sets individual-go false with goat/pro/provider/max/ultra\n // true (\"Available on GOAT and above\"), and the Go plan page's table does not\n // list it while GOAT's does.\n 'xai/grok-4.7': 'goat',\n // command-code@1.62.0 added MiMo V2.6 Pro UltraSpeed on GOAT and above, the\n // same split as its Grok 4.7 sibling (individual-go false; the Go plan page\n // does not list it, GOAT/Pro/Max do) — its two cheaper V2.6 siblings are Go\n // models and sit in the section above.\n 'xiaomi/mimo-v2.6-pro-ultraspeed': 'goat',\n // --- Pro (14 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 // command-code@1.64.0 added GPT-6 Sol on Pro and above: the pricing page's\n // availability sets individual-go/goat false with pro and above true, and the\n // Go and GOAT plan pages do not list it while Pro/Max do.\n 'gpt-6-sol': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider / Max (8) ---\n 'claude-fable-5-1': 'provider',\n 'claude-fable-5': 'provider',\n 'claude-opus-4-7': 'provider',\n 'claude-opus-4-8': 'provider',\n // command-code@1.64.0 added Claude Opus 5.5 on the Provider API only: the\n // pricing page's availability sets go/goat/pro/pro-v1 all false with\n // provider/max/ultra true, and the public catalog serves it with\n // supported_endpoints ['/messages'] — the Claude family's route, which the\n // adapter's `claude-*` prefix rule already sends down the CLI transport.\n 'claude-opus-5-5': '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 * Whether the picker lists `modelId` for a whole POOL of accounts: true when\n * at least one of them includes it. The picker's plan filter is asked this\n * rather than {@link modelVisibleInPlan} for a single account because the pool\n * — not any one account — is what serves a request: keying the list on\n * whichever account rotation happened to reach made models appear and vanish\n * as accounts rotated, and hid models the user's other accounts could run.\n *\n * An account whose facts are unknown counts as \"may include it\" (the same\n * fail-open rule `modelVisibleInPlan` applies one level down), and an empty\n * pool is \"show everything\": hiding a model somebody can run is the one\n * failure this filter must never cause.\n */\nexport function modelVisibleForAnyAccount(\n modelId: string,\n accounts: readonly (CommandCodeBillingAccess | undefined)[] | undefined,\n): boolean {\n if (accounts === undefined || accounts.length === 0) return true\n return accounts.some((access) => modelVisibleInPlan(modelId, access))\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 // command-code@1.61.0 put Grok 4.7 on a 40% off launch deal (\"Grok 4.7 40%\n // off\"), running 2026-09-21 -> 2026-09-27T23:59:59.999Z and reverting to\n // $2.00 in / $6.00 out. The expiry is stamped from the page's own `deal`\n // record so the badge lapses by itself: the vendored rate row already holds\n // the discounted figures ($1.20 in / $3.60 out / $0.30 cache read, doubling\n // past 200K), exactly like the other percentage deals here.\n 'xai/grok-4.7': { label: '40% off', expiresAt: '2026-09-27T23:59:59.999Z' },\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 promo ended 2026-09-19 (the pricing page's deal count\n // dropped 6 -> 5, its free count 4 -> 3, and the DEAL block no longer exists):\n // the entry that shipped from command-code@1.42.0 on is removed here rather\n // than left to badge a model the catalog now serves paid as\n // `meituan/LongCat-2.0` at $0.30/$1.20/$0.006.\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 used to be). Free requests cost no credits on every plan.\n 'inclusionai/ling-3.0-flash-sante:free': { label: 'FREE', free: true },\n // command-code@1.65.0 added Space Bunny Alpha as a stealth-preview free model\n // (\"Free while the stealth preview lasts\", 100% off, auto-applied) — a\n // permanent-style free deal like Ling's, so no expiresAt. It is NOT routed\n // under ZDR (see KNOWN_NON_ZDR_MODELS). The pricing page publishes its rates\n // as a literal zero, and `modelPriceTable()` serves free models explicitly at\n // zero, so no row is added to the vendored price table.\n 'stealth/space-bunny-alpha': { 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-opus-5-5', rates: [4, 20, 0.2, 5] },\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: 'glm-5.3-flashx', rates: [0.37, 1.25, 0.075] },\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: 'gpt-6-luna', rates: [0.1, 0.5, 0.01, 0.125], contextTiers: [{\"maxContext\":272000,\"rates\":[0.1,0.5,0.01,0.125]},{\"rates\":[0.2,0.75,0.02,0.25]}] },\n { id: 'gpt-6-sol', rates: [2, 10, 0.2, 2.5], contextTiers: [{\"maxContext\":272000,\"rates\":[2,10,0.2,2.5]},{\"rates\":[4,15,0.4,5]}] },\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: 'grok-4.7', rates: [1.2, 3.6, 0.3], contextTiers: [{\"maxContext\":200000,\"rates\":[1.2,3.6,0.3]},{\"rates\":[2.4,7.2,0.6]}] },\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: 'longcat-2.0', rates: [0.3, 1.2, 0.006] },\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: 'mimo-v2.6-flash', rates: [0.14, 0.28, 0.0028] },\n { id: 'mimo-v2.6-pro', rates: [0.435, 0.87, 0.0036] },\n { id: 'mimo-v2.6-pro-ultraspeed', rates: [4.35, 8.7, 0.036] },\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: 'qwen-3.8-omni-flash', rates: [0.15, 0.47, 0.016] },\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: 'step-5-preview', rates: [1, 2.7, 0.05] },\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 * Ask Command Code for plain response bodies. A DSH host using an incompatible\n * undici global dispatcher can lose response headers and leave compressed\n * JSON, SSE, and pre-stream error bodies undecoded.\n */\nexport const IDENTITY_ENCODING_HEADER = { 'accept-encoding': 'identity' } as const\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 or 401 against\n * the exact API key, so several slots sharing one key share one state. A\n * 429 that NAMED a usage window marks the window exhausted; a 429 that\n * named none is recorded as a plain throttle, which rotates the same way\n * but is never reported as an exhausted window (issue #54).\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 * - An account the user explicitly asked for — the manual pin\n * ({@link CommandCodeAccountPoolDeps.preferredId}) or a model rule's\n * routed account — is probed the same way when a mark would demote it, so\n * a fallback is never permanent (issue #51).\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/**\n * How long an explicitly selected account's rate-limit mark may stand before\n * its window is probed again. A 429 whose reset was never learned marks the\n * key `unknown`, which {@link accountUsable} refuses forever — deliberately,\n * because the all-marked revival pass is the only thing meant to clear it and\n * it costs one billing call per key. That is fine for a key nobody asked for,\n * and wrong for the one the user pinned: a single 429 would otherwise demote\n * the user's own selection until the process restarts (issue #51). The probe\n * is therefore allowed once per interval per key, which bounds an endpoint\n * that keeps failing while a successful probe resolves the mark for good.\n */\nconst EXPLICIT_ACCOUNT_PROBE_INTERVAL_MS = 60_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/**\n * Why a key stopped serving requests.\n *\n * `rate-limit` is a USAGE-WINDOW rejection: the provider named one of its\n * metered windows (`error.rateLimit.window`, or a message saying the plan's\n * usage limit was reached — the only two shapes the official CLI's own\n * `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the\n * plain 429: the provider refused the request without saying anything about a\n * window, so the key leaves rotation for now but the pool must not describe it\n * as an exhausted window. Collapsing the two is issue #54: the reporter's\n * account panel showed the five-hour window at 2% and the weekly one at 10%\n * while the turn failed with \"all 1 Command Code account(s) have exhausted\n * their usage window\".\n */\nexport type AccountRejection = 'rate-limit' | 'throttled' | '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 /**\n * The evidence behind the mark — what the pool may CLAIM when it reports\n * that no account can serve. `window`: the provider named a usage window, or\n * a `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429\n * that said nothing about a window (a burst limiter, or a model- or\n * spend-level limit the billing endpoint cannot show). `auth`: a 401.\n */\n cause: 'window' | 'throttle' | 'auth'\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/**\n * One account's real rate-limit state, probed from `/alpha/billing/credits`:\n * `exceeded` is true when ANY of the account's usage windows is spent, and\n * `resetAt` is the latest reset among them (the binding constraint — an open\n * five-hour window buys nothing while the weekly quota is exhausted).\n */\nexport interface AccountWindowProbe {\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 /**\n * Probe one key's usage windows — BOTH windows the endpoint publishes (the\n * five-hour and the weekly one), not just the five-hour one; see\n * {@link AccountWindowProbe}. Undefined when the probe itself failed.\n */\n probeWindow(apiKey: string): Promise<AccountWindowProbe | 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 — and an exhausted one is\n * re-probed on the way (see {@link CommandCodeAccountPool.resolveKey}), so\n * the fallback lasts only as long as the window really is exceeded.\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 * Clock seam for the explicit-account probe throttle. Tests drive it so the\n * \"the interval elapsed, probe again\" half of\n * {@link CommandCodeAccountPool.canProbeExplicit} is reachable without\n * waiting a real minute; production reads `Date.now()`.\n */\n now?(): number\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 /** Last explicit-revival probe attempt by API key (throttles a failing probe). */\n private readonly explicitProbes = new Map<string, number>()\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.tried` lists the keys this request has already used — the\n * just-rejected one included. They are removed from the resolution entirely,\n * which is what lets one request walk a four-account pool: an account-scoped\n * rejection that does not mark the key (no credits, a model outside the\n * account's plan) would otherwise be offered again on every attempt, and the\n * accounts behind it would never be reached.\n *\n * An explicit selection (the pin or a model rule) that a rate-limit mark\n * would demote is probed before the fallback serves, so \"falls back while\n * exhausted\" never becomes \"stays demoted until the process restarts\".\n */\n async resolveKey(options?: { tried?: readonly 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 // One filter for the whole resolution: the routed, pinned, rotating and\n // probe-revival paths must all agree on which accounts are still in play.\n const tried = options?.tried\n const available = tried === undefined || tried.length === 0\n ? accounts\n : accounts.filter((account) => !tried.includes(account.key))\n const preferred = this.deps.preferredId?.()\n // Every account was already tried in this request. Nothing can be handed\n // back: an account that is merely UNMARKED (a plan or balance rejection\n // marks nothing) leaves the caller's own rejection as the honest answer,\n // so return undefined and let it surface. When every account is marked\n // instead, the pool still owes its own diagnosis — the earliest window\n // reset, with the wait the retry policy sleeps on — and it is built from\n // the marks as they stand, without probing: a probe here would answer a\n // question this request cannot act on, and reviving a key mid-request\n // would make the diagnosis below describe an account that is usable again.\n const diagnoseOnly = available.length === 0\n if (diagnoseOnly) {\n if (selectActiveAccount(accounts, preferred) !== undefined) return undefined\n throw allAccountsUnusable(accounts)\n }\n const routed = selectAccountForModel(available, options?.model ?? '', this.deps.modelAccountRules?.())\n if (routed !== undefined) return this.pick(routed)\n const chosen = selectActiveAccount(available, preferred)\n if (chosen !== undefined) {\n // The explicit account is unusable while another one can serve — the\n // fallback path. Its mark is re-checked against the real window before\n // the user's own selection is demoted for good (issue #51).\n const explicit = this.explicitAccount(available, options?.model ?? '', preferred)\n if (\n explicit !== undefined\n && explicit.key !== chosen.key\n && this.canProbeExplicit(explicit)\n ) {\n const revived = await this.probeExplicit(explicit)\n if (revived !== undefined) return this.pick(revived)\n }\n return this.pick(chosen)\n }\n\n // Every account still in play is marked: probe the real windows before\n // giving up. Disabled (401) keys are not probed — an invalid key stays\n // invalid. A throwing probe counts as \"unknown\" (like a failed probe): it\n // must not turn the all-exhausted path into a raw rejection instead of\n // RATE_LIMIT.\n await Promise.all(available.map(async (account) => {\n if (account.state?.kind === 'disabled') return\n let probe: AccountWindowProbe | 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 return\n }\n // A known reset becomes a cooldown that expires by itself. An UNKNOWN one\n // must not: `until: 0` would read as \"never usable again\" to\n // {@link accountUsable} and take the account out of service for the rest\n // of the process — the very permanence this pool must not have. Keeping\n // the `unknown` mark leaves it eligible for the next probe. Either way the\n // cause becomes `window`: a probe that read a window as exceeded is\n // window evidence, whatever the key was originally marked for. A mark that\n // ALREADY carries a cooldown keeps it when this probe publishes no reset\n // — a known reset must never be thrown away for an unknown one.\n if (probe.resetAt > 0) {\n this.states.set(account.key, {\n kind: 'cooldown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: probe.resetAt,\n })\n } else if (account.state?.kind !== 'cooldown') {\n this.states.set(account.key, {\n kind: 'unknown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: 0,\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.) The tried\n // keys stay filtered out: a probe that clears one must not re-offer a key\n // this request already burned, which is what the adapter refuses anyway.\n const latestAccounts = await this.resolvedAccounts()\n const latest = tried === undefined || tried.length === 0\n ? latestAccounts\n : latestAccounts.filter((account) => !tried.includes(account.key))\n const revived = selectActiveAccount(latest, preferred)\n if (revived !== undefined) return this.pick(revived)\n\n // Nothing still in play can serve — but an account this request already\n // used may be UNMARKED, because an `unavailable` rejection (no credits, a\n // model outside this account's plan) deliberately marks nothing. That\n // rejection is the honest answer, and returning undefined is how the caller\n // gets to surface it. Throwing the pool's own diagnosis instead would name\n // the wrong cause, count only the tried-filtered subset, and — for\n // RATE_LIMIT — hand dsh-llm-retry a wait that turns a PERMANENT failure\n // into a ~15-minute stall. The no-account-left branch above applies exactly\n // this rule; the two disagreed before, on the very case issue #51's\n // follow-up is about.\n if (selectActiveAccount(latestAccounts, preferred) !== undefined) return undefined\n // The diagnosis always describes the POOL. A second resolution that came\n // back empty — a transient credential-store miss, not a configuration\n // change — would otherwise report \"every configured account (0) was\n // rejected with 401\", naming neither an account nor a real cause.\n throw allAccountsUnusable(latestAccounts.length > 0 ? latestAccounts : accounts)\n }\n\n /**\n * Record a rejection against one key. `rate-limit` marks the key's usage\n * WINDOW exhausted — as a `cooldown` until `resetAtMs` when the rejection\n * body named the provider's own reset time, otherwise as an `unknown` mark\n * whose window is probed lazily. `throttled` (the plain 429 that named no\n * window) marks the key with the `throttle` cause instead: it leaves rotation\n * exactly like a window mark does, but the pool's own diagnosis keeps saying\n * \"rate limited\" rather than inventing an exhausted window. A 401\n * (`invalid-credential`) disables the key until the stored credential\n * changes.\n *\n * `resetAtMs` is seconds-to-millis converted by the adapter from the\n * provider's `error.rateLimit.reset`: knowing the real reset immediately is\n * what keeps an exhausted account out of rotation for exactly as long as the\n * provider said. It only applies to a window mark; a plain throttle keeps the\n * window unknown on purpose, so a probe can still find out.\n */\n markRejected(apiKey: string, rejection: AccountRejection, resetAtMs?: number): void {\n if (rejection === 'invalid-credential') {\n this.states.set(apiKey, { kind: 'disabled', cause: 'auth', reason: 'invalid API key (401)', until: 0 })\n } else if (rejection === 'throttled') {\n // Deliberately NOT a cooldown from `resetAtMs`: a throttle carries no\n // window fact, and an `unknown` mark is what keeps the key eligible for\n // the window probe that turns a real window limit into a cooldown with\n // the provider's own reset (or revives the key when the window is open).\n this.states.set(apiKey, { kind: 'unknown', cause: 'throttle', reason: 'rate limited (429)', until: 0 })\n } else if (resetAtMs !== undefined && resetAtMs > Date.now()) {\n this.states.set(apiKey, { kind: 'cooldown', cause: 'window', reason: 'usage window exhausted (429)', until: resetAtMs })\n } else {\n this.states.set(apiKey, { kind: 'unknown', cause: 'window', reason: 'usage window exhausted (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 /**\n * The account the user explicitly asked for: the slot a model rule routes\n * the request to when that id exists among the resolved slots, else the\n * manually pinned slot. Consulted only on the fallback path — a usable\n * routed account already returned above — so unlike\n * {@link selectAccountForModel} it does NOT require the account to be\n * usable, which is exactly what {@link resolveKey} re-probes.\n */\n private explicitAccount(\n accounts: readonly ResolvedAccount[],\n model: string,\n preferredId: string | undefined,\n ): ResolvedAccount | undefined {\n const rule = matchModelRule(model, this.deps.modelAccountRules?.())\n const id = rule !== undefined && accounts.some((account) => account.slot.id === rule.account)\n ? rule.account\n : preferredId\n return id === undefined ? undefined : accounts.find((account) => account.slot.id === id)\n }\n\n /**\n * Whether an explicitly selected account's mark is due for a window probe.\n * Only an `unknown` mark (a 429 whose reset was never learned) is worth\n * re-probing: a `cooldown` already carries its reset time and expires by\n * itself, and a `disabled` (401) key stays out until the stored credential\n * changes. The interval bounds a probe endpoint that keeps failing.\n */\n private canProbeExplicit(account: ResolvedAccount): boolean {\n if (account.state?.kind !== 'unknown') return false\n const last = this.explicitProbes.get(account.key)\n return last === undefined || this.now() - last >= EXPLICIT_ACCOUNT_PROBE_INTERVAL_MS\n }\n\n /** The clock the probe throttle reads; injected so a test can travel in time. */\n private now(): number {\n return this.deps.now?.() ?? Date.now()\n }\n\n /**\n * Probe one explicitly selected account's window and apply the answer. A\n * window that is no longer exceeded drops the mark, so the user's own\n * selection serves again on this very request. An exceeded one is stamped\n * as a cooldown carrying the provider's reset time, after which\n * {@link accountUsable} lets the account back in with no further probe. A\n * probe that fails changes nothing: the mark stays `unknown` and the next\n * attempt waits out the interval.\n */\n private async probeExplicit(account: ResolvedAccount): Promise<ResolvedAccount | undefined> {\n this.explicitProbes.set(account.key, this.now())\n let probe: AccountWindowProbe | undefined\n try {\n probe = await this.deps.probeWindow(account.key)\n } catch {\n return undefined\n }\n if (probe === undefined) return undefined\n if (!probe.exceeded) {\n this.states.delete(account.key)\n // The throttle timestamp SURVIVES the revival. Deleting it read as \"this\n // key was never probed\", so the next request probed again — and the loop\n // that follows is exactly the one the interval exists to bound: the probe\n // says the window is open, the chat endpoint answers 429 anyway (a spend\n // cap or a model-level limit is invisible to `windowLimits`), the mark\n // returns to `unknown`, and the next request probes once more — one\n // billing GET plus one doomed upstream attempt per request, forever.\n // Keeping the stamp costs nothing when the revival was right: a serving\n // account is never probed at all, and the mark only comes back if the\n // provider rejects it again, which is when the interval should apply.\n return { slot: account.slot, key: account.key, state: undefined }\n }\n // A reset time is what makes the mark expire on its own; without one the\n // mark stays `unknown`, so a later probe can still learn it. The cause is\n // `window` either way: the probe read the account's own usage windows. A\n // mark that already carries a cooldown keeps it, exactly like the all-marked\n // pass: a known reset is never traded for an unknown one.\n if (probe.resetAt > 0) {\n this.states.set(account.key, {\n kind: 'cooldown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: probe.resetAt,\n })\n } else if (account.state?.kind !== 'cooldown') {\n this.states.set(account.key, {\n kind: 'unknown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: 0,\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 * The error for \"accounts exist but none of them can serve\". Three shapes, each\n * claiming only what the pool actually knows:\n *\n * - every account rejected with 401 → `INVALID_CREDENTIAL`;\n * - at least one account marked by a NAMED usage window (or by a probe that\n * read a window as exceeded) → the window diagnosis, naming the earliest\n * known reset when the provider published one;\n * - every mark a plain throttle (a 429 that said nothing about a window, and\n * no probe could confirm one) → a throttle diagnosis that says so. Claiming\n * \"all accounts have exhausted their usage window\" here is issue #54: the\n * report's account panel showed the five-hour window at 2% and the weekly\n * one at 10% while the turn failed with exactly that sentence.\n *\n * Shared by the all-marked tail of {@link CommandCodeAccountPool.resolveKey}\n * and by its already-tried diagnosis, so the two can never drift apart.\n *\n * The attached `providerRetryAfterMs` is the exact wait until the earliest\n * known window reset, so dsh-llm-retry sleeps through the window instead of\n * polling at its backoff cadence. It is capped at {@link RETRY_MAX_DELAY_MS}:\n * the executor honors a provider wait verbatim only at or below the policy's\n * `maxDelayMs` — a LONGER attached wait makes it abandon the retry entirely\n * (normal mode), which would turn \"poll until the window opens\" into \"fail\n * now\". Longer resets simply ride the capped local backoff and the probe\n * revival. A throttle diagnosis attaches none: its marks carry no reset.\n */\nfunction allAccountsUnusable(accounts: readonly ResolvedAccount[]): LlmError {\n const disabled = accounts.filter((account) => account.state?.kind === 'disabled')\n if (disabled.length === accounts.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 return new LlmError(\n `llm-commandcode: every configured Command Code account (${accounts.length}) was rejected with 401`\n + ' — check the stored API keys (Models page / settings) or the auth file'\n + `;已配置的 ${accounts.length} 个 Command Code 账户密钥均被拒绝(401)`\n + '——请在设置页检查存储的 API 密钥,或重新运行 command-code login',\n 'INVALID_CREDENTIAL',\n )\n }\n const marked = accounts\n .map((account) => account.state)\n .filter((state): state is CommandCodeAccountState => state !== undefined)\n // Only a `window` mark may be described as an exhausted usage window. A\n // throttle mark proves the provider refused the request, never that a\n // metered window is spent — and because it deliberately carries no reset\n // (`unknown`, so the next pass may probe the real windows), this answer has\n // no time to name either. dsh-llm-retry's own backoff paces the retries.\n const windowMarked = marked.filter((state) => state.cause === 'window')\n if (windowMarked.length === 0) {\n return new LlmError(\n `llm-commandcode: all ${accounts.length} Command Code account(s) are rate limited (429)`\n + ' — the provider did not report an exhausted usage window; retrying'\n + `;全部 ${accounts.length} 个 Command Code 账户被限流(429)`\n + '——服务商未报告用量窗口用尽,正在重试',\n 'RATE_LIMIT',\n )\n }\n const resets = windowMarked\n .filter((state) => state.kind === 'cooldown' && state.until > 0)\n .map((state) => state.until)\n const earliest = resets.length > 0 ? Math.min(...resets) : 0\n const wait = earliest > 0 ? Math.max(1000, earliest - Date.now()) : 0\n return new LlmError(\n `llm-commandcode: all ${accounts.length} Command Code account(s) have exhausted their usage window`\n + (earliest > 0\n ? `; the earliest window resets at ${clockLabel(earliest)}`\n : ' — the provider published no reset time for it')\n + ' — requests will succeed again after the reset (or add another account)'\n + `;已用尽全部 ${accounts.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 * 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 * The target IS the projected geometry — `{ width, height, maxBytes }` — which\n * the attachment service passes straight to its encoder.\n *\n * @module dsh-commandcode-provider/image-request\n */\n\nimport type { ImageAttachmentRef, ImageRequestTarget } 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 * 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 * `dsh-attachment` exports an equivalent `longEdgeDimensions`, but it does not\n * guard its inputs: a reference whose declared size is 0 or NaN — a malformed\n * or fabricated attachment record — would project to a zero-sized target and\n * make the encoder refuse the whole request. The guard is the reason this stays\n * local; `tests/image-tokens.test.ts` pins the degenerate cases.\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 encoded-byte budget.\n */\nexport function requestImageTarget(ref: ImageAttachmentRef): ImageRequestTarget {\n const projected = longEdgeDimensions(ref.width, ref.height, REQUEST_IMAGE_MAX_LONG_EDGE)\n return {\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 * Opt-in raw-stream trace for the Command Code transports.\n *\n * Why this exists: this route's failure mode of record is a response that ENDS\n * EARLY. The gateway, an intermediary proxy, or the network closes the socket\n * mid-generation, so the adapter's read loop sees `done` without ever seeing\n * the transport's terminal event. From inside the adapter those two endings are\n * indistinguishable — the provider cut the stream, a proxy timed out, or the\n * socket was dropped — and the only artifact that separates them is the raw\n * wire: which events actually arrived, when the last one landed, how long the\n * socket then sat silent, and how it ended. Without that, a truncated answer is\n * a report with no evidence attached.\n *\n * Enable it per process:\n *\n * ```sh\n * DSH_COMMANDCODE_TRACE=/tmp/cc-stream.jsonl dsh web\n * DSH_COMMANDCODE_TRACE=1 dsh web # -> $TMPDIR/dsh-commandcode-stream.jsonl\n * ```\n *\n * Any value that is not a flag is a path, and the explicit off-spellings\n * (`0`, `false`, `no`, `off`) are recognized as \"off\" rather than being taken\n * for a file name.\n *\n * Every model request appends one JSONL record per raw chunk plus lifecycle\n * records (`response`, `eof`, `idle-timeout`, `read-error`, `end`,\n * `stream-close`), each stamped with `at` — milliseconds since that request's\n * first byte. The chunk records carry the provider's own payload verbatim\n * (bounded per chunk), because a truncated answer is exactly what is being\n * diagnosed: treat the file as conversation content, not as a log safe to\n * share. It never carries the request body, an API key, or any request header.\n *\n * Deliberate trade-offs:\n * - OFF costs one `process.env` read per request.\n * - ON appends synchronously, one file open per chunk. The trace must survive\n * a host killed mid-diagnosis, and the microseconds it costs are irrelevant\n * beside the seconds-scale silences it is there to measure.\n * - A trace that cannot be written turns itself off instead of failing the\n * request it is observing: a diagnostic must never become the outage.\n *\n * @module\n */\n\nimport { appendFileSync, mkdirSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join } from 'node:path'\n\n/** Environment variable that turns the trace on. */\nexport const STREAM_TRACE_ENV = 'DSH_COMMANDCODE_TRACE'\n\n/** File used when the variable is set to a bare flag instead of a path. */\nexport const STREAM_TRACE_DEFAULT_FILE = 'dsh-commandcode-stream.jsonl'\n\n/**\n * Ceiling for ONE request's trace, in bytes.\n *\n * A long generation is megabytes of SSE; the interesting part is always the\n * tail, but records are appended in arrival order, so the cap is what keeps a\n * forgotten trace from filling a disk. Hitting it stops payload records;\n * one bounded `end` and `stream-close` record can still follow so a long\n * reasoning phase cannot hide the very terminal outcome being diagnosed.\n */\nexport const STREAM_TRACE_MAX_BYTES = 4 * 1024 * 1024\n\n/** One raw chunk is recorded verbatim up to this many characters. */\nexport const STREAM_TRACE_MAX_TEXT = 16 * 1024\n\n/** Values of {@link STREAM_TRACE_ENV} that mean \"trace to the default file\". */\nconst FLAG_VALUES = new Set(['1', 'true', 'yes', 'on'])\n\n/**\n * Values that explicitly mean OFF.\n *\n * A user turning the trace off writes `false` as readily as they write `1` to\n * turn it on, and without this set every one of these spellings fell through to\n * \"…so it must be a path\" — the trace switched ON and wrote the conversation to\n * a file NAMED `false` (or `0`, or `off`) in the process's working directory.\n */\nconst OFF_VALUES = new Set(['0', 'false', 'no', 'off'])\n\n/** What the adapter writes through; {@link openStreamTrace}'s disabled stand-in is inert. */\nexport interface StreamTrace {\n /** Whether records are actually being written. */\n readonly enabled: boolean\n /**\n * Append one record.\n *\n * @param event - short record name (`response`, `chunk`, `eof`, …).\n * @param fields - JSON-serializable payload; never pass credentials.\n */\n record(event: string, fields?: Record<string, unknown>): void\n /** Write the closing record; safe to call twice, and on a capped trace. */\n close(): void\n}\n\n/** The inert trace used whenever the switch is off. */\nconst OFF: StreamTrace = { enabled: false, record: () => undefined, close: () => undefined }\n\n/**\n * Resolve the trace file for this process.\n *\n * @param raw - the variable's raw value; defaults to the live environment.\n * @returns the file to append to, or undefined when the trace is off.\n */\nexport function resolveStreamTracePath(\n raw: string | undefined = process.env[STREAM_TRACE_ENV],\n): string | undefined {\n const value = raw?.trim()\n if (value === undefined || value === '') return undefined\n const lower = value.toLowerCase()\n if (OFF_VALUES.has(lower)) return undefined\n if (FLAG_VALUES.has(lower)) return join(tmpdir(), STREAM_TRACE_DEFAULT_FILE)\n return value\n}\n\n/**\n * Clamp one recorded payload so a single chunk cannot consume the whole cap.\n *\n * @param text - the text to record.\n * @param max - characters to keep, defaulting to {@link STREAM_TRACE_MAX_TEXT}.\n * @returns `text` unchanged, or its head plus a marker naming what was dropped.\n */\nexport function boundTraceText(text: string, max: number = STREAM_TRACE_MAX_TEXT): string {\n if (text.length <= max) return text\n return `${text.slice(0, max)}…[+${text.length - max} chars]`\n}\n\n/**\n * Open one request's trace.\n *\n * @param scope - what the records describe (the `provider/model` route).\n * @param options - `path` overrides the environment (tests pass a temp file);\n * `now` overrides the clock the `at` stamps are measured with.\n * @returns a writer that never throws and never fails the request.\n */\nexport function openStreamTrace(\n scope: string,\n options: { path?: string; now?: () => number } = {},\n): StreamTrace {\n const path = options.path ?? resolveStreamTracePath()\n if (path === undefined) return OFF\n const now = options.now ?? Date.now\n const startedAt = now()\n let written = 0\n let stopped = false\n let capped = false\n const terminals = new Set<string>()\n // The directory is created once, here, so the hot path is a single append.\n // A path that cannot be prepared disables the trace rather than throwing:\n // the request this observes must not depend on the observer.\n try {\n mkdirSync(dirname(path), { recursive: true })\n } catch {\n return OFF\n }\n const write = (record: Record<string, unknown>): void => {\n if (stopped) return\n const terminal = record.event === 'end' || record.event === 'stream-close'\n if (capped && !terminal) return\n if (terminal && terminals.has(String(record.event))) return\n let line: string\n try {\n line = `${JSON.stringify({ at: now() - startedAt, scope, ...record })}\\n`\n } catch {\n // A payload that cannot be serialized (a cycle, a BigInt) drops that\n // record only; the trace stays on for the records that do serialize.\n return\n }\n // Bound final metadata too: at most two 16 KiB records beyond the payload\n // cap. Count UTF-8 bytes, since reasoning often contains non-ASCII text.\n if (terminal) {\n if (Buffer.byteLength(line) > STREAM_TRACE_MAX_TEXT) return\n terminals.add(String(record.event))\n } else if (written + Buffer.byteLength(line) > STREAM_TRACE_MAX_BYTES) {\n capped = true\n line = `${JSON.stringify({ at: now() - startedAt, scope, event: 'trace-capped', bytes: written })}\\n`\n }\n try {\n appendFileSync(path, line)\n written += Buffer.byteLength(line)\n } catch {\n stopped = true\n }\n }\n write({ event: 'stream-open' })\n return {\n enabled: true,\n record(event, fields) {\n write(fields === undefined ? { event } : { event, ...fields })\n },\n close() {\n write({ event: 'stream-close', bytes: written })\n },\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.62.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'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n ToolCallId,\n errorChain,\n IMAGE_OFFLOAD_REQUIRED_CODE,\n offloadedImageText,\n projectOffloadedImages,\n requiredImageOffload,\n resolveRetryPolicy,\n textOnlyImageText,\n type ImageBlock,\n type LlmErrorOptions,\n type LlmImageRequestBudget,\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 RequestMessage,\n type StreamChunk,\n type TokenUsage,\n} 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'\nimport { boundTraceText, openStreamTrace, STREAM_TRACE_ENV } from './stream-trace.ts'\n\nimport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n capabilityDescription,\n compareByPlan,\n modelVisibleForAnyAccount,\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.65.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 * concatenated in the order the gateway sent it.\n *\n * Entries are read by their own text members rather than filtered on `type`:\n * DeepSeek sends `{ type: 'reasoning.text', text }` while the OpenAI family\n * sends `{ type: 'reasoning.summary', summary, format: 'openai-responses-v1' }`\n * — the same summary text the scalar `delta.reasoning` carries, in the\n * Responses protocol's vocabulary. A `type` filter would drop one family or the\n * other, and losing thinking is the failure this exists to prevent.\n *\n * `text` wins per entry, but an EMPTY `text` must not shadow a populated\n * `summary` (the Responses wire emits `text: ''` placeholders), so the fallback\n * tests for non-empty rather than merely present. Entries carrying neither\n * member — the encrypted blobs — contribute nothing, and no entry contributes\n * both, so a summary is never counted twice.\n *\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 const exact = stringValue(entry.text)\n const summary = stringValue(entry.summary)\n text += exact !== undefined && exact !== '' ? exact : (summary ?? '')\n }\n return text === '' ? undefined : text\n}\n\n/**\n * One SCALAR thinking delta, treating an empty string as \"this chunk carries\n * none\" — the same rule {@link reasoningDetailsText} applies inside the array.\n * The scalar and the array describe the same thinking, so an empty spelling of\n * one must not shadow populated text in the other (the Responses wire pads with\n * `text: ''`). `??` alone cannot express this: an empty string is not nullish,\n * so `reasoning: ''` beside a populated `reasoning_details` used to drop the\n * whole chunk's thinking.\n */\nfunction nonEmptyText(value: string | undefined): string | undefined {\n return value === undefined || value === '' ? undefined : value\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 *\n * Written with spaces rather than the CLI's underscores, because\n * {@link hasTerminalStreamMarker} normalizes the separator before matching:\n * a JSON body usually carries `premium credits exhausted` while the CLI's own\n * list is written `premium_credits_exhausted`, and both are the same refusal\n * (the pre-stream classifier normalizes identically).\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 normalized = message.toLowerCase().replaceAll('_', ' ')\n return TERMINAL_STREAM_ERROR_MARKERS.some((marker) => normalized.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 * Whether one rejection says \"ZDR requested, no ZDR-capable upstream\": the\n * provider spells the code `cmd_zdr_no_providers` in JSON error bodies and\n * `CMD_ZDR_NO_PROVIDERS` in plain-text ones (the official CLI's own\n * classifier checks both spellings, and its error text tells the user to\n * unset `CMD_ZDR`). Underscore-separated matching normalizes the separator, so\n * one comparison covers the variants — the same normalization the pre-stream\n * rejection classifier and `hasTerminalStreamMarker` already use.\n */\nconst ZDR_NO_PROVIDERS_PATTERN = /cmd[_\\s-]?zdr[_\\s-]?no[_\\s-]?providers/i\n\nfunction isZdrNoProviders(providerCode: string | undefined, providerDetail: string, errText: string): boolean {\n return ZDR_NO_PROVIDERS_PATTERN.test(providerCode ?? '')\n || ZDR_NO_PROVIDERS_PATTERN.test(providerDetail)\n || ZDR_NO_PROVIDERS_PATTERN.test(errText)\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 — and an explicit\n * refusal (`isRetryable: false`) or a terminal marker OUTRANKS a status, so a\n * 5xx carrying \"insufficient credits\" stays terminal instead of entering the\n * retry cadence as `SERVER`.\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 // An explicit refusal and a terminal marker both outrank the STATUS, so a 5xx\n // that carries \"insufficient credits\" (or `isRetryable: false`) cannot be\n // answered with `SERVER` — that put a permanent refusal back on\n // dsh-llm-retry's 1000-attempt cadence. Only a status with no such evidence\n // keeps the transient mapping, and an explicit `isRetryable: true` still\n // wins over everything.\n const retryable = isRetryable === true\n || (isRetryable === false || terminal\n ? false\n : (statusCode !== undefined ? retryableStatus : true))\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 RequestMessage[] -> 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/** The tool result one `role: 'tool'` message answers. */\ninterface ToolResultView {\n readonly toolCallId: string\n readonly isError?: boolean\n readonly content: readonly ContentBlock[]\n}\n\n/**\n * The tool result one message answers, or undefined when it answers none.\n *\n * The harness models a tool result as its own `role: 'tool'` message carrying\n * `toolCallId`/`isError` beside raw content blocks (a closed role map:\n * `MessageRoleMap.tool` is the only role a tool result can arrive on). Pairing\n * and emission MUST agree on this same view: otherwise a dropped result either\n * drops its call too (making the model forget completed work), or leaves an\n * unanswered call on the wire.\n */\nfunction toolResultOf(message: RequestMessage): ToolResultView | undefined {\n if (message.role !== 'tool') return undefined\n const { toolCallId, content } = message\n if (typeof toolCallId !== 'string' || toolCallId === '') return undefined\n return { toolCallId, isError: message.isError ?? false, content }\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 RequestMessage[]): {\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 const result = toolResultOf(message)\n if (result) resultIds.add(result.toolCallId)\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 }\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: ToolResultView): ToolResultMedia {\n const chunks: string[] = []\n const images: ImageAttachmentRef[] = []\n const seen = new Set<string>()\n for (const nested of block.content) {\n if (nested.type === 'text' || nested.type === 'reasoning') {\n if (nested.text) chunks.push(nested.text)\n continue\n }\n if (nested.type === 'image' && !seen.has(nested.attachment.attachmentId)) {\n seen.add(nested.attachment.attachmentId)\n images.push(nested.attachment)\n }\n }\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: RequestMessage): boolean {\n return message.content.some((block) => block.type === 'image')\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. The\n// offload set is a DURABLE surface fact: the adapter renders the surface's\n// `offloaded` marks with `projectOffloadedImages`, and when the history still\n// exceeds the budget it does NOT evict — it fails with\n// `IMAGE_OFFLOAD_REQUIRED` + `offloadImages`, which the default\n// `dsh-compaction-image-offload` plugin turns into one `image/offload` session\n// event and a retry. Every later request on the session then carries the same\n// placeholder text, across restore and fork, and the token meter stops counting\n// the evicted images as context. The budget is accounted in the encoded form,\n// because it is the base64 the wire actually carries that has to fit.\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/** One occurrence's exact request-version byte length, as the core counter wants it. */\ntype ImageVersionBytes = (block: { attachment: ImageAttachmentRef }) => number\n\n/**\n * The engine's durable-offload contract, as one object.\n *\n * Both members are required together: a half-populated policy would either lose\n * the surface's marks (re-sending evicted images as pixels) or lose the count\n * (silently sending an over-budget body), and neither is worth a partial\n * opt-in. The defaults are the engine's own helpers; the object exists so tests\n * can substitute a counting stub.\n */\nexport interface SurfaceImagePolicy {\n /** Render the surface's durable offload marks as placeholder text. */\n projectOffloadedImages: typeof projectOffloadedImages\n /** How many more leading retained occurrences must be offloaded. */\n requiredImageOffload: typeof requiredImageOffload\n}\n\n/** The engine's own helpers: what a process that injects nothing speaks. */\nconst ENGINE_IMAGE_POLICY: SurfaceImagePolicy = { projectOffloadedImages, requiredImageOffload }\n\n/**\n * The failure a route raises instead of evicting on its own. 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 members the core counter reads, plus the wire representation. */\ntype CoreImageBudget = Pick<\n LlmImageRequestBudget,\n 'representation' | 'maxBytes' | 'maxImages' | 'byteQuantum' | 'countQuantum'\n>\n\n/** The budget in the shape the core counter takes (representation + the rung). */\nfunction coreBudget(budget: RequestImageBudget): CoreImageBudget {\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 * Request options under one budget rung: the surface's durable marks become\n * placeholder text, and an over-budget history FAILS with the count to offload\n * instead of being evicted here. Throws rather than returning, so no caller can\n * accidentally send a body this route already knows is too large.\n *\n * The next rung is applied to the CURRENT projection, never to the raw history —\n * otherwise the 413 retry could reintroduce images the first rung had already\n * evicted.\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.\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).\n */\nasync function readRequestImage(\n attachments: AttachmentStore,\n ref: ImageAttachmentRef,\n): Promise<Uint8Array> {\n return (await attachments.readImageRequest(ref, requestImageTarget(ref))).data\n}\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 (the same placeholder text rides in every later request). A retained\n * occurrence on this route contributes no text at all — the pixels are inlined —\n * so its price is the family's visual-token count and nothing else.\n */\nfunction priceRequestImage(\n block: ImageBlock,\n model: string,\n imageCapable: boolean,\n): LlmImageRequestPrice {\n const ref = block.attachment\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 RequestMessage[],\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 const result = toolResultOf(message)\n if (message.role === 'user' && !result) {\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 // Both modern tool messages and legacy wrapped results use the same view.\n if (result) {\n if (!paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\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(result.toolCallId) ?? result.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(result.toolCallId) || 'unknown',\n output: result.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 RequestMessage[],\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 const result = toolResultOf(message)\n if (message.role === 'user' && !result) {\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 // Both modern tool messages and legacy wrapped results use the same view.\n if (result) {\n if (!paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\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(result.toolCallId) ?? result.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 * Whether requests enforce zero data retention by sending the\n * `x-cmd-zdr: 1` header (the same opt-in the official CLI exposes as\n * `CMD_ZDR=1`). Default false. Every chat request carries the header when\n * enabled. The provider refuses a model without a ZDR-capable upstream with\n * 422 `cmd_zdr_no_providers`; never retry that request without the header.\n * The decision endpoint (`/provider/v1/systemone`) is deliberately never\n * reached through this connection option — see `./systemone.ts`.\n */\n zdr?: boolean\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/**\n * Why a pre-stream rejection rotates to another account. `rate-limit` (a usage\n * window the provider NAMED), `throttled` (a 429 that named no window) and\n * `invalid-credential` are the three the pool records as marks; `unavailable`\n * is an account-scoped rejection that must NOT become a mark — the account's\n * key is valid and its windows may be open, the ACCOUNT just cannot serve THIS\n * request (no credits, a model outside its plan) — so the pool moves on\n * without remembering anything.\n *\n * The window/throttle split decides what the pool may CLAIM, never whether it\n * rotates: both leave rotation and mark the key, but only a named window lets\n * the pool report an exhausted usage window (issue #54).\n */\nexport type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable'\n\n/** What the rotation hook knows about the request it is rotating within. */\nexport interface AccountRotationContext {\n /** Every API key this request has already used, just-rejected key included. */\n tried: readonly string[]\n /** The provider's own reset time for a `rate-limit` rejection, in millis. */\n resetAtMs?: number\n}\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 before any response body streamed, for an account-scoped reason\n * (see {@link AccountRotationReason}). The host marks that key when the\n * reason warrants it and returns the next account's key to retry with, or\n * `undefined` to surface the failure. Only pre-stream rejections rotate — a\n * mid-stream failure never replays a partially consumed generation against\n * another account.\n *\n * `rotation.tried` lists every key this request has already used (the\n * just-rejected one included). The host must not offer one of them again:\n * with several accounts a rejection that does not mark the key (a plan or\n * balance rejection is model-specific, not account-fatal) would otherwise\n * re-offer the same account on every attempt and the pool could never reach\n * the accounts behind it.\n *\n * `rotation.resetAtMs` carries the provider's own reset time when the\n * rejection body published one, so the host can hold the key out until then\n * instead of waiting for a billing probe to learn the same fact.\n */\n rotateApiKey?: (\n rejectedKey: string,\n rejection: AccountRotationReason,\n connection: C,\n model?: string,\n rotation?: AccountRotationContext,\n ) => Promise<string | undefined>\n /**\n * Every API key the host can serve from, in rotation order and deduplicated\n * — the multi-account pool's own list. The picker's plan filter asks all of\n * them, because the pool (not any single account) is what serves a request;\n * a host without a pool omits this seam and the filter falls back to the key\n * that would serve the current request.\n */\n resolveAccountKeys?: () => Promise<readonly string[]>\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 engine's own\n * `projectOffloadedImages`/`requiredImageOffload`. Injecting a stub is how a\n * test observes the budget rungs a 413 walks.\n */\n imageOffload?: SurfaceImagePolicy\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' | 'invalid-response' | '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), `invalid-response`\n * (every call answered but its body was not usable JSON), or `network`\n * (no HTTP 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 */\ntype UsageEndpointFailure =\n | { kind: 'http'; status: number }\n | { kind: 'invalid-response'; status: number }\n | { kind: 'transport' }\n\nfunction classifyTotalFailure(\n failures: readonly string[],\n failed: readonly UsageEndpointFailure[],\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 if (failed.every((item) => item.kind === 'http' && item.status === 401)) {\n return 'invalid-key'\n }\n if (failed.every((item) => item.kind === 'http' && item.status >= 500)) {\n return 'service-unavailable'\n }\n if (failed.every((item) => item.kind === 'invalid-response')) return 'invalid-response'\n if (failed.every((item) => item.kind === 'transport')) 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 // Enforce ZDR on every chat request when selected. The provider is the\n // routing authority: an unsupported model (or unavailable ZDR capacity)\n // fails with 422 rather than sending the prompt through a retaining upstream.\n // Never omit the header based on a client-side capability snapshot.\n const zdr = connection.zdr === true\n const headers = protocol === 'cli'\n ? {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\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 ...(zdr ? { 'x-cmd-zdr': '1' } : {}),\n ...attributionHeaders(),\n }\n : {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\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. ZDR is the one header both\n // transports share: the Provider API documents `x-cmd-zdr: 1`\n // itself (commandcode.ai/docs/provider#zero-data-retention-zdr).\n ...(zdr ? { 'x-cmd-zdr': '1' } : {}),\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 /** Provider spelling, retained for terminal diagnostics rather than inferred from usage. */\n finishReason: string | undefined\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 finishReason: undefined,\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 /**\n * The durable-offload contract, resolved once (tests may inject a stub). The\n * contract cannot change while the process runs.\n */\n private readonly surfaceOffload: SurfaceImagePolicy\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.surfaceOffload = deps.imageOffload ?? ENGINE_IMAGE_POLICY\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 ImageBlock[]) =>\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', ...IDENTITY_ENCODING_HEADER, ...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 no account in the pool can run. Fails open —\n // a billing-fetch problem, an unknown plan, or a positive on-demand\n // balance all keep the catalog visible, and the server remains the final\n // gate (403 MODEL_NOT_IN_PLAN). The catalog itself is never filtered:\n // resolveModel still serves every model.\n //\n // EVERY account's entitlement is consulted, not just the one that happens\n // to serve right now (issue #51's follow-up: 《卡片会切换》). Keying the\n // filter on the serving account made the picker's contents depend on which\n // account rotation had reached — a Pro model vanished while a Go account\n // served and came back later — and it hid models the user's OTHER accounts\n // could run, which no request could ever fix. The union is the honest\n // question for a pool, and it only works together with the entitlement\n // rotation in the connect loop: a model offered here because SOME account\n // includes it is served there by that account, after at most one rejected\n // attempt.\n const accesses = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess()\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) => modelVisibleForAnyAccount(model.id, accesses))\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 raw = apiKey ?? (await this.deps.resolveApiKey(connection))\n // The chat path validates the key through the harness's own helper (see\n // `resolveApiKey` in the plugin entry); every account endpoint must run the\n // same check, or a key carrying a character no HTTP header can hold throws\n // inside `fetch` BEFORE any I/O — once per endpoint — and the report reads\n // as \"the network is down\". The credential reference is read structurally:\n // it belongs to the host's resolved options, not to this adapter's\n // connection type, and it only names the key in the rejection message.\n const named = (connection as { apiKeyEnv?: unknown }).apiKeyEnv\n const ref = typeof named === 'string' && named !== '' ? named : 'the stored credential'\n const key = assertUsableApiKey(raw, 'llm-commandcode', ref)\n return {\n Authorization: `Bearer ${key}`,\n ...IDENTITY_ENCODING_HEADER,\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 invalid JSON bodies come\n * back without a record; only a fetch failure propagates to the caller.\n *\n * `timeoutMs` is the caller's budget for this one request. The default is the\n * CATALOG probe's short cap, which fits the picker's fail-open reads; the\n * usage report deliberately passes the connection's own request budget so an\n * account query is not held to a stricter (and invisible) limit than chat.\n */\n private async fetchEndpointJson(\n url: string,\n headers: Record<string, string>,\n timeoutMs: number = MODELS_TIMEOUT_MS,\n ): Promise<{ status: number; record?: Record<string, unknown>; invalidResponse?: boolean }> {\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(timeoutMs),\n })\n if (!response.ok) return { status: response.status }\n let parsed: unknown\n try {\n parsed = await response.json()\n } catch {\n return { status: response.status, invalidResponse: true }\n }\n return isRecord(parsed)\n ? { status: response.status, record: parsed }\n : { status: response.status, invalidResponse: true }\n }\n\n /**\n * Every account's billing facts behind the picker's plan filter, in the\n * pool's rotation order and cached per key for {@link BILLING_ACCESS_TTL_MS}\n * (so the extra accounts cost their three requests once per TTL, not once\n * per picker load). `undefined` means the filter cannot be evaluated at all\n * — no key resolved — which {@link modelVisibleForAnyAccount} reads as\n * \"show everything\".\n *\n * The serving account is only the first entry: with several accounts the\n * model list must not depend on which of them rotation happens to be using.\n */\n private async loadPoolBillingAccess(): Promise<readonly (CommandCodeBillingAccess | undefined)[] | undefined> {\n const keys = await this.poolAccountKeys()\n if (keys.length === 0) return undefined\n return Promise.all(keys.map((key) => this.loadBillingAccessForKey(key)))\n }\n\n /**\n * The API keys the picker's plan filter must consult: every account the host\n * can serve from, in rotation order, when the host exposes one. A host\n * without a pool (or without the seam) reports just the key that would serve\n * this request — exactly the pre-pool behaviour.\n */\n private async poolAccountKeys(): Promise<readonly string[]> {\n try {\n const keys = await this.deps.resolveAccountKeys?.()\n const usable = (keys ?? []).filter((key) => typeof key === 'string' && key !== '')\n if (usable.length > 0) return usable\n } catch {\n // Fall through to the single-key answer below.\n }\n try {\n return [await this.deps.resolveApiKey(this.deps.options())]\n } catch {\n return []\n }\n }\n\n /**\n * One account's billing facts, cached for {@link BILLING_ACCESS_TTL_MS} and\n * shared across concurrent callers. `undefined` means \"unknown — show\n * everything\" (fail-open).\n */\n private async loadBillingAccessForKey(apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\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 * Two failure modes are NOT \"the network is down\", and the report must say\n * so rather than let {@link classifyTotalFailure} blame the connection:\n *\n * - A key that no HTTP header can carry (a stray newline from a paste, a\n * full-width character) makes `fetch` throw a `TypeError` **before any\n * I/O**, for every endpoint at once. The chat path refuses such a key\n * through `assertUsableApiKey`; this path must too, and it answers\n * `blocked: 'invalid-key'` instead of four phantom transport failures.\n * - The four endpoints get the SAME per-request budget as a chat call\n * (`connection.requestTimeoutMs`, default 60 s), not the catalog's 10 s\n * probe budget: on a slow link a 10 s cap made every account query time\n * out while chat kept working, which is exactly a \"check your network\"\n * banner that never clears.\n */\n async getUsage(apiKey?: string): Promise<CommandCodeUsageReport> {\n const connection = this.deps.options()\n const base = connection.apiBase\n let headers: Record<string, string>\n try {\n headers = await this.accountHeaders(apiKey)\n } catch (error: unknown) {\n // An unusable key is a CREDENTIAL verdict, not a transport one. A\n // missing key still propagates (the caller renders the unconfigured\n // state); only the harness's own \"characters no header can carry\"\n // rejection — and a blank resolved key — becomes `invalid-key`.\n if (error instanceof LlmError && error.code === 'INVALID_CREDENTIAL') {\n return { failures: [error.message], blocked: 'invalid-key' }\n }\n throw error\n }\n const failures: string[] = []\n // Keep received-but-unreadable bodies separate from requests that never\n // received a response. The former used to be counted as \"network\".\n const failed: UsageEndpointFailure[] = []\n\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> => {\n try {\n const { status, record, invalidResponse } = await this.fetchEndpointJson(\n `${base}${path}`,\n headers,\n connection.requestTimeoutMs,\n )\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}${invalidResponse ? ' returned an unreadable or invalid JSON body' : ''}`)\n failed.push(invalidResponse ? { kind: 'invalid-response', status } : { kind: 'http', status })\n return undefined\n }\n return record\n } catch (error: unknown) {\n failures.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n failed.push({ kind: 'transport' })\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, failed)\n if (blocked !== undefined) report.blocked = blocked\n\n return report\n }\n\n /**\n * Probe one account's real usage windows from `/alpha/billing/credits`. The\n * multi-account pool calls this when every account is marked exhausted: an\n * account whose windows no longer report `exceeded` is revived, and the\n * `resetAt` values feed the \"earliest reset\" error message.\n *\n * BOTH windows the endpoint publishes are read, not just `fiveHour`. An\n * account can have an open five-hour window and an exhausted WEEKLY quota at\n * the same time (the two are metered separately), and reading only the\n * shorter one revived such an account as \"usable\" — the pool then handed it\n * out, the provider rejected the request again, and the next all-marked pass\n * revived it once more, so a used-up account kept coming back (issue #51's\n * follow-up: \"切到一个不可用账号\"). `exceeded` is therefore true when ANY\n * published window is exceeded, and `resetAt` is the LATEST reset among the\n * exceeded ones — the binding constraint, because a clear five-hour window\n * buys nothing while the weekly quota is spent.\n *\n * Returns `undefined` when the probe itself failed (transport, non-200, or a\n * payload with no window limits at all) — a failed probe never changes pool\n * state. The monthly/purchased/free credit balances are deliberately NOT part\n * of this answer: they are balances rather than windows, they carry no reset\n * time, and the server remains the final gate on them.\n */\n async probeWindowLimits(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 if (windowLimits === undefined) return undefined\n let reported = false\n let exceeded = false\n let resetAt = 0\n for (const raw of [windowLimits.fiveHour, windowLimits.weekly]) {\n const window = isRecord(raw) ? parseWindowLimit(raw) : undefined\n if (window === undefined) continue\n reported = true\n if (!window.exceeded) continue\n exceeded = true\n // Same untrusted-magnitude rule as the rejection body's reset: a value\n // beyond the horizon is not a reset this route can act on, and pinning\n // a cooldown to it would keep the account out of rotation for the life\n // of the process (nothing probes a `cooldown`). Dropping it leaves the\n // mark `unknown`, which the next probe pass re-checks.\n if (window.resetAt > 0 && window.resetAt - Date.now() <= MAX_TRUSTED_RESET_MS) {\n resetAt = Math.max(resetAt, window.resetAt)\n }\n }\n // No window in the payload at all: nothing can be concluded, so the\n // caller keeps the mark (fail-safe, exactly like a failed probe).\n if (!reported) return undefined\n return { exceeded, resetAt: exceeded ? 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 // The session surface owns the offload set, so this throws\n // `IMAGE_OFFLOAD_REQUIRED` when more images must go; the retry then arrives\n // with the surface already updated.\n let requestOptions = withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[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 asks for another offload. Safe like the\n // rotation below: nothing streamed and the same key stays in use. The\n // stricter rung becomes another offload request rather than a local edit,\n // so the extra omissions are recorded on the session and survive the\n // retry. Zero here means the images are already gone and the body is\n // simply too big — fall through to the 413 diagnosis instead of asking\n // for an offload that cannot happen, which is also what keeps the branch\n // from looping.\n if (attempt.status === 413 && REQUEST_IMAGE_BUDGETS.length > 1) {\n const missing = this.surfaceOffload.requiredImageOffload(\n requestOptions.messages,\n coreBudget(REQUEST_IMAGE_BUDGETS[1]!),\n imageVersionBytes,\n )\n if (missing > 0) throw imageOffloadRequired(missing)\n }\n const rotate = this.deps.rotateApiKey\n // Account-scoped rejection (429/RATE_LIMITED, 401, or \"this account\n // cannot serve\"): retry the same body with another account when the host\n // has one. The tried set travels along so a rejection that does not mark\n // the key cannot make the pool re-offer it forever.\n const rejection = classifyAccountRejection(attempt.status, attempt.errText)\n if (\n rejection !== undefined\n && rotate !== undefined\n && options.signal?.aborted !== true\n && tried.size < MAX_ACCOUNT_ROTATIONS\n ) {\n const next = await rotate(apiKey, rejection.reason, connection, options.model, {\n tried: [...tried],\n ...(rejection.resetAtMs !== undefined && { resetAtMs: rejection.resetAtMs }),\n })\n if (next !== undefined && !tried.has(next)) {\n apiKey = next\n continue\n }\n }\n // The provider named a window limit — or refused the request as a plain\n // throttle — and no other account could serve. The turn must fail as a\n // RATE_LIMIT carrying that reset rather than as the generic\n // `PROVIDER_HTTP_ERROR` this status maps to: the CLI accepts the\n // `RATE_LIMITED` code on ANY status (a 400 is pinned by a test above), and\n // `PROVIDER_HTTP_ERROR` sits outside dsh-llm-retry's whitelist — so\n // without this the turn dies on the spot even though the provider said\n // exactly when the same request would work again.\n //\n // The two reasons keep their own wording: only a NAMED window may be\n // described as a spent window (issue #54), while a plain throttle says\n // what it is and leaves the window verdict to the pool's own diagnosis.\n //\n // A status that already maps to RATE_LIMIT (a plain 429) keeps the\n // mapping it had — `generateHttpError` owns the `Retry-After` header's cap\n // and finiteness rules there, and its tests pin them — unless the body\n // named its own reset, which is more precise.\n if (\n rejection !== undefined\n && (rejection.reason === 'rate-limit' || rejection.reason === 'throttled')\n && (rejection.resetAtMs !== undefined || attempt.status !== 429)\n ) {\n const reset = rejection.resetAtMs\n const wait = reset === undefined\n ? 0\n : Math.min(Math.max(1000, reset - Date.now()), RETRY_MAX_DELAY_MS)\n const when = reset === undefined ? undefined : new Date(reset).toISOString()\n const window = rejection.reason === 'rate-limit'\n throw new LlmError(\n (window\n ? 'llm-commandcode: the Command Code account is rate limited'\n : 'llm-commandcode: the Command Code account is rate limited (429)'\n + ' — the provider did not report an exhausted usage window')\n + (when === undefined ? '' : ` — the provider reports it resets at ${when}`)\n + (window\n ? ';当前 Command Code 账户已被限流'\n : ';当前 Command Code 账户被限流(429),服务商未报告用量窗口用尽')\n + (when === undefined ? '' : `,服务商给出的重置时间为 ${when}`),\n 'RATE_LIMIT',\n wait > 0 ? { providerRetryAfterMs: wait } : undefined,\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 // Raw-stream trace (opt-in via `DSH_COMMANDCODE_TRACE`): the only artifact\n // that can tell \"the provider closed this stream\" apart from \"our parser\n // missed the terminal event\" — see ./stream-trace.ts for why that\n // distinction is the whole diagnosis. Off, this is one environment read and\n // every call below is inert.\n const trace = openStreamTrace(`${options.provider}/${options.model}`)\n const streamStartedAt = Date.now()\n let chunkCount = 0\n let totalBytes = 0\n let lastChunkAt = streamStartedAt\n trace.record('response', {\n protocol,\n endpoint: protocol === 'cli'\n ? `${connection.apiBase}/alpha/generate`\n : `${connection.apiBase}/provider/v1/chat/completions`,\n status: response.status,\n attempts: tried.size,\n maxTokens,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n })\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 let finish: Extract<StreamChunk, { type: 'finish' }> | undefined\n let usage: TokenUsage | undefined\n let usageEmitted = false\n let endRecorded = false\n // Do not publish success until the assembled answer has been checked.\n // DSH converts an adapter throw into an error finish; throwing AFTER a\n // success finish would violate its single-terminal-event contract.\n function* handle(event: unknown): Generator<StreamChunk> {\n for (const chunk of handleEvent(asm, protocol, event)) {\n if (chunk.type === 'finish') finish = chunk\n else if (chunk.type === 'usage') usage = chunk.usage\n else yield chunk\n }\n }\n try {\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 trace.record('read-error', {\n chunks: chunkCount,\n bytes: totalBytes,\n silentMs: Date.now() - lastChunkAt,\n message: errorChain(error),\n })\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 trace.record('eof', {\n chunks: chunkCount,\n bytes: totalBytes,\n silentMs: Date.now() - lastChunkAt,\n totalMs: Date.now() - streamStartedAt,\n finishSeen: finish !== undefined,\n idleFired,\n buffered: buffer.length,\n })\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; it uses the same\n // terminal validation as events parsed in the line loop.\n yield* handle(parseStreamEventLine(buffer))\n }\n break\n }\n const text = decoder.decode(value, { stream: true })\n buffer += text\n chunkCount += 1\n totalBytes += value.byteLength\n lastChunkAt = Date.now()\n trace.record('chunk', {\n n: chunkCount,\n bytes: value.byteLength,\n text: boundTraceText(text),\n })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n yield* handle(parseStreamEventLine(line))\n }\n if (finish !== undefined) break\n }\n // Preserve the provider's usage even when this attempt fails. Usage is\n // cumulative, so only the latest sample is emitted, before the terminal.\n if (usage !== undefined) {\n usageEmitted = true\n yield { type: 'usage', usage }\n }\n if (finish !== undefined) {\n const failure = asm.sawContent ? undefined : emptyCompletionError(asm.finishReason, maxTokens, usage)\n trace.record('end', {\n outcome: failure === undefined ? 'finished' : failure.code === 'OUTPUT_TOKEN_LIMIT' ? 'output-token-limit' : 'empty',\n finishReason: asm.finishReason,\n ...(failure === undefined ? {} : { code: failure.code }),\n maxTokens,\n ...(usage === undefined ? {} : { usage }),\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: Date.now() - streamStartedAt,\n sawContent: asm.sawContent,\n })\n endRecorded = true\n if (failure !== undefined) throw failure\n yield finish\n } else {\n // The stream ended without its terminal event, and that is NOT a normal\n // ending — it must not be reported as one. Both transports terminate\n // explicitly (the CLI transport with a `finish` event, the Provider API\n // with a final `finish_reason` chunk), so an EOF here means the\n // response was closed mid-generation: the gateway, an intermediary\n // proxy, or the network. Synthesizing a clean `stop` is what turned a\n // truncated answer into a turn that just ended, with nothing in the UI\n // or the session log saying why. `dsh-llm-deepseek`'s `translate()`\n // raises this same code for this same condition (\"… stream ended before\n // message_stop\").\n const elapsed = Date.now() - streamStartedAt\n const detail = `${chunkCount} chunk(s), ${totalBytes} bytes, ${elapsed}ms`\n trace.record('end', {\n outcome: asm.sawContent ? 'stream-closed' : 'empty',\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: elapsed,\n sawContent: asm.sawContent,\n })\n endRecorded = true\n if (!asm.sawContent) {\n // Nothing usable came out of it (no visible text, no tool call): the\n // request has no tool action to replay, and this code is in the retry\n // policy's whitelist — the cut is absorbed instead of surfaced. A cut\n // during a long thinking phase lands here.\n throw new LlmError('Command Code returned an empty response;Command Code 返回了空响应,重试通常可恢复', 'EMPTY_RESPONSE')\n }\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} ended before its finish event (${detail})`\n + ' — the response was closed mid-generation, so this is not the model stopping by itself'\n + ';Command Code API 流式响应在结束事件之前被关闭(生成中途断流),并非模型主动结束——请重试'\n + `;若频繁出现,可用 ${STREAM_TRACE_ENV}=<文件路径> 抓取原始流以定位断流原因`,\n 'STREAM_CLOSED',\n )\n }\n } catch (error: unknown) {\n // A later read/provider error must not discard usage already received.\n if (!usageEmitted && usage !== undefined) yield { type: 'usage', usage }\n if (!endRecorded) {\n trace.record('end', {\n outcome: options.signal?.aborted ? 'aborted' : 'error',\n code: error instanceof LlmError ? error.code : 'unknown',\n finishReason: asm.finishReason,\n maxTokens,\n ...(usage === undefined ? {} : { usage }),\n sawContent: asm.sawContent,\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: Date.now() - streamStartedAt,\n })\n }\n throw error\n } finally {\n clearIdle()\n cleanup()\n trace.close()\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 === 422 && isZdrNoProviders(providerCode, providerDetail, errText)) {\n // Zero data retention refused (the `zdr` connection option is on): either\n // this model has no ZDR-capable upstream, or none had capacity at that\n // moment. Bilingual — the harness UI renders this message verbatim. The\n // code is matched shape-insensitively because the provider spells it both\n // ways (`cmd_zdr_no_providers` in the JSON error body, `CMD_ZDR_NO_PROVIDERS`\n // in plain-text ones, exactly as the official CLI's classifier reads it),\n // and the CLI's own user guidance is to unset CMD_ZDR.\n return new LlmError(\n `Command Code API error 422 (${detail}): zero data retention is enforced but no ZDR-capable`\n + ' upstream is available for this model — turn the ZDR setting off (or use another model)'\n + ';Command Code API 返回 422:已开启零数据保留(ZDR),但该模型当前没有可用的 ZDR 上游——'\n + '请关闭 ZDR 开关,或改用其他模型',\n 'PROVIDER_HTTP_ERROR',\n { status: 422 },\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 if (delta.trim() !== '') 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 asm.finishReason = stringValue(event.finishReason)\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 const outputDetails = isRecord(usage.outputTokenDetails) ? usage.outputTokenDetails : undefined\n const reasoningTokens = numberValue(outputDetails?.reasoningTokens) ?? numberValue(usage.reasoningTokens)\n if (reasoningTokens !== undefined) tokenUsage.reasoningTokens = reasoningTokens\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, GLM/Qwen/\n // Kimi answer with the DeepSeek-native `reasoning_content`, and the OpenAI\n // family answers with the scalar `reasoning` PLUS a `reasoning_details` array\n // whose entry is `{ type: 'reasoning.summary', summary }`. All three\n // spellings are read here, in that order, so no family's thinking is dropped\n // (measured live 2026-09-18, gpt-5.6-luna, 6/6 rounds: the scalar and the\n // array's `summary` carried the identical text every time). The\n // `reasoning_details` branch is a forward guard rather than the live path for\n // any family — every family that sends the array also sends a scalar\n // alongside it — so it only carries the text if that ever stops; it reads\n // `summary` as well as `text` precisely so the guard covers the family whose\n // array uses the other member.\n const reasoningDelta =\n nonEmptyText(stringValue(delta.reasoning))\n ?? nonEmptyText(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 if (contentDelta.trim() !== '') asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: contentDelta })\n }\n\n if (Array.isArray(delta.tool_calls)) {\n for (const rawCall of delta.tool_calls) {\n if (!isRecord(rawCall)) continue\n asm.sawContent = true\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 asm.finishReason = stringValue(choice.finish_reason)\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/** A terminal marker without text or tools is a failed attempt, not a completed turn. */\nfunction emptyCompletionError(reason: string | undefined, maxTokens: number, usage: TokenUsage | undefined): LlmError {\n const detail = `finish_reason=${reason ?? 'unknown'}, max_tokens=${maxTokens}, outputTokens=${usage?.outputTokens ?? 'unknown'}, reasoningTokens=${usage?.reasoningTokens ?? 'unknown'}`\n if (mapFinishReason(reason).kind === 'max-tokens') {\n // A length finish proves a generation limit, not how all tokens were spent.\n // Keep this outside the retry whitelist: replaying the identical budget\n // can repeatedly charge for reasoning without ever producing an answer.\n return new LlmError(\n `Command Code reached the output token limit without producing answer text or a tool call (${detail})`\n + ';Command Code 已达到输出 token 上限,但没有生成正文或工具调用;请调整思考强度,或在模型和接口上限内增加输出预算',\n 'OUTPUT_TOKEN_LIMIT',\n )\n }\n if (reason === 'content_filter' || reason === 'content-filter') {\n return new LlmError(`Command Code filtered the response (${detail});Command Code 拦截了响应,未生成正文或工具调用`, 'CONTENT_FILTER')\n }\n return new LlmError(\n `Command Code finished without producing answer text or a tool call (${detail})`\n + ';Command Code 返回了空响应(可能只有思考内容),重试通常可恢复',\n 'EMPTY_RESPONSE',\n )\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 */\n/**\n * Classify a pre-stream rejection that is about the ACCOUNT rather than about\n * the request, using the official CLI's own rules (command-code@1.56.0:\n * `parseWindowLimitError`, `isInsufficientCreditsRequestError`,\n * `parseSpendCapError` and the terminal-marker list\n * `[\"premium_credits_exhausted\", \"model_not_in_plan\", \"insufficient credits\"]`).\n * Undefined means \"not an account-scoped rejection\": a malformed request, an\n * oversized body or a context overflow must fail fast instead of walking the\n * whole account pool.\n *\n * Issue #51's follow-up is why this exists. Only 429/401 used to rotate, so\n * every other account-scoped rejection was terminal AND invisible to the pool:\n * an account that could not pay, or could not run the model, stayed \"usable\",\n * was handed out again on the next request, and produced the same error again\n * (\"切到一个不可用账号后就报 400,还挺频繁\"). The three reasons differ in what\n * the host should do with them, which is the caller's decision, not this\n * function's:\n *\n * - `rate-limit`: a usage WINDOW is spent. The code `RATE_LIMITED` is the\n * authoritative signal — the CLI accepts the code OR a 429 status — and the\n * body's `error.rateLimit` names the window and its `reset` (in seconds),\n * so the host can hold the account out until the provider's own reset time.\n * - `throttled`: the provider refused the request (429 or a bare\n * `RATE_LIMITED` code) without naming a usage window. It is account-scoped\n * like the above, so it rotates and marks the key the same way, but it is\n * NOT evidence that a metered window is spent: the CLI's own\n * `parseWindowLimitError` returns a window limit only when\n * `resolveWindowLabel` can name one, and a burst/model/spend limiter the\n * billing endpoint cannot see is exactly this shape (issue #54's report: a\n * 429 whose probe read five-hour 2% and weekly 10% while the error claimed\n * both were exhausted).\n * - `invalid-credential`: 401; the key itself is bad.\n * - `unavailable`: the key is fine but this account cannot serve: no credits\n * (`400 Insufficient credits`, the codes `INSUFFICIENT_CREDITS`,\n * `USAGE_EXCEEDED`, `PREMIUM_CREDITS_EXHAUSTED`, or a spend-cap wording)\n * or a model outside its plan (`MODEL_NOT_IN_PLAN`). Rotating must NOT mark\n * the account: the fact is about the model or the balance, it can change\n * without the key changing, and a `:free` model can still be served by an\n * account with an empty balance. These codes are recognized on EVERY\n * status — a 5xx that proxies the provider's own credits/plan body is\n * still an account fact, and only the prose scan is confined to 4xx.\n */\n\n/**\n * The provider's structured \"this account cannot serve this request\" codes.\n *\n * Status-independent on purpose, mirroring the CLI's classifier, which reads\n * the code before any status guard. A 5xx that carries one of these must not\n * be retried as a transient provider failure: the same request against the\n * same account cannot succeed, so the caller rotates past it (without marking\n * the key) instead of replaying it on the harness's retry cadence.\n */\nconst ACCOUNT_UNAVAILABLE_CODES: ReadonlySet<string> = new Set([\n 'USAGE_EXCEEDED',\n 'INSUFFICIENT_CREDITS',\n 'PREMIUM_CREDITS_EXHAUSTED',\n 'MODEL_NOT_IN_PLAN',\n])\n\nfunction classifyAccountRejection(status: number, errText: string): { reason: AccountRotationReason; resetAtMs?: number } | undefined {\n if (status === 429 || readProviderErrorCode(errText)?.toUpperCase() === 'RATE_LIMITED') {\n const evidence = readWindowLimitEvidence(errText)\n // A plain throttle carries no reset: an `error.rateLimit.reset` without a\n // window label is the provider saying \"come back later\", not \"this window\n // is spent\", and a mark pinned to it would be a window claim the body never\n // made.\n if (evidence.window === undefined) return { reason: 'throttled' }\n return evidence.resetAtMs === undefined\n ? { reason: 'rate-limit' }\n : { reason: 'rate-limit', resetAtMs: evidence.resetAtMs }\n }\n if (status === 401) return { reason: 'invalid-credential' }\n // The structured account codes are checked BEFORE the status guard, exactly\n // like `RATE_LIMITED` above: a gateway that proxies the provider's own\n // credits/plan rejection under a 5xx is still reporting a fact about this\n // account, and treating it as \"the provider is unavailable\" is what turned a\n // permanent refusal into a retried one — `SERVER` reaches dsh-llm-retry's\n // 1000-attempt cadence while the sibling accounts that could serve are never\n // consulted. The guard below therefore covers only the rejections with NO\n // such code, whose evidence is prose: a bare 5xx (or a status under 400) is\n // the provider being unavailable and must keep its retry cadence for every\n // account instead of being remembered against one. `tests/adapter.test.ts`\n // pins both halves.\n const code = readProviderErrorCode(errText)?.toUpperCase()\n if (code !== undefined && ACCOUNT_UNAVAILABLE_CODES.has(code)) return { reason: 'unavailable' }\n if (status < 400 || status >= 500) return undefined\n // Underscored and spaced spellings are the same words: a JSON body carries\n // `insufficient_credits` / `model_not_in_plan`, while the CLI's own marker\n // list is written with spaces. Normalizing the separator keeps both wire\n // spellings classified, and the explicit code list above covers a body that\n // carries a code and no message at all — which is exactly how the code-only\n // `INSUFFICIENT_CREDITS` body slipped through before.\n const lower = errText.toLowerCase().replaceAll('_', ' ')\n if (\n lower.includes('insufficient credits')\n || lower.includes('premium credits exhausted')\n || lower.includes('model not in plan')\n || /insufficient (credit|balance)/.test(lower)\n || /out of credit/.test(lower)\n || /not (available|included)[^.]{0,40}plan/.test(lower)\n || lower.includes('upgrade your plan')\n ) {\n return { reason: 'unavailable' }\n }\n return undefined\n}\n\n/** The machine-readable `error.code`/`error.type` of a pre-stream failure body. */\nfunction readProviderErrorCode(errText: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(errText)\n if (!isRecord(parsed)) return undefined\n const error = isRecord(parsed.error) ? parsed.error : parsed\n return stringValue(error.code) ?? stringValue(error.type)\n } catch {\n return undefined\n }\n}\n\n/**\n * How far ahead a provider-published reset may be and still be trusted.\n *\n * Generous on purpose: the weekly window is the longest this provider meters,\n * and the value is a plausibility bound rather than a policy. Beyond it the\n * reset is dropped rather than clamped, which leaves the account's mark\n * `unknown` — the state the pool's probe pass re-checks — instead of a\n * cooldown that never expires.\n */\nconst MAX_TRUSTED_RESET_MS = 30 * 24 * 60 * 60 * 1000\n\n/**\n * The usage-window evidence carried by a rejected request, mirroring the CLI's\n * `parseWindowLimitError` → `resolveWindowLabel`/`extractResetAtMs` pair.\n *\n * `window` is present only when the body actually names one: a\n * `error.rateLimit.window` of `fiveHour`/`weekly`/`daily`, or the\n * \"usage limit for your plan\" wording (read as `weekly` when it says so, else\n * `fiveHour`). That is the CLI's own bar for calling a rejection a WINDOW\n * limit, and it is what keeps a bare 429 — a burst limiter, a model-level\n * limit, a spend cap `windowLimits` cannot show — from being reported as an\n * exhausted window (issue #54).\n *\n * `resetAtMs` is the reset the body publishes: `error.rateLimit.reset` is\n * SECONDS (`1e3 * reset`, like the CLI), and a `resets at <ISO>` stamp in the\n * message is honored as the fallback. Either can be present without the other;\n * the window label is what decides the classification.\n */\nfunction readWindowLimitEvidence(errText: string): { window?: 'fiveHour' | 'weekly' | 'daily'; resetAtMs?: number } {\n let named: string | undefined\n let message = ''\n let seconds: number | undefined\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed)) {\n const error = isRecord(parsed.error) ? parsed.error : parsed\n const rateLimit = isRecord(error.rateLimit) ? error.rateLimit : undefined\n named = stringValue(rateLimit?.window)\n message = stringValue(error.message) ?? stringValue(parsed.message) ?? ''\n seconds = numberValue(rateLimit?.reset)\n }\n } catch {\n // A plain-text body carries no structured window; the message scan below\n // still reads its `resets at <ISO>` stamp.\n }\n const window = named === 'fiveHour' || named === 'weekly' || named === 'daily'\n ? named\n : /usage limit for your plan/i.test(message) || /usage limit for your plan/i.test(errText)\n ? (/weekly/i.test(message) ? 'weekly' : 'fiveHour')\n : undefined\n const stamp = /resets at (\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z)/i.exec(message)?.[1]\n ?? /resets at (\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z)/i.exec(errText)?.[1]\n const stamped = stamp === undefined ? undefined : Date.parse(stamp)\n const published = seconds !== undefined && seconds > 0\n ? Math.round(seconds * 1000)\n : stamped !== undefined && !Number.isNaN(stamped) ? stamped : undefined\n // A published reset is UNTRUSTED input, and two things break on a bogus\n // magnitude: `new Date(...).toISOString()` throws `RangeError: Invalid time\n // value` (replacing the intended RATE_LIMIT with an internal error), and a\n // mark pinned beyond the horizon becomes a `cooldown` no probe will ever\n // revisit — the account leaves rotation for the life of the process. A usage\n // window resets within days, so anything further out is not a reset this\n // route can act on: dropping it degrades the mark to `unknown`, which the\n // pool's probe pass re-checks.\n const resetAtMs = published !== undefined\n && Number.isFinite(published)\n && published - Date.now() <= MAX_TRUSTED_RESET_MS\n ? published\n : undefined\n return {\n ...(window === undefined ? {} : { window }),\n ...(resetAtMs === undefined ? {} : { resetAtMs }),\n }\n}\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 | 'blockedInvalidResponse' // received an unreadable response body\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 blockedInvalidResponse:\n '⚠️ Command Code 返回了无法读取的响应 — 请检查宿主的 HTTP 代理或响应解压配置',\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 blockedInvalidResponse:\n '⚠️ Command Code returned an unreadable response — check the host HTTP proxy or response decoding',\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 === 'invalid-response') {\n lines.push(commandCopy(locale, 'blockedInvalidResponse'), '')\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 */\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.\n *\n * `mode: 'strict'` carries a LAZY schema factory (`create()`), which the\n * registry requires and the Gateway validates with (`codec.create().parse`).\n * The schema is built by `makeStrictCodec` from the endpoint's hand-rolled\n * validator, so nothing here depends on a generated codec.\n */\ninterface StrictCodec<Output> {\n readonly mode: 'strict'\n readonly typeSymbol: string\n readonly create: () => TypertSchema<Output>\n}\n\n/** Use the same strict-codec shape for invocation parameters and results. */\nexport function makeStrictCodec<Output>(typeSymbol: string, schema: TypertSchema<Output>): StrictCodec<Output> {\n return { mode: 'strict', typeSymbol, create: () => schema }\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: makeStrictCodec(typeSymbol, 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 === 'invalid-response' || 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 // Every Host contribution must carry its reflection model. This hand-written\n // Remote deliberately has no generated reflection exports, so use the\n // official empty-model form rather than a cast that would leave registry\n // 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","/**\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 makeStrictCodec,\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/** Optional account target; the Host still checks it against saved slots. */\nconst loginTargetSchema: TypertSchema<string | undefined> = {\n parse(value: unknown): string | undefined {\n if (value === undefined || typeof value === 'string') return value\n return reject('targetRef')\n },\n}\n\n/** Build one login invocation descriptor. Only begin accepts an account ref. */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n const descriptor = makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n return method === 'loginBegin'\n ? {\n ...descriptor,\n parameters: [{\n name: 'targetRef', wire: 'targetRef', source: 'json',\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#CommandCodeLoginTargetRef`, loginTargetSchema),\n acceptsUndefined: true,\n }],\n }\n : descriptor\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(targetRef?: string): 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(targetRef?: string): Promise<CommandCodeLoginStatus> {\n const login = this.requireLogin()\n return login.begin(targetRef)\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 { IDENTITY_ENCODING_HEADER } from './response-encoding.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, targetRef?: string): Promise<void>\n /** Reject an account target that is not a saved slot before opening Studio. */\n validateTargetRef?(targetRef: string | undefined): void\n}\n\n/** Resolve a browser-login destination without allowing arbitrary credential writes. */\nexport function loginCredentialRef(\n targetRef: string | undefined,\n defaultRef: string,\n accounts: readonly { apiKeyEnv?: string }[],\n): string {\n if (targetRef === undefined) return defaultRef\n if (targetRef === defaultRef || !accounts.some((account) => account.apiKeyEnv === targetRef)) {\n throw new Error('the target account must be saved before browser sign-in')\n }\n return targetRef\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', ...IDENTITY_ENCODING_HEADER, 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 start that is still binding its port is REJOINED through\n * {@link CommandCodeLoginFlow.begin}'s in-flight promise, because the status\n * face cannot say `waiting` until that bind settles; a terminal state makes the\n * 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 /**\n * The start currently binding a port, if any. Every `begin()` that arrives\n * before it settles joins it: two independent starts would each bind their\n * own loopback server, and only the LAST one is reachable by\n * {@link CommandCodeLoginFlow.teardown} — the orphan keeps listening and\n * answering `/callback` for the process's lifetime, and ten of them exhaust\n * the port window so browser login dies until the Host restarts.\n */\n private starting: Promise<CommandCodeLoginStatus> | undefined\n /** A live attempt's destination; different rows may not rejoin it. */\n private targetRef: string | undefined\n /** A `cancel()` that arrived while a start was still binding (see {@link CommandCodeLoginFlow.cancel}). */\n private cancelPending = false\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(targetRef?: string): Promise<CommandCodeLoginStatus> {\n if (this.disposed) throw new Error('login flow has been disposed')\n this.deps.validateTargetRef?.(targetRef)\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) {\n if (this.targetRef !== targetRef) throw new Error('another account login is already in progress')\n return this.statusValue\n }\n // ...and rejoin a start that has not published `waiting` yet. Two GUI tabs\n // (or a Sign-in that follows a cancel which arrived too early to retire\n // anything) would otherwise each bind a loopback server; see `starting`.\n if (this.starting !== undefined) {\n if (this.targetRef !== targetRef) throw new Error('another account login is already in progress')\n return this.starting\n }\n this.cancelPending = false\n this.targetRef = targetRef\n const starting = this.startAttempt(targetRef)\n this.starting = starting\n try {\n return await starting\n } finally {\n if (this.starting === starting) this.starting = undefined\n }\n }\n\n /**\n * The binding half of {@link CommandCodeLoginFlow.begin}: one attempt, one\n * server, one published `waiting` status. Callers reach it only through\n * `begin()`'s single-flight fence.\n */\n private async startAttempt(targetRef: string | undefined): Promise<CommandCodeLoginStatus> {\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 // The attempt may have been retired while the port was being bound: a\n // `cancel()` (the panel's ×, or a quick Sign-in → Cancel → Sign-in) cannot\n // see a `waiting` status yet, and a `dispose()` may have unloaded the\n // plugin. Publishing `waiting` now would hand the user a live authUrl they\n // already asked to drop and start a watchdog nobody can reach, so the\n // freshly bound server is closed here instead.\n if (this.disposed || this.cancelPending) {\n const cancelled = !this.disposed\n this.cancelPending = false\n this.teardown()\n if (cancelled) this.setStatus({ state: 'failed', reason: 'cancelled' })\n return this.statusValue\n }\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, targetRef),\n (failure) => this.failFrom(attempt, failure),\n )\n return this.statusValue\n }\n\n /**\n * Cancel a waiting attempt; terminal states are untouched. A start that is\n * still binding a port is flagged instead of ignored — it cannot be torn\n * down from here (its server does not exist yet), so `startAttempt` observes\n * the flag once the bind settles and retires it.\n */\n cancel(): void {\n if (this.disposed) return\n if (this.statusValue.state === 'waiting') {\n this.teardown()\n this.setStatus({ state: 'failed', reason: 'cancelled' })\n return\n }\n if (this.starting !== undefined) this.cancelPending = true\n }\n\n /** Stop everything; a waiting attempt ends cancelled. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.cancelPending = false\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) {\n // Another attempt owns the tracked server. This one is unreachable by\n // every teardown path, so it is closed here — an orphaned listener\n // would answer /callback for the rest of the process's life and hold\n // a port out of the login window.\n closeServer(server)\n return\n }\n this.server = undefined\n // A post-listen error leaves a server that may still be listening;\n // close() is a no-op (safe) when it never bound or is already gone.\n closeServer(server)\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, targetRef: string | undefined): 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 this.deps.validateTargetRef?.(targetRef)\n await this.deps.storeKey(credentials, targetRef)\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 closeServer(this.server)\n this.server = undefined\n this.settle = undefined\n }\n}\n\n/** Close one loopback server without letting \"not running\"/\"already closed\" escape. */\nfunction closeServer(server: Server | undefined): void {\n try {\n server?.close()\n } catch {\n // The server never bound, or was already closed: nothing to release.\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'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.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 * 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 *\n * `preexisting` is the one fact `displaced` cannot carry: an `undefined`\n * `displaced` means EITHER \"the field was unset when we took over\" (give\n * `undefined` back on disable) OR \"the field already read `commandcode`\"\n * (touch nothing on disable — see {@link applyCommandCodeSearchSelection}).\n * Collapsing the two is what turned a user's own `searchProvider: commandcode`\n * pin into an auto-select — and then into `WEB_PROVIDER_AMBIGUOUS` on every\n * search — the moment this plugin was disabled or unloaded.\n */\nexport interface CommandCodeSearchSelection {\n owner: boolean\n displaced: string | undefined\n /** Whether the field already read `commandcode` when this plugin first took it over. */\n preexisting: boolean\n}\n\n/** Fresh selection state: the plugin starts out not owning the selection. */\nexport function commandCodeSearchSelection(): CommandCodeSearchSelection {\n return { owner: false, displaced: undefined, preexisting: false }\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 and\n * `preexisting` is set, so the later disable is a no-op rather than a guess\n * at the factory default. A \"no-op\" means the field is left ALONE: writing\n * that `undefined` back would destroy the user's own pin, and dsh-web reads\n * a cleared `searchProviderId` as auto-select — where a second usable\n * provider (the shipped `deepseek-official` is usable whenever a DeepSeek\n * key resolves) makes EVERY later search throw\n * `WEB_PROVIDER_AMBIGUOUS`.\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 // Three cases, and `displaced` alone cannot tell the last two apart:\n // a sibling's id (restore it), the field was unset (restore `undefined`),\n // or the field already read OUR id (touch nothing — see the disable\n // branch). `preexisting` carries that third case.\n state.preexisting = prior === COMMANDCODE_SEARCH_PROVIDER_ID\n state.displaced = state.preexisting ? 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 // Restore ONLY a selection this plugin actually took over. `preexisting`\n // means the field already read `commandcode` before we ever touched it\n // (a manual `searchProvider: commandcode` patch,\n // `$DSH_WEB_SEARCH_PROVIDER`, or a surviving runtime): assigning the\n // empty memory back would clear the user's own pin and hand the\n // selection to auto-select, which throws `WEB_PROVIDER_AMBIGUOUS` as\n // soon as a second provider is usable — while our own provider stays\n // registered either way.\n if (!state.preexisting) field.searchProviderId = state.displaced\n state.preexisting = false\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 ...IDENTITY_ENCODING_HEADER,\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 configuration files.`,\n hintDescriptions: { zh: `保存在凭据库(${ref}),不会写入配置文件。` },\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: ['commandGuard'],\n group: 'advanced',\n kind: 'boolean',\n label: 'AI command guard',\n descriptions: { zh: 'AI 命令安全预判' },\n hint: 'typesafe/jev judges whether a shell command is safe; sandbox escalations'\n + ' also need separate scope and necessity verdicts. All must be confident'\n + ' enough; everything else asks as usual. Off by default.',\n hintDescriptions: { zh: '由 typesafe/jev 判断 shell 命令是否安全;沙箱提权还要分别判断范围与必要性,三项都足够确定才自动放行,其余照常弹窗。默认关闭。' },\n // Off is the shipped default and the safe reading of an unset document.\n format: (value) => (value === true ? 'true' : 'false'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\n },\n {\n path: ['commandGuardLevel'],\n group: 'advanced',\n kind: 'select',\n label: 'Auto-approve threshold',\n descriptions: { zh: '自动放行阈值' },\n hint: 'How confident typesafe/jev must be before a command runs without asking. Default: medium.',\n hintDescriptions: { zh: 'typesafe/jev 需要多确定才免弹窗放行;默认「中」。' },\n // Mirrors COMMAND_GUARD_LEVELS / COMMAND_GUARD_LEVEL_THRESHOLDS in ./command-guard.ts.\n options: [\n { value: 'high', label: 'High (0.95, approves least)', descriptions: { zh: '高(0.95,放行最少)' } },\n { value: 'medium', label: 'Medium (0.9)', descriptions: { zh: '中(0.9)' } },\n { value: 'low', label: 'Low (0.8, approves most)', descriptions: { zh: '低(0.8,放行最多)' } },\n ],\n format: (value) => (value === 'high' || value === 'low' ? value : 'medium'),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === 'high' || trimmed === 'medium' || trimmed === 'low'\n ? { kind: 'set', value: trimmed }\n : undefined\n },\n },\n {\n path: ['zdr'],\n group: 'advanced',\n kind: 'boolean',\n label: 'Zero data retention (ZDR)',\n descriptions: { zh: '零数据保留(ZDR)' },\n hint: 'Route requests only through upstreams that retain nothing and never'\n + ' train on prompts (the CLI\\'s CMD_ZDR=1). Models without an available'\n + ' ZDR upstream fail instead of losing protection; ZDR is usually'\n + ' billed at higher pass-through rates. Off by default.',\n hintDescriptions: {\n zh: '请求只经由不留存数据、也不用于训练的上游(等价于 CLI 的 CMD_ZDR=1)。'\n + '没有可用 ZDR 上游的模型会报错,不会降级为非 ZDR 请求;'\n + 'ZDR 通常按更高的透传价计费。默认关闭。',\n },\n // Off is the shipped default and the safe reading of an unset document.\n format: (value) => (value === true ? 'true' : 'false'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\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 settings\n // page stays 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 * Host-side client for Command Code's System One decision endpoint\n * (`POST {apiBase}/provider/v1/systemone`).\n *\n * `typesafe/jev` is **not a chat model**: it takes a `state` plus typed\n * questions and answers with probabilities, never text, and it never streams.\n * It is therefore absent from `/provider/v1/models` (so the picker can never\n * offer it) and must never be registered as a model route — this plugin uses it\n * as an internal advisor instead: the command guard in `./command-guard.ts`\n * asks it whether a shell command is safe to auto-approve.\n *\n * The three question types are the whole vocabulary (command-code@1.65.0\n * `systemOneRequestSchema`, unchanged since 1.64.0):\n *\n * - `noul` — \"is this true?\", optional `criteria: { true, false }` describing\n * each verdict. Answers with `noul`, the probability of *yes*.\n * - `choice` — \"which one?\", `criteria` maps each option key to its\n * description. Answers with `choice`, plus optional `confidence` and\n * `probabilities`.\n * - `score` — \"where on this rubric?\", `criteria` is an array of at least two\n * levels, lowest first. Answers with `score`, `legend` and `probabilities`.\n *\n * A request carries at most 20 questions and every answer is keyed by the\n * question id it belongs to. `usage` is reported per request, in tokens.\n *\n * Billing: free through 2026-09-24T23:59:59Z, then $0.042 per 1M input tokens\n * with output free. The model has **no ZDR-capable upstream**, so a request\n * carrying `x-cmd-zdr: 1` is refused with HTTP 422 `cmd_zdr_no_providers` —\n * this client never sends that header, and it must stay that way even though\n * the plugin now ships a ZDR switch for chat (`Config.zdr` → the `x-cmd-zdr: 1`\n * header per model, gated on `KNOWN_NON_ZDR_MODELS`): the decision endpoint is\n * reached through THIS module's own request path, never through the adapter's\n * chat connection, so the two cannot drift — and a deployment that later widens\n * ZDR must exclude this endpoint rather than route it through the switch.\n *\n * Auth is the plugin's ordinary chain (the multi-account pool, the credentials\n * seam, the CLI auth file) through the same `Authorization: Bearer <key>` and\n * `x-command-code-version` headers every other endpoint uses.\n *\n * @module dsh-commandcode-provider/systemone\n */\n\nimport { attributionHeaders } from '@deepseek-ai/dsh-llm'\nimport { COMMAND_CODE_CLI_VERSION } from './adapter.ts'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\n\n/** Path of the decision endpoint, relative to `apiBase`. */\nexport const SYSTEMONE_ROUTE = '/provider/v1/systemone'\n\n/** The one decision model the endpoint serves today (aliases: `jev`, `jev-latest`, `typesafe-ai/jev`). */\nexport const SYSTEMONE_MODEL = 'typesafe/jev'\n\n/** Server-enforced ceiling on questions per request (command-code@1.65.0 `zP`). */\nexport const SYSTEMONE_MAX_QUESTIONS = 20\n\n/** Milliseconds a decision may take before the caller gives up on it. */\nexport const SYSTEMONE_DEFAULT_TIMEOUT_MS = 1500\n\n/** A criterion description: free-form JSON, rendered to the model as context. */\nexport type SystemOneInstructions =\n | string\n | number\n | boolean\n | null\n | readonly SystemOneInstructions[]\n | { readonly [key: string]: SystemOneInstructions }\n\n/** One typed question. The `criteria` shape is fixed by the question's type. */\nexport type SystemOneQuestion =\n | {\n readonly type: 'noul'\n readonly instructions: SystemOneInstructions\n readonly criteria?: { readonly true?: SystemOneInstructions; readonly false?: SystemOneInstructions }\n }\n | {\n readonly type: 'choice'\n readonly instructions: SystemOneInstructions\n readonly criteria: { readonly [option: string]: SystemOneInstructions }\n }\n | {\n readonly type: 'score'\n readonly instructions: SystemOneInstructions\n readonly criteria: readonly SystemOneInstructions[]\n }\n\n/** One decision request: the situation, and the typed questions about it. */\nexport interface SystemOneRequest {\n /** Decision model id; defaults to {@link SYSTEMONE_MODEL} at the call site. */\n readonly model?: string\n /** The situation under judgement — text, or any JSON the question can refer to. */\n readonly state: SystemOneInstructions\n /** Questions keyed by a stable id, echoed in the answers. At most {@link SYSTEMONE_MAX_QUESTIONS}. */\n readonly questions: { readonly [id: string]: SystemOneQuestion }\n}\n\n/** One parsed answer. Only the members this plugin consumes are kept. */\nexport type SystemOneAnswer =\n | { readonly type: 'noul'; readonly noul: number }\n | {\n readonly type: 'choice'\n readonly choice: string\n readonly confidence?: number\n readonly probabilities?: Readonly<Record<string, number>>\n }\n | {\n readonly type: 'score'\n readonly score: number\n readonly confidence?: number\n readonly probabilities?: Readonly<Record<string, number>>\n }\n\n/** Per-request token usage as the endpoint reports it. */\nexport interface SystemOneUsage {\n readonly inputTokens?: number\n readonly outputTokens?: number\n}\n\n/** A parsed decision response. */\nexport interface SystemOneResponse {\n /** The model that answered, when the endpoint echoes one. */\n readonly model?: string\n /** Answers keyed by question id. */\n readonly answers: Readonly<Record<string, SystemOneAnswer>>\n /** Token usage, when the endpoint reports it. */\n readonly usage?: SystemOneUsage\n}\n\n/** Why a decision call produced no usable answer. */\nexport type SystemOneFailureKind =\n /** The request could not be built (no questions, too many, an invalid apiBase). */\n | 'invalid-request'\n /** No usable credential — the pool's own MISSING_CREDENTIAL / invalid-key surface. */\n | 'credential'\n /** The endpoint answered a non-2xx status. */\n | 'http'\n /** The connection failed before a response arrived. */\n | 'network'\n /** The decision did not arrive inside the caller's budget. */\n | 'timeout'\n /** The caller withdrew the request (the approval was answered elsewhere). */\n | 'aborted'\n /** A 2xx body that is not a decision response. */\n | 'invalid-response'\n\n/** The one error type this client throws. Callers fail closed on it. */\nexport class SystemOneError extends Error {\n constructor(\n message: string,\n readonly kind: SystemOneFailureKind,\n readonly status?: number,\n options?: { cause?: unknown },\n ) {\n super(message, options)\n this.name = 'SystemOneError'\n }\n}\n\n/** Everything the client needs beyond the request itself. */\nexport interface SystemOneDeps {\n /** Provider API base URL, read per call (settings-aware). */\n apiBase: () => string\n /** Resolve a usable API key from the plugin's own chain. */\n resolveApiKey: () => Promise<string>\n /** Injectable fetch (tests); defaults to the global `fetch`. */\n fetchImpl?: typeof fetch\n}\n\n/** Deadline plus the reason it fired, so a caller can tell a timeout from a withdrawal. */\ninterface SystemOneDeadline {\n readonly signal: AbortSignal\n /** Whether the caller's own signal was the one that aborted. */\n callerAborted: () => boolean\n /** Whether the timeout was the one that aborted. */\n timedOut: () => boolean\n /** Clear the timer and the caller listener; always called in a `finally`. */\n dispose: () => void\n}\n\n/**\n * Combine the caller's signal with a timeout, keeping the two distinguishable:\n * a timeout is this client's own budget expiring (the guard delegates to the\n * user) while a caller abort means the approval was already withdrawn (answer\n * nothing) — both fail closed, but the diagnosis must not lie about which.\n *\n * The timer is a plain `setTimeout` rather than `AbortSignal.timeout()`, whose\n * timer Node unrefs: with nothing else pending (a test double, a socket that\n * never opened) an unref'd timer lets the process exit while the promise is\n * still pending, which reads as a hang rather than as the timeout it is.\n */\nfunction deadlineOf(signal: AbortSignal | undefined, timeoutMs: number): SystemOneDeadline {\n const controller = new AbortController()\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort()\n }, timeoutMs)\n const onCallerAbort = (): void => controller.abort()\n if (signal !== undefined) {\n if (signal.aborted) controller.abort()\n else signal.addEventListener('abort', onCallerAbort, { once: true })\n }\n return {\n signal: controller.signal,\n callerAborted: () => signal?.aborted === true,\n timedOut: () => timedOut,\n dispose: () => {\n clearTimeout(timer)\n signal?.removeEventListener('abort', onCallerAbort)\n },\n }\n}\n\n/** Whether a caught value is an abort-shaped failure. */\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')\n}\n\n/** Stop waiting for an operation that does not accept an AbortSignal. */\nfunction withinDeadline<T>(operation: Promise<T>, deadline: SystemOneDeadline, timeoutMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => {\n reject(deadline.callerAborted()\n ? new SystemOneError('decision request aborted', 'aborted')\n : new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout'))\n }\n deadline.signal.addEventListener('abort', onAbort, { once: true })\n operation.then(\n (value) => {\n deadline.signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error) => {\n deadline.signal.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n if (deadline.signal.aborted) onAbort()\n })\n}\n\n/** A finite number in `[0, 1]`, or undefined. */\nfunction probability(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1 ? value : undefined\n}\n\n/** A finite number, or undefined. */\nfunction finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\n/** A record of finite numbers (probabilities), or undefined when the shape is off. */\nfunction numberRecord(value: unknown): Readonly<Record<string, number>> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const out: Record<string, number> = {}\n for (const [key, entry] of Object.entries(value)) {\n const parsed = finite(entry)\n if (parsed === undefined) return undefined\n out[key] = parsed\n }\n return out\n}\n\n/**\n * Parse one answer entry strictly by its own `type`. A body whose answer does\n * not carry the member its type promises is rejected rather than defaulted:\n * an absent probability is exactly the case the caller must not read as \"safe\".\n *\n * @param value - one raw entry from the response's `answers` object.\n * @returns the parsed answer, or undefined when the entry is malformed.\n */\nexport function parseSystemOneAnswer(value: unknown): SystemOneAnswer | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const raw = value as Record<string, unknown>\n if (raw.type === 'noul') {\n const noul = probability(raw.noul)\n return noul === undefined ? undefined : { type: 'noul', noul }\n }\n if (raw.type === 'choice') {\n if (typeof raw.choice !== 'string' || raw.choice === '') return undefined\n const confidence = raw.confidence === undefined ? undefined : probability(raw.confidence)\n if (raw.confidence !== undefined && confidence === undefined) return undefined\n const probabilities = raw.probabilities === undefined ? undefined : numberRecord(raw.probabilities)\n if (raw.probabilities !== undefined && probabilities === undefined) return undefined\n return {\n type: 'choice',\n choice: raw.choice,\n ...(confidence === undefined ? {} : { confidence }),\n ...(probabilities === undefined ? {} : { probabilities }),\n }\n }\n if (raw.type === 'score') {\n const score = finite(raw.score)\n if (score === undefined) return undefined\n const confidence = raw.confidence === undefined ? undefined : probability(raw.confidence)\n if (raw.confidence !== undefined && confidence === undefined) return undefined\n const probabilities = raw.probabilities === undefined ? undefined : numberRecord(raw.probabilities)\n if (raw.probabilities !== undefined && probabilities === undefined) return undefined\n return {\n type: 'score',\n score,\n ...(confidence === undefined ? {} : { confidence }),\n ...(probabilities === undefined ? {} : { probabilities }),\n }\n }\n return undefined\n}\n\n/**\n * Parse a decision response body. Every answer entry must be well formed — one\n * malformed entry fails the whole response, because a partially understood\n * decision is not a decision. Unknown extra members are ignored so a server-side\n * addition cannot break the guard.\n *\n * @param value - the decoded JSON body.\n * @returns the parsed response, or undefined when the body is not one.\n */\nexport function parseSystemOneResponse(value: unknown): SystemOneResponse | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const raw = value as Record<string, unknown>\n const rawAnswers = raw.answers\n if (typeof rawAnswers !== 'object' || rawAnswers === null || Array.isArray(rawAnswers)) return undefined\n const entries = Object.entries(rawAnswers)\n if (entries.length === 0) return undefined\n const answers: Record<string, SystemOneAnswer> = {}\n for (const [id, entry] of entries) {\n const answer = parseSystemOneAnswer(entry)\n if (answer === undefined) return undefined\n answers[id] = answer\n }\n const usage = raw.usage === undefined ? undefined : parseUsage(raw.usage)\n if (raw.usage !== undefined && usage === undefined) return undefined\n return {\n ...(typeof raw.model === 'string' ? { model: raw.model } : {}),\n answers,\n ...(usage === undefined ? {} : { usage }),\n }\n}\n\n/** Parse the optional `usage` member; an unreadable one is a malformed body. */\nfunction parseUsage(value: unknown): SystemOneUsage | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const raw = value as Record<string, unknown>\n const inputTokens = raw.input_tokens === undefined ? undefined : finite(raw.input_tokens)\n if (raw.input_tokens !== undefined && inputTokens === undefined) return undefined\n const outputTokens = raw.output_tokens === undefined ? undefined : finite(raw.output_tokens)\n if (raw.output_tokens !== undefined && outputTokens === undefined) return undefined\n return {\n ...(inputTokens === undefined ? {} : { inputTokens }),\n ...(outputTokens === undefined ? {} : { outputTokens }),\n }\n}\n\n/** Validate the outgoing request where the server would only reject it with a 400. */\nfunction assertRequest(request: SystemOneRequest): void {\n const ids = Object.keys(request.questions)\n if (ids.length === 0) throw new SystemOneError('a decision request needs at least one question', 'invalid-request')\n if (ids.length > SYSTEMONE_MAX_QUESTIONS) {\n throw new SystemOneError(\n `a decision request carries at most ${SYSTEMONE_MAX_QUESTIONS} questions (got ${ids.length})`,\n 'invalid-request',\n )\n }\n for (const id of ids) {\n if (id.trim() === '') throw new SystemOneError('every decision question needs a non-empty id', 'invalid-request')\n }\n}\n\n/** Read the endpoint's error body into a one-line diagnosis. */\nasync function httpFailure(response: Response): Promise<SystemOneError> {\n let detail = ''\n try {\n const text = await response.text()\n const slice = text.trim().slice(0, 200)\n if (slice !== '') detail = `: ${slice}`\n } catch {\n // A body that cannot be read adds nothing; the status is the diagnosis.\n }\n return new SystemOneError(\n `Command Code decision request failed (HTTP ${response.status})${detail}`,\n 'http',\n response.status,\n )\n}\n\n/**\n * Run one decision request.\n *\n * @param deps - connection facts, credential chain and fetch seam.\n * @param request - the state and typed questions.\n * @param options - caller cancellation and the per-call budget.\n * @returns the parsed decision.\n * @throws {SystemOneError} on every failure path; callers fail closed.\n */\nexport async function runSystemOne(\n deps: SystemOneDeps,\n request: SystemOneRequest,\n options: { signal?: AbortSignal; timeoutMs?: number } = {},\n): Promise<SystemOneResponse> {\n assertRequest(request)\n const apiBase = deps.apiBase()\n if (!URL.canParse(apiBase)) {\n throw new SystemOneError(\n `Command Code decision request is misconfigured: apiBase ${JSON.stringify(apiBase)} is not a valid URL`,\n 'invalid-request',\n )\n }\n if (options.signal?.aborted === true) throw new SystemOneError('decision request aborted', 'aborted')\n const timeoutMs = options.timeoutMs ?? SYSTEMONE_DEFAULT_TIMEOUT_MS\n const deadline = deadlineOf(options.signal, timeoutMs)\n try {\n let key: string\n try {\n key = await withinDeadline(Promise.resolve().then(() => deps.resolveApiKey()), deadline, timeoutMs)\n } catch (error) {\n if (error instanceof SystemOneError && (error.kind === 'aborted' || error.kind === 'timeout')) throw error\n throw new SystemOneError(\n `Command Code decision request has no usable credential: ${error instanceof Error ? error.message : String(error)}`,\n 'credential',\n undefined,\n { cause: error },\n )\n }\n\n const body = {\n model: request.model ?? SYSTEMONE_MODEL,\n state: request.state,\n questions: request.questions,\n }\n\n // The credential chain can take a moment (the pool may probe a window), and\n // the caller may withdraw — or the budget may expire — while it runs. Re-check\n // before opening the connection: a real fetch would reject an aborted signal\n // on its own, but the diagnosis belongs to this client, and a deployment with\n // its own transport must not have to re-derive it.\n if (deadline.signal.aborted) {\n throw deadline.callerAborted()\n ? new SystemOneError('decision request aborted', 'aborted')\n : new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout')\n }\n\n let response: Response\n try {\n response = await (deps.fetchImpl ?? fetch)(`${apiBase.replace(/\\/$/, '')}${SYSTEMONE_ROUTE}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n signal: deadline.signal,\n })\n } catch (error) {\n if (deadline.callerAborted()) throw new SystemOneError('decision request aborted', 'aborted', undefined, { cause: error })\n if (deadline.timedOut() || isAbortError(error)) {\n throw new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout', undefined, { cause: error })\n }\n throw new SystemOneError(\n `Command Code decision request failed: ${error instanceof Error ? error.message : String(error)}`,\n 'network',\n undefined,\n { cause: error },\n )\n }\n\n if (!response.ok) throw await httpFailure(response)\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch (error) {\n if (deadline.callerAborted()) throw new SystemOneError('decision request aborted', 'aborted', undefined, { cause: error })\n throw new SystemOneError('Command Code returned an unparseable decision body', 'invalid-response', undefined, { cause: error })\n }\n const parsed = parseSystemOneResponse(payload)\n if (parsed === undefined) {\n throw new SystemOneError('Command Code returned a decision body this plugin cannot read', 'invalid-response')\n }\n return parsed\n } finally {\n // Always: a live timeout timer would otherwise hold the process open, and a\n // caller listener would outlive the request it belongs to.\n deadline.dispose()\n }\n}\n","/**\n * The command guard: an AI second opinion on shell approvals.\n *\n * dsh already decides *that* a tool call needs approval (permission presets, the\n * sandbox's escalation path, `PreToolUse` hooks) and then asks the user. This\n * module inserts one answerer in front of the human: the Command Code decision\n * model `typesafe/jev` (see `./systemone.ts`) is asked whether the command is\n * safe to run without asking, and only a confident *yes* turns into a one-shot\n * `allowed-once` grant. A sandbox escalation is judged as a separate, explicit\n * decision: JEV must confirm both that the wider access has a narrow purpose and\n * that it is necessary, rather than treating a sandbox string as a harmless\n * detail. Everything else — a lower probability, a malformed answer, a timeout,\n * a rate limit, a missing key, a command we refuse to judge — delegates to the\n * next answerer with `next()`, which is the human.\n *\n * Why this seam and not the decision one: `approval/request` fires only after a\n * policy already decided to ask, so a grant here can never widen a policy (a\n * session under the strict `never` policy rejects before any answerer runs) and\n * never has to re-implement one. The same waterfall is what the browser's\n * approval panel answers through, so the guard must be registered with\n * `prepend: true` — otherwise that panel holds the request until the user\n * clicks and this answerer never runs at all.\n *\n * The approval payload carries only a `callId`, no arguments, so the command\n * text comes from a transparent observer on `tools/pre-execute` (which the tool\n * runtime dispatches for every execution, immediately before it resolves the\n * very ask we are answering). The observer always returns `next()`: it can\n * never change a decision, it only remembers what the call was.\n *\n * Fail-closed rules, in order, each of which delegates to the human:\n *\n * 1. the feature is off (the default);\n * 2. the ask is not about a shell tool, or we never saw its arguments;\n * 3. the command matches the hard denylist — those are never even sent to the\n * model;\n * 4. the command is too long to judge in full (a truncated state would invite a\n * verdict on a command the model did not see);\n * 5. a sandbox escalation lacks either explicit scope or necessity support;\n * 6. the decision call fails for any reason (timeout, HTTP, credential,\n * network, unreadable body);\n * 7. the primary probability or either escalation probability is below the\n * configured threshold.\n *\n * The model is billed per request ($0.042/1M input tokens once the free window\n * ends on 2026-09-24) and the endpoint has no ZDR upstream (its requests never\n * carry the `x-cmd-zdr` header the chat transports may send under `Config.zdr`),\n * so the decision is only ever asked about commands a policy already wanted a\n * human to look at, and identical decision contexts within one agent reuse\n * one result from an in-memory memo.\n *\n * @module dsh-commandcode-provider/command-guard\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n type SystemOneQuestion,\n type SystemOneRequest,\n type SystemOneResponse,\n} from './systemone.ts'\n\n/** Tool names whose `arguments.command` this guard judges. */\nexport const COMMAND_GUARD_SHELL_TOOLS: readonly string[] = ['bash', 'pwsh']\n\n/** Question id the primary safety verdict is keyed by. */\nexport const COMMAND_GUARD_QUESTION_ID = 'safe'\n\n/** Question id for the narrow-purpose part of a sandbox escalation. */\nexport const COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID = 'escalation_scope'\n\n/** Question id for the necessity/proportionality part of a sandbox escalation. */\nexport const COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID = 'escalation_necessity'\n\n/**\n * The auto-approve strictness a user picks (`Config.commandGuardLevel`). Each\n * level is the probability every verdict must reach before the guard grants\n * `allowed-once`; a higher level approves less, on stronger evidence. Three\n * presets replace a free-form probability because the useful range is narrow\n * and a hand-typed 0.6 silently turns the guard into a rubber stamp.\n */\nexport type CommandGuardLevel = 'high' | 'medium' | 'low'\n\n/** The selectable levels, strictest first (the order the settings surfaces list them in). */\nexport const COMMAND_GUARD_LEVELS: readonly CommandGuardLevel[] = ['high', 'medium', 'low']\n\n/** Each level's probability threshold. */\nexport const COMMAND_GUARD_LEVEL_THRESHOLDS: Readonly<Record<CommandGuardLevel, number>> = {\n high: 0.95,\n medium: 0.9,\n low: 0.8,\n}\n\n/** The level an unset config reads as. */\nexport const COMMAND_GUARD_DEFAULT_LEVEL: CommandGuardLevel = 'medium'\n\n/** Probability of \"safe\" at or above which the guard grants `allowed-once` by default. */\nexport const COMMAND_GUARD_DEFAULT_THRESHOLD = COMMAND_GUARD_LEVEL_THRESHOLDS[COMMAND_GUARD_DEFAULT_LEVEL]\n\n/** The threshold for a stored level; anything unrecognized reads as the default level. */\nexport function commandGuardThreshold(level: unknown): number {\n return typeof level === 'string' && Object.hasOwn(COMMAND_GUARD_LEVEL_THRESHOLDS, level)\n ? COMMAND_GUARD_LEVEL_THRESHOLDS[level as CommandGuardLevel]\n : COMMAND_GUARD_DEFAULT_THRESHOLD\n}\n\n/**\n * Decision budget; the approval prompt must not wait longer than this. Fixed\n * rather than configurable: it only bounds how long a late verdict can delay\n * the prompt, and every failure (a timeout included) already falls back to\n * asking the user, so there is nothing for a user to tune. 3 s leaves room for\n * credential resolution plus one decision round trip on a slow link.\n */\nexport const COMMAND_GUARD_TIMEOUT_MS = 3000\n\n/**\n * Longest command the guard will send for judgement. A longer one is delegated\n * instead of truncated: a verdict on the first N characters of a command is a\n * verdict on a different command.\n */\nexport const COMMAND_GUARD_MAX_COMMAND_CHARS = 6000\n\n/** Executions remembered for their arguments, and decisions memoized. */\nexport const COMMAND_GUARD_CACHE_ENTRIES = 64\n\n/** How long one command's decision may be reused. */\nexport const COMMAND_GUARD_DECISION_TTL_MS = 10 * 60_000\n\n/** The resolved settings the guard reads per ask. */\nexport interface CommandGuardSettings {\n /** Master switch; the shipped default is off. */\n readonly enabled: boolean\n /** Minimum probability of \"safe\" that grants `allowed-once`. */\n readonly threshold: number\n /** Decision budget in milliseconds. */\n readonly timeoutMs: number\n}\n\n/**\n * Hard denylist: commands the guard never auto-approves, and never even sends\n * for judgement. Each entry is a deliberate, narrow reading of one destructive\n * family — the goal is not to classify every dangerous command (that is the\n * model's job) but to make sure the classics cannot be talked into a grant by a\n * persuasive-looking command string.\n *\n * Every pattern is allowed to OVER-match: a false positive costs one ordinary\n * human prompt, while a false negative would hand a destructive command to a\n * model that has to guess. That asymmetry is why `sudo` is matched anywhere in\n * the line rather than only in command position, and why `fdisk` is listed even\n * though `fdisk -l` only lists partitions.\n */\nexport const COMMAND_GUARD_DENY_LIST: readonly { readonly id: string; readonly pattern: RegExp }[] = [\n // Recursive force-delete of a root-ish, home, cwd or wildcard target.\n // Deleting a plain project-relative path is deliberately NOT here: that is a\n // normal operation the model is allowed to judge.\n {\n id: 'rm-root',\n pattern: /\\brm\\s+(?:-[a-zA-Z]*[rR][a-zA-Z]*f[a-zA-Z]*|-[a-zA-Z]*f[a-zA-Z]*[rR][a-zA-Z]*|--recursive[^\\n]*--force|--force[^\\n]*--recursive)\\s+(?:\\/|\\/\\*|~|~\\/\\*|\\$HOME(?:\\/\\*)?|\\*|\\.\\/\\*|\\.)(?:\\s|$)/,\n },\n { id: 'rm-home', pattern: /\\brm\\s+-[a-zA-Z]*[rR][a-zA-Z]*\\s+(?:~|\\$HOME)\\// },\n // Disk and filesystem primitives.\n { id: 'filesystem-write', pattern: /\\b(?:mkfs(?:\\.\\w+)?|wipefs|fdisk|parted|shred)\\b/ },\n { id: 'raw-device-write', pattern: /\\bdd\\b[^\\n]*\\bof=\\/dev\\// },\n { id: 'device-redirect', pattern: />{1,2}\\s*\\/dev\\/(?:sd|disk|nvme|hd)/ },\n { id: 'fork-bomb', pattern: /:\\s*\\(\\s*\\)\\s*\\{\\s*:\\s*\\|\\s*:\\s*&\\s*\\}\\s*;\\s*:/ },\n // Privilege and ownership.\n { id: 'privilege-escalation', pattern: /\\b(?:sudo|doas)\\b/ },\n { id: 'su', pattern: /\\bsu\\s/ },\n { id: 'chmod-world-write', pattern: /\\bchmod\\b[^\\n]*\\b(?:777|a\\+w|o\\+w)\\b/ },\n { id: 'chown-root', pattern: /\\bchown\\b[^\\n]*\\b(?:root|0):/ },\n // Git history, remote state and discarded work.\n { id: 'git-push', pattern: /\\bgit\\s+push\\b/ },\n { id: 'git-history-rewrite', pattern: /\\bgit\\s+(?:filter-branch|filter-repo)\\b/ },\n { id: 'git-hard-reset', pattern: /\\bgit\\s+reset\\s+--hard\\b/ },\n { id: 'git-clean-force', pattern: /\\bgit\\s+clean\\b[^\\n]*\\s-[a-zA-Z]*f/ },\n { id: 'git-discard-worktree', pattern: /\\bgit\\s+(?:checkout|restore)\\s+(?:--\\s+)?\\.(?:\\s|$)/ },\n { id: 'git-stash-drop', pattern: /\\bgit\\s+stash\\s+(?:drop|clear)\\b/ },\n // Publishing and uploading.\n { id: 'publish', pattern: /\\b(?:npm|pnpm|yarn|bun)\\s+publish\\b/ },\n { id: 'release-upload', pattern: /\\b(?:gh\\s+release|twine\\s+upload)\\b/ },\n { id: 'docker-push', pattern: /\\bdocker\\s+push\\b/ },\n { id: 'cloud-upload', pattern: /\\b(?:aws\\s+s3|gsutil|gcloud\\s+storage|az\\s+storage)\\b[^\\n]*\\b(?:cp|sync|mv|rm|rb)\\b/ },\n { id: 'remote-copy', pattern: /\\b(?:scp|rsync)\\b[^\\n]*(?::|@)/ },\n // A download piped straight into an interpreter.\n { id: 'pipe-to-shell', pattern: /\\b(?:curl|wget|fetch)\\b[^\\n|]*\\|\\s*(?:sudo\\s+)?(?:sh|bash|zsh|dash|ksh|python\\d*|node|ruby|perl)\\b/ },\n // Machine state and process control.\n { id: 'power', pattern: /\\b(?:shutdown|reboot|halt|poweroff)\\b/ },\n { id: 'kill-everything', pattern: /\\bkill\\s+(?:-9\\s+)?-1\\b|\\b(?:killall|pkill)\\s+-9\\b/ },\n // Credentials and shell history.\n {\n id: 'credential-write',\n pattern: /(?:>{1,2}|tee|cp|mv|rm|chmod|chown)\\s[^\\n]*(?:\\.ssh\\b|\\.aws\\b|\\.gnupg\\b|\\.commandcode\\/auth\\.json|id_rsa|id_ed25519)/,\n },\n { id: 'history-clear', pattern: /\\bhistory\\s+-c\\b|\\bunset\\s+HISTFILE\\b/ },\n // System and language-level installs (they run third-party code installers).\n { id: 'global-install', pattern: /\\b(?:npm|pnpm|yarn|bun)\\s+(?:i|install|add)\\s+(?:-g\\b|--global\\b)/ },\n { id: 'system-install', pattern: /\\b(?:apt|apt-get|dnf|yum|zypper|apk|pacman|brew)\\s+(?:install|remove|purge|uninstall|upgrade)\\b/ },\n { id: 'language-install', pattern: /\\b(?:pip3?|pipx|gem|cargo)\\s+(?:install|add)\\b/ },\n]\n\n/**\n * Why the guard refuses to judge a command, when it does.\n *\n * @param command - the raw command text.\n * @returns the matching denylist id, or undefined.\n */\nexport function denyReasonOf(command: string): string | undefined {\n for (const entry of COMMAND_GUARD_DENY_LIST) {\n if (entry.pattern.test(command)) return entry.id\n }\n return undefined\n}\n\n/** One shell command awaiting approval, as read from its tool execution. */\nexport interface ShellCommandFact {\n /** Tool name (`bash` / `pwsh`). */\n readonly tool: string\n /** The command itself. */\n readonly command: string\n /** The agent's own one-line description, when it wrote one. */\n readonly description?: string\n /** The call's working directory, when it named one. */\n readonly workdir?: string\n /** The wider sandbox mode this call asks for, when it is an escalation retry. */\n readonly sandboxPermissions?: string\n /** The asker's own explanation of why approval is needed. */\n readonly reason?: string\n}\n\n/** A non-empty string member, or undefined. */\nfunction stringMember(value: unknown, key: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const member = (value as Record<string, unknown>)[key]\n return typeof member === 'string' && member.trim() !== '' ? member : undefined\n}\n\n/**\n * Read a shell command out of a tool execution, or undefined when this call is\n * not one the guard judges (a different tool, or arguments without a command).\n *\n * @param name - the executed tool's name.\n * @param args - the execution's parsed `arguments`.\n * @returns the fact to judge, without the asker's reason (that arrives later).\n */\nexport function shellCommandOf(name: string, args: unknown): Omit<ShellCommandFact, 'reason'> | undefined {\n if (!COMMAND_GUARD_SHELL_TOOLS.includes(name)) return undefined\n const command = stringMember(args, 'command')\n if (command === undefined) return undefined\n const description = stringMember(args, 'description')\n const workdir = stringMember(args, 'workdir')\n const sandboxPermissions = stringMember(args, 'sandbox_permissions')\n return {\n tool: name,\n command,\n ...(description === undefined ? {} : { description }),\n ...(workdir === undefined ? {} : { workdir }),\n ...(sandboxPermissions === undefined ? {} : { sandboxPermissions }),\n }\n}\n\n/**\n * Build the decision request for one command.\n *\n * A normal approval asks one question. A call that explicitly requests a wider\n * sandbox gets the same safety question plus two veto questions. This keeps the\n * common case cheap while making the broader permission change an explicit\n * decision: JEV must agree that the extra access has a narrow purpose and is\n * necessary, not merely that the command text looks familiar.\n *\n * The agent's own `description` and the harness's `reason` are included as\n * context, but the criteria say the command text itself decides — a\n * model-written description is a claim, not evidence.\n *\n * @param fact - the command and its context.\n * @returns the request to send.\n */\nexport function buildSafetyRequest(fact: ShellCommandFact): SystemOneRequest {\n const escalated = fact.sandboxPermissions !== undefined\n const lines = [\n `Tool: ${fact.tool}`,\n 'Command:',\n fact.command,\n ...(fact.description === undefined ? [] : ['', `The agent describes this command as: ${fact.description}`]),\n ...(fact.workdir === undefined ? [] : ['', `Working directory: ${fact.workdir}`]),\n ...(fact.sandboxPermissions === undefined\n ? []\n : ['', `The harness is asking because this call requests a wider sandbox mode (${fact.sandboxPermissions}) than the one currently in force.`]),\n ...(fact.reason === undefined ? [] : ['', `The asker's reason for needing approval: ${fact.reason}`]),\n ]\n const question: SystemOneQuestion = {\n type: 'noul',\n instructions: escalated\n ? 'Is it safe to run this command right now WITHOUT asking the user first, including the requested sandbox escalation? Judge the command text itself; a description or stated reason is only a claim about it.'\n : 'Is it safe to run this command right now WITHOUT asking the user first? Judge the command text itself; a description is only a claim about it.',\n criteria: {\n true: escalated\n ? 'A normal, non-obfuscated read, build, or test operation whose outside-workspace effects are limited to conventional build/dependency caches or temporary files and are easily reversible: no unrelated user or system data is accessed, no data leaves the machine, and no credentials, git history or remote state are touched.'\n : 'Read-only, or its effects stay inside the current project and are trivially reversible: no data leaves the machine, nothing outside the project is modified, and no credentials, git history or remote state are touched.',\n false: 'Anything else. Broad or unrelated outside-workspace access, deleting or overwriting files outside the project, rewriting or publishing git history, uploading data anywhere, installing system or global packages, changing permissions, ownership or credentials, killing processes, running as another user or as root, piping a download into a shell, or a command obfuscated enough that its effect cannot be read.',\n },\n }\n const questions: Record<string, SystemOneQuestion> = {\n [COMMAND_GUARD_QUESTION_ID]: question,\n }\n if (escalated) {\n questions[COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID] = {\n type: 'noul',\n instructions: 'Is the requested wider sandbox access limited to a narrow, conventional purpose supported by this command, such as a build cache, dependency cache, or temporary directory, rather than unrelated user files, credentials, other projects, or the network?',\n criteria: {\n true: 'The wider access is plausibly limited to conventional local build/dependency caches or temporary files required by the command, with no unrelated host data or remote transfer in scope.',\n false: 'The command needs broad or unrelated host access, cannot establish a narrow purpose, or would use the wider permission to reach credentials, other projects, user files, or the network.',\n },\n }\n questions[COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID] = {\n type: 'noul',\n instructions: 'Is the requested sandbox escalation necessary and proportionate for this one command, rather than broader than the command needs? Treat the stated reason as a claim to check against the command, not as proof.',\n criteria: {\n true: 'The command and its stated purpose support a one-shot escalation that is needed for the task and is no broader than the requested effect requires.',\n false: 'The wider mode is unnecessary, broader than needed, unsupported by the command, or the command is too ambiguous to justify the extra authority.',\n },\n }\n }\n return {\n state: lines.join('\\n'),\n questions,\n }\n}\n\n/**\n * Read a probability out of a decision response.\n *\n * @param response - the parsed response.\n * @param questionId - the question id to read (defaults to the guard's own).\n * @returns the probability, or undefined when the answer is missing or is not\n * a `noul` verdict.\n */\nexport function safeProbabilityOf(\n response: SystemOneResponse,\n questionId: string = COMMAND_GUARD_QUESTION_ID,\n): number | undefined {\n const answer = response.answers[questionId]\n return answer !== undefined && answer.type === 'noul' ? answer.noul : undefined\n}\n\n/** The subset of a tool execution this guard reads. */\nexport interface GuardToolExecution {\n readonly callId: string\n readonly name: string\n readonly arguments: unknown\n readonly agent?: object\n}\n\n/** The subset of an approval request this guard reads. */\nexport interface GuardApprovalRequest {\n readonly toolName: string\n readonly callId?: string\n readonly reason?: string\n readonly signal?: AbortSignal\n readonly agent?: object\n}\n\n/** The approval vocabulary, from the harness's own closed set. */\nexport type GuardApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'\n\n/** What one ask resolved to, for logging and tests. */\nexport type CommandGuardVerdict =\n /** A confident \"safe\" — the caller grants `allowed-once`. */\n | {\n readonly kind: 'approve'\n readonly probability: number\n readonly source: 'model' | 'memo'\n /** The two explicit sandbox-escalation guard probabilities, when applicable. */\n readonly escalation?: {\n readonly scope: number\n readonly necessity: number\n }\n /** One-line excerpt of the command, for the audit log. */\n readonly command?: string\n }\n /** Delegate to the next answerer (the human). */\n | {\n readonly kind: 'delegate'\n readonly reason: string\n readonly probability?: number\n /** One-line excerpt of the command, when the guard got far enough to know it. */\n readonly command?: string\n }\n\n/**\n * One-line, length-bounded excerpt of a command for the log. The full text is\n * already in the session's tool call and was already sent to the decision\n * endpoint, so this adds no exposure — it is what makes \"why did this run\n * without asking?\" answerable from the log alone.\n */\nexport function commandExcerpt(command: string, limit = 160): string {\n const flat = command.replace(/\\s+/g, ' ').trim()\n return flat.length <= limit ? flat : `${flat.slice(0, limit - 1)}…`\n}\n\n/** Everything the guard needs beyond the two listeners. */\nexport interface CommandGuardDeps {\n /** Live settings, re-read per ask so a settings write lands on the next one. */\n settings: () => CommandGuardSettings\n /**\n * Run one decision. The binding owns the connection facts and the API key;\n * the guard owns the request and passes its own budget and cancellation.\n */\n decide: (\n request: SystemOneRequest,\n options: { signal?: AbortSignal; timeoutMs: number },\n ) => Promise<SystemOneResponse>\n /** Clock (tests). Defaults to `Date.now`. */\n now?: () => number\n /** One-line decision log (the harness logger, in the plugin entry). */\n log?: (message: string) => void\n}\n\n/** A memoized decision for one exact command. */\ninterface MemoEntry {\n readonly probability: number\n /** The two extra probabilities required by a sandbox escalation. */\n readonly escalation?: {\n readonly scope: number\n readonly necessity: number\n }\n readonly at: number\n}\n\ninterface ObservedExecution {\n readonly fact: Omit<ShellCommandFact, 'reason'>\n readonly agent: object | undefined\n}\n\n/**\n * The guard's stateful half: what was executed (by call id) and what has\n * already been decided (by agent and complete decision context), both bounded.\n *\n * The execution cache is the bridge between the two seams — `tools/pre-execute`\n * knows the arguments, `approval/request` knows the call id — and it is keyed by\n * call id with an agent-identity check when read: an entry for an execution\n * that never asked is never read, so there is nothing to clean up on the result\n * side (and the ask happens before the result anyway).\n */\nexport class CommandGuard {\n private readonly executions = new Map<string, ObservedExecution>()\n private decisions = new WeakMap<object, Map<string, MemoEntry>>()\n\n constructor(private readonly deps: CommandGuardDeps) {}\n\n /**\n * Remember one execution's command. Never throws, never changes a decision.\n *\n * @param execution - the execution about to run.\n */\n noteExecution(execution: GuardToolExecution): void {\n const callId = execution?.callId\n if (typeof callId !== 'string' || callId === '') return\n const fact = shellCommandOf(execution.name, execution.arguments)\n if (fact === undefined) return\n this.executions.delete(callId)\n this.executions.set(callId, { fact, agent: execution.agent })\n while (this.executions.size > COMMAND_GUARD_CACHE_ENTRIES) {\n const oldest = this.executions.keys().next()\n if (oldest.done === true) break\n this.executions.delete(oldest.value)\n }\n }\n\n /** Forget every remembered execution and decision (disposal, tests). */\n clear(): void {\n this.executions.clear()\n this.decisions = new WeakMap()\n }\n\n /**\n * Judge one approval request.\n *\n * @param request - the pending approval.\n * @returns the verdict; `approve` is the only outcome that grants anything.\n */\n async judge(request: GuardApprovalRequest): Promise<CommandGuardVerdict> {\n const settings = this.deps.settings()\n if (!settings.enabled) return { kind: 'delegate', reason: 'guard disabled' }\n const callId = request.callId\n if (callId === undefined) return { kind: 'delegate', reason: 'approval carries no call id' }\n const observed = this.executions.get(callId)\n if (observed === undefined || observed.agent !== request.agent) {\n return { kind: 'delegate', reason: 'the guard never saw this call for this agent' }\n }\n const fact = observed.fact\n const excerpt = commandExcerpt(fact.command)\n if (!COMMAND_GUARD_SHELL_TOOLS.includes(request.toolName)) {\n return { kind: 'delegate', reason: `not a shell tool (${request.toolName})` }\n }\n if (fact.command.length > COMMAND_GUARD_MAX_COMMAND_CHARS) {\n return {\n kind: 'delegate',\n reason: `command longer than ${COMMAND_GUARD_MAX_COMMAND_CHARS} characters`,\n command: excerpt,\n }\n }\n const denied = denyReasonOf(fact.command)\n if (denied !== undefined) {\n return { kind: 'delegate', reason: `denylisted command (${denied})`, command: excerpt }\n }\n\n const full: ShellCommandFact = {\n ...fact,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n }\n // Only an agent-scoped, identical decision state may reuse a verdict.\n // The same relative command can have different effects in another working\n // directory or sandbox mode; the asker's reason also changes the question.\n const memoKey = JSON.stringify(full)\n const now = this.deps.now?.() ?? Date.now()\n const agentDecisions = request.agent === undefined ? undefined : this.decisions.get(request.agent)\n const memo = agentDecisions?.get(memoKey)\n if (memo !== undefined) {\n if (now - memo.at < COMMAND_GUARD_DECISION_TTL_MS) {\n return this.verdict(memo, settings.threshold, 'memo', excerpt, full.sandboxPermissions !== undefined)\n }\n agentDecisions?.delete(memoKey)\n }\n\n let response: SystemOneResponse\n try {\n response = await this.deps.decide(buildSafetyRequest(full), {\n ...(request.signal === undefined ? {} : { signal: request.signal }),\n timeoutMs: settings.timeoutMs,\n })\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n return { kind: 'delegate', reason: `decision unavailable: ${detail}`, command: excerpt }\n }\n const probability = safeProbabilityOf(response)\n if (probability === undefined) {\n return { kind: 'delegate', reason: 'the decision carried no safe verdict', command: excerpt }\n }\n let escalation: { readonly scope: number; readonly necessity: number } | undefined\n if (full.sandboxPermissions !== undefined) {\n const scope = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID)\n const necessity = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID)\n if (scope === undefined || necessity === undefined) {\n return {\n kind: 'delegate',\n reason: 'the decision carried no complete sandbox-escalation verdict',\n command: excerpt,\n }\n }\n escalation = { scope, necessity }\n }\n const memoEntry: MemoEntry = {\n probability,\n ...(escalation === undefined ? {} : { escalation }),\n at: now,\n }\n\n if (request.agent !== undefined) {\n const decisions = agentDecisions ?? new Map<string, MemoEntry>()\n decisions.set(memoKey, memoEntry)\n while (decisions.size > COMMAND_GUARD_CACHE_ENTRIES) {\n const oldest = decisions.keys().next()\n if (oldest.done === true) break\n decisions.delete(oldest.value)\n }\n this.decisions.set(request.agent, decisions)\n }\n return this.verdict(memoEntry, settings.threshold, 'model', excerpt, full.sandboxPermissions !== undefined)\n }\n\n /** Apply the threshold to the primary verdict and any escalation vetoes. */\n private verdict(\n entry: MemoEntry,\n threshold: number,\n source: 'model' | 'memo',\n command: string,\n escalated: boolean,\n ): CommandGuardVerdict {\n if (entry.probability < threshold) {\n return {\n kind: 'delegate',\n reason: `safe probability ${entry.probability.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n if (!escalated) {\n return { kind: 'approve', probability: entry.probability, source, command }\n }\n if (entry.escalation === undefined) {\n return { kind: 'delegate', reason: 'the cached sandbox-escalation verdict was incomplete', command }\n }\n if (entry.escalation.scope < threshold) {\n return {\n kind: 'delegate',\n reason: `sandbox scope probability ${entry.escalation.scope.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n if (entry.escalation.necessity < threshold) {\n return {\n kind: 'delegate',\n reason: `sandbox necessity probability ${entry.escalation.necessity.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n return {\n kind: 'approve',\n probability: entry.probability,\n source,\n ...(entry.escalation === undefined ? {} : { escalation: entry.escalation }),\n command,\n }\n }\n}\n\n/** The two listeners this module registers, typed structurally. */\ninterface CommandGuardEvents {\n on(\n event: 'tools/pre-execute',\n listener: (execution: GuardToolExecution, next: () => Promise<unknown>) => unknown,\n options?: { prepend?: boolean },\n ): unknown\n on(\n event: 'approval/request',\n listener: (\n request: GuardApprovalRequest,\n next: () => Promise<GuardApprovalOutcome>,\n ) => Promise<GuardApprovalOutcome> | GuardApprovalOutcome,\n options?: { prepend?: boolean },\n ): unknown\n}\n\n/**\n * Register the guard on a context that has the approval seam.\n *\n * Call this from inside `ctx.inject(['approval'], …)`: the seam's presence is\n * what makes the feature meaningful (no approval service means no asks), and\n * tying the listeners to that injected fiber is what makes them go away with it.\n *\n * @param ctx - the injected context (or a test double with `on`).\n * @param deps - settings, the decision client, clock and logger.\n * @returns a disposer for both listeners.\n */\nexport function applyCommandGuard(ctx: Context, deps: CommandGuardDeps): () => void {\n const guard = new CommandGuard(deps)\n const events = ctx as unknown as CommandGuardEvents\n\n const offPreExecute = events.on('tools/pre-execute', (execution, next) => {\n guard.noteExecution(execution)\n return next()\n }, { prepend: true })\n\n const offApproval = events.on('approval/request', async (request, next) => {\n // The disabled path is checked here as well as inside `judge()` so that a\n // guard nobody turned on costs one config read and logs nothing: an\n // approval prompt is an ordinary event in every session, and narrating\n // \"delegated, guard disabled\" for each one would be pure noise.\n try {\n if (!deps.settings().enabled) return next()\n } catch (error) {\n deps.log?.(`command guard failed: ${error instanceof Error ? error.message : String(error)}`)\n return next()\n }\n let verdict: CommandGuardVerdict\n try {\n verdict = await guard.judge(request)\n } catch (error) {\n // The guard must never be the reason an approval fails; the human path is\n // always still there.\n deps.log?.(`command guard failed: ${error instanceof Error ? error.message : String(error)}`)\n return next()\n }\n if (verdict.kind === 'approve') {\n deps.log?.(\n `command guard auto-approved a ${request.toolName} call`\n + ` (safe probability ${verdict.probability.toFixed(3)}`\n + `${verdict.escalation === undefined\n ? ''\n : `, sandbox scope ${verdict.escalation.scope.toFixed(3)}, necessity ${verdict.escalation.necessity.toFixed(3)}`}`\n + `, ${verdict.source}): ${verdict.command ?? '(command unknown)'}`,\n )\n return 'allowed-once'\n }\n deps.log?.(\n `command guard delegated a ${request.toolName} call: ${verdict.reason}`\n + `${verdict.command === undefined ? '' : ` — ${verdict.command}`}`,\n )\n return next()\n }, { prepend: true })\n\n return () => {\n guard.clear()\n for (const off of [offPreExecute, offApproval]) {\n if (typeof off === 'function') (off as () => void)()\n }\n }\n}\n","/**\n * Volatile-config helpers for dsh 0.1.7's schema-derived profile Config.\n *\n * 0.1.7 rewrote settings around profile Config: `settings.describe()` projects\n * each active entry's schema through `volatileForm()`, so a form contains ONLY\n * fields whose schema nodes carry `meta.volatile`, and a form edit is refused\n * unless its path lies beneath a marked node. On that generation the loader\n * resolves each marked top-level field into a readonly `Volatile<T>` reference\n * (`{ get() }`, frozen, written in place by the owning runtime) instead of a\n * plain value, commits later changes WITHOUT remounting the fiber, and\n * dispatches `loader/volatile-update` to the owning fiber.\n *\n * Two helpers keep the rest of the plugin reading a PLAIN `Config`:\n *\n * - `markVolatile(schema)` applies `.volatile()`, so 0.1.7's forms see every\n * field we mark. The declared type is preserved through the mark on purpose:\n * it changes what the schema PARSES to (a live reference), not the\n * plugin-facing `Config` shape every consumer reads.\n * - `unwrapVolatileConfig(config)` reads every top-level field through its\n * reference when one is present — returning a FRESH object per call, since\n * a reference's identity is stable while its value changes — and returns the\n * config untouched when none is.\n *\n * Only TOP-LEVEL fields are marked (form writes name top-level paths such as\n * `accounts` or `modelVisibility.<id>`, whose first segment is the marked\n * node), so one unwrap level is complete. The literal `apiKey` secret stays\n * unmarked on purpose: no settings surface writes it — the settings page and\n * the dsh-TUI section both write keys through the credentials seam — so it\n * keeps composition-only semantics, and a config-file edit to it reloading the\n * fiber is the correct behavior for a secret literal.\n *\n * @module dsh-commandcode-provider/config-volatile\n */\n\n/**\n * Mark one schema field volatile.\n *\n * `.volatile()` is unconditional: the mark is a schemastery 3.18.3 feature and\n * the only engine this bundle supports (`dsh 0.1.7-rc.1`) pins `~3.18.4`, so\n * the method is always present. It is reached through a structural member\n * rather than schemastery's own typing so the function can keep the caller's\n * declared field type, which is what lets `Config` stay the plain shape every\n * consumer reads while the schema parses to live references.\n *\n * @param schema - The field schema.\n * @returns The schema carrying `meta.volatile`.\n */\nexport function markVolatile<S>(schema: S): S {\n return (schema as S & { volatile(): S }).volatile()\n}\n\n/**\n * Mark every field of a Config field dict volatile, except the named\n * composition-only secrets (`apiKey` here, which no settings surface writes).\n *\n * @param fields - Freshly built field schemas.\n * @param skip - Field names that must stay unmarked.\n * @returns The field dict with every non-skipped field marked.\n */\nexport function markVolatileFields<D extends Record<string, unknown>>(\n fields: D,\n skip: readonly string[] = [],\n): D {\n return Object.fromEntries(\n Object.entries(fields).map(([name, schema]) => [name, skip.includes(name) ? schema : markVolatile(schema)]),\n ) as D\n}\n\n/** A resolved volatile config reference: the frozen `{ get() }` cosmokit hands out. */\nexport interface VolatileRef {\n get(): unknown\n}\n\n/**\n * Whether a resolved config value is a volatile reference.\n *\n * Duck-typed on the two properties `createVolatile` produces (frozen object\n * with a `get` method) rather than cosmokit's private `write` symbol, because\n * cosmokit is not a peer of this bundle. Config values are plain parsed JSON\n * (or `!!jsExpr` wrappers), which are never frozen, so the test cannot\n * misfire on an ordinary field.\n */\nexport function isVolatileRef(value: unknown): value is VolatileRef {\n return typeof value === 'object'\n && value !== null\n && !Array.isArray(value)\n && Object.isFrozen(value)\n && typeof (value as VolatileRef).get === 'function'\n}\n\n/**\n * Read one config object as PLAIN values.\n *\n * Every top-level field found to be a volatile reference is read through\n * `.get()` — freshly on every call, so a live update lands on the very next\n * read. The loader resolves EVERY marked node into a reference, unset fields\n * included, so a loader-parsed config always yields a fresh object here; the\n * pass-through for a field that is not a reference is what keeps the unmarked\n * `apiKey` literal readable.\n */\nexport function unwrapVolatileConfig<C>(config: C): C {\n const source = config as C & Record<string, unknown>\n if (typeof source !== 'object' || source === null) return config\n const plain: Record<string, unknown> = {}\n for (const [field, value] of Object.entries(source)) {\n plain[field] = isVolatileRef(value) ? value.get() : value\n }\n return plain as C\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 plugin's live profile Config (volatile fields, unwrapped per read) and\n * the credential seam, so a changed key, endpoint, or cache path reaches the\n * next request 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 { AccountRotationReason, 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, loginCredentialRef } 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'\nimport {\n COMMAND_GUARD_DEFAULT_LEVEL,\n COMMAND_GUARD_LEVELS,\n COMMAND_GUARD_TIMEOUT_MS,\n applyCommandGuard,\n commandGuardThreshold,\n type CommandGuardLevel,\n type CommandGuardSettings,\n} from './command-guard.ts'\nimport { runSystemOne } from './systemone.ts'\nimport { markVolatileFields, unwrapVolatileConfig } from './config-volatile.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_NON_ZDR_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 supportsZeroDataRetention,\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 } 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 * Whether the Command Code decision model (`typesafe/jev`) may auto-approve\n * shell commands that dsh was about to ask about. Defaults to FALSE: the\n * guard turns a model's opinion into a one-shot approval grant, so it is\n * opt-in, and the command text (plus the agent's own description of it) is\n * sent to Command Code to judge. Only commands a policy already wanted a\n * human to look at are ever judged, and only a confident \"safe\" verdict\n * (`commandGuardLevel`) skips the prompt — every other outcome, including\n * any failure of the decision call itself, delegates to the normal approval\n * flow. See `./command-guard.ts`.\n */\n commandGuard?: boolean\n /**\n * How confident every verdict must be before the guard skips the approval\n * prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower\n * level approves more, on less evidence. The decision budget is fixed\n * (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.\n */\n commandGuardLevel?: CommandGuardLevel\n /**\n * Whether requests enforce zero data retention: the provider then routes\n * them only through upstreams that keep no prompts/completions and never\n * train on them (its own opt-in, `CMD_ZDR=1` in the CLI / `x-cmd-zdr: 1` on\n * the Provider API). Defaults to FALSE: `zdr` changes WHERE a request is\n * served. Every chat request carries the header when enabled; a model with\n * no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` instead of\n * being routed through an upstream that retains data. ZDR capacity is\n * priced pass-through and usually costs more, and the price readout keeps\n * quoting the ordinary catalog rates (the real per-request price shows in\n * Command Code's Studio). The decision endpoint behind the command guard is\n * never ZDR-enforced — see `./systemone.ts`.\n */\n zdr?: 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\n/**\n * The Config schema: every field volatile except the composition-only `apiKey`\n * secret.\n *\n * dsh 0.1.7's settings forms are projected from the schema's `meta.volatile`\n * nodes, so an unmarked field would be invisible to AND unwritable from the\n * settings page and refused by form-edit path validation — and the loader\n * hands `apply()` a live reference per marked field, committing later writes\n * without remounting this fiber (the `loader/volatile-update` listener at the\n * bottom of `apply` covers the facts that are not re-derived per read).\n */\nexport const Config: z<Config> = z.object(markVolatileFields({\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 profile Config document\n // (the 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 // DELIBERATELY not volatile: no settings surface writes it (both the web\n // page and the dsh-TUI section write keys through the credentials seam), so\n // it stays composition-only, and a config-file edit to it reloading this\n // fiber is the correct behavior for a secret literal.\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 Config.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 // The command guard. The level list mirrors COMMAND_GUARD_LEVELS in\n // `./command-guard.ts`; the client's field spec mirrors it again (the browser\n // bundle cannot import that node-side module).\n commandGuard: z.boolean().default(false),\n commandGuardLevel: z.union([...COMMAND_GUARD_LEVELS]).default(COMMAND_GUARD_DEFAULT_LEVEL),\n // Off by default: turning it on changes which upstream serves the request\n // (and usually what it costs), so nobody gets ZDR routing by accident.\n zdr: z.boolean().default(false),\n lang: z.string().pattern(/^(zh|en)$/).default('zh' as const),\n}, ['apiKey']))\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 // The connection carries the switch; the adapter enforces it on every\n // chat request rather than depending on a client-side coverage snapshot.\n zdr: config.zdr === true,\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 // The raw composition config as handed to `apply`. Everything downstream\n // reads through `current()`, which unwraps volatile references on every call\n // — the loader commits a settings write IN PLACE on the reference, so a\n // cached plain snapshot would go stale on the very next write.\n const current = (): Config => unwrapVolatileConfig(config)\n const options = (): ResolvedCommandCodeOptions => resolveAdapterOptions(current())\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.probeWindowLimits(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 account-scoped rejection: mark the rejected key when the\n // reason warrants it and hand the adapter the next account's key. When\n // every account is exhausted the pool throws the RATE_LIMIT /\n // INVALID_CREDENTIAL error that names the earliest reset — that error, not\n // the raw provider rejection, is what the caller sees.\n rotateApiKey: async (\n rejectedKey: string,\n rejection: AccountRotationReason,\n _connection: ResolvedCommandCodeOptions,\n model?: string,\n rotation?: { tried: readonly string[]; resetAtMs?: number },\n ): Promise<string | undefined> => {\n // Only the two account-health reasons become marks: an `unavailable`\n // rejection (no credits, a model outside this account's plan) says\n // nothing durable about the key, so the pool rotates past it without\n // remembering — a `:free` model is still served by a credits-empty\n // account. `rate-limit` (a window the provider named) and `throttled` (a\n // 429 that named none) both mark, but with different causes, so the\n // pool's own diagnosis never reports a plain throttle as an exhausted\n // usage window (issue #54). The provider's own `resetAtMs`, when the body\n // carried one, turns the rate-limit mark into a cooldown that expires by\n // itself.\n if (rejection !== 'unavailable') pool.markRejected(rejectedKey, rejection, rotation?.resetAtMs)\n // The whole tried set, not just the rejected key, reaches the pool: a\n // rejection that does not mark the key would otherwise be re-offered on\n // every attempt and a four-account pool could never reach the accounts\n // behind it. The model rides along so model-routing rules pick the next\n // account for the same model. An EMPTY set must not be forwarded — the\n // pool reads it as \"nothing was tried\" and drops the filter this set\n // exists for, so it falls back to the rejected key like a missing one.\n const tried = rotation?.tried?.length ? rotation.tried : [rejectedKey]\n const resolved = await pool.resolveKey(\n model === undefined ? { tried } : { tried, 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 // The picker's plan filter asks about the whole pool, not just the account\n // that would serve right now: with several accounts on different plans,\n // keying the list on the serving one made models appear and vanish as\n // rotation moved between them (and hid models the other accounts could\n // run). Read live, so adding or removing an account applies to the next\n // picker load.\n resolveAccountKeys: async (): Promise<readonly string[]> => {\n const accounts = await pool.resolvedAccounts()\n return accounts.map((account) => account.key)\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 validateTargetRef: (targetRef): void => {\n loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? [])\n },\n storeKey: async ({ apiKey }: CommandCodeLoginCredentials, targetRef): Promise<void> => {\n const ref = credentialRef(loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? []))\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 command guard's live settings. Declared BEFORE the inject below\n // because an inject callback can run synchronously (when the seam is already\n // mounted) and a `const` declared after it would be a temporal-dead-zone\n // throw. Every fact is re-read per ask, so a settings write lands on the very\n // next approval.\n const commandGuardSettings = (): CommandGuardSettings => {\n const raw = current()\n return {\n enabled: raw.commandGuard === true,\n threshold: commandGuardThreshold(raw.commandGuardLevel),\n timeoutMs: COMMAND_GUARD_TIMEOUT_MS,\n }\n }\n\n // The command guard: an AI second opinion in front of the human approval\n // prompt. dsh's approval seam is an optional service, and the guard is only\n // meaningful where it exists (no approval service means no asks to answer at\n // all), so the listeners ride `ctx.inject(['approval'], …)` exactly like\n // `web` and `tuiSettingsSections`: a profile without the seam never activates\n // this fiber, and an engine that predates the service stays inert.\n //\n // The decision endpoint uses the plugin's ordinary credential chain and base\n // URL — no separate key — and every failure inside it delegates to the human\n // (`./command-guard.ts` documents the ladder).\n ctx.inject(['approval'], (approvalCtx) => {\n applyCommandGuard(approvalCtx, {\n settings: commandGuardSettings,\n decide: (request, decideOptions) => runSystemOne(\n {\n apiBase: () => options().apiBase,\n resolveApiKey: () => resolveApiKey(options()),\n },\n request,\n decideOptions,\n ),\n log: (message) => {\n ctx.logger.info(`llm-commandcode: ${message}`)\n },\n })\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 is an optional service. `configure({ auto: false })` declares that\n // this plugin ships its own page, so SettingsForms publishes no auto-generated\n // form for this entry; config IS the live source (volatile fields), and the\n // `loader/volatile-update` listener below is what re-applies the two facts\n // that are not re-derived per read. A profile without a settings service\n // simply keeps using the composition config `apply()` was handed.\n //\n // The one-time settings.yaml import needs no cooperation from here: the\n // section id and the profile entry id are the SAME string\n // (`llm-commandcode`), which is exactly the identity the engine's\n // `importLegacyDocument` looks the entry up by.\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.effect(() => {\n const dispose = settingsCtx.settings.configure({ auto: false }, ctx.fiber)\n return () => {\n dispose()\n }\n }, 'dsh-commandcode-provider: settings auto-form policy')\n })\n\n // The loader commits volatile config IN PLACE — no remount — and notifies the\n // OWNING fiber (`loader/volatile-update`, every value already committed\n // before dispatch). The facts that are not re-derived from `current()` per\n // use re-apply here: the web seam's selection (its private field is written,\n // not read back from config) and the TUI section (its option lists are frozen\n // into the declaration). Typed structurally because the event is declared by\n // `cordis-plugin-loader`, which is not a peer of this bundle.\n const loaderEvents = ctx as unknown as {\n on(event: 'loader/volatile-update', listener: () => void): unknown\n }\n ctx.effect(() => {\n const off = loaderEvents.on('loader/volatile-update', () => {\n applySearchSelection(current().webSearch ?? true)\n refreshTuiSettings?.()\n })\n return () => {\n if (typeof off === 'function') (off as () => void)()\n }\n }, 'dsh-commandcode-provider: volatile config updates')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["record","finite","record","stringField","reject","createNetServer","createHttpServer","isAbortError"],"sources":["../src/capabilities.ts","../src/model-prices.ts","../src/cost-facts.ts","../src/cost-projection.ts","../src/response-encoding.ts","../src/accounts.ts","../src/image-request.ts","../src/image-tokens.ts","../src/stream-trace.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/systemone.ts","../src/command-guard.ts","../src/config-volatile.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.62.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 // The 1.58.0 -> 1.62.0 train added `xai/grok-4.7` (command-code@1.59.0) and\n // `stepfun/Step-5-Preview` (1.60.0) — the only two effort-map changes across\n // those releases, re-verified against the 1.62.0 table; every existing entry,\n // and every effort-less automatic-reasoning model, is unchanged.\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 // command-code@1.56.0 added Qwen 3.8 Omni Flash — the only model-registry\n // change across 1.54.0 -> 1.56.0, and the only catalog model with no local\n // snapshot entry before this. Omni-modal (text+image), 1M context, reasoning\n // with the same ['low', 'medium', 'xhigh'] set as its Qwen 3.8 siblings.\n 'Qwen/Qwen3.8-Omni-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 // command-code@1.60.0 added Step 5 Preview (StepFun's 600B sparse-MoE agentic\n // coding model, 1M context, text+image) with ['low', 'medium', 'high']\n // efforts — the same three-level set as its Step 3.x Flash siblings, which\n // still reason automatically with no levels and so stay out of this map.\n 'stepfun/Step-5-Preview': ['low', 'medium', 'high'],\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 // command-code@1.59.0 added Grok 4.7 (\"Add Grok 4.7\") with the same\n // four-level set as Grok 4.6; 1.61.0 then put it on a 40% off launch deal\n // (see KNOWN_DEALS).\n 'xai/grok-4.7': ['low', 'medium', 'high', 'xhigh'],\n 'z-ai/glm-5.3-flash': ['low', 'high', 'max'],\n // command-code@1.57.0 added GLM-5.3 FlashX — the only model-registry change\n // across 1.56.0 -> 1.57.0 — with the same three-level effort set as its\n // `z-ai/glm-5.3-flash` sibling.\n 'z-ai/glm-5.3-flashx': ['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 // The 1.62.0 -> 1.64.0 train (1.63.0 and 1.64.0; neither has a changelog\n // entry yet — the official changelog page still tops out at 1.62.0, so this\n // was read from the 1.64.0 bundle and the public sources) is additive again:\n // the registry grows 83 -> 86 with exactly three additions — Claude Opus 5.5\n // and the GPT-6 Sol / GPT-6 Luna pair — all three text+image, reasoning with\n // the same five-level set as `gpt-6-astra`, and no edit to any existing row.\n // They are also the only three models the public catalog gained (77 -> 80).\n 'claude-opus-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-6-sol': ['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 // command-code@1.65.0 added `stealth/space-bunny-alpha` (Space Bunny Alpha) —\n // the only model-registry change in the release (no official changelog entry\n // exists for it yet; read from the 1.65.0 bundle and the public catalog,\n // which now serves it). OpenRouter-served (`chatComplete`), text+image, 1M\n // context, reasoning with the three-level set. It is free during the stealth\n // preview (see KNOWN_DEALS) and is NOT routed under ZDR (see\n // KNOWN_NON_ZDR_MODELS).\n 'stealth/space-bunny-alpha': ['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 // command-code@1.56.0 added Qwen 3.8 Omni Flash; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'Qwen/Qwen3.8-Omni-Flash',\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 // command-code@1.64.0 added Claude Opus 5.5; Vision per the official registry\n // and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page also\n // carries caps.vision: true).\n 'claude-opus-5-5',\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.64.0 added the GPT-6 Sol / GPT-6 Luna pair; Vision per the\n // official registry and the CLI's inputModalities:[\"text\",\"image\"] (the\n // pricing page also carries caps.vision: true).\n 'gpt-6-luna',\n 'gpt-6-sol',\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 // command-code@1.65.0 added Space Bunny Alpha; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n // command-code@1.60.0 added Step 5 Preview; Vision per the official registry\n // (\"Text input, Vision, Reasoning\") and the CLI's\n // inputModalities:[\"text\",\"image\"] (the pricing page also carries\n // caps.vision: true).\n 'stepfun/Step-5-Preview',\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 // command-code@1.59.0 added Grok 4.7; Vision per the official registry\n // (\"Text input, Vision, Reasoning\"), the CLI's\n // inputModalities:[\"text\",\"image\"] and the pricing page's caps.vision: true.\n 'xai/grok-4.7',\n 'xiaomi/mimo-v2.5',\n // command-code@1.62.0 added the MiMo V2.6 family (Flash, Pro, Pro\n // UltraSpeed); all three are Vision per the official registry (\"Text input,\n // Vision\"), the CLI's inputModalities:[\"text\",\"image\"] and the pricing\n // page's caps.vision: true. None of them carries a reasoning flag in any\n // source, so they are plain non-thinking models — no effort or\n // automatic-reasoning entry belongs beside these.\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n 'z-ai/glm-5.3-flash',\n // command-code@1.57.0 added GLM-5.3 FlashX; Vision per the official\n // registry and the CLI's inputModalities:[\"text\",\"image\"] (the pricing page\n // also carries caps.vision: true).\n 'z-ai/glm-5.3-flashx',\n])\n\n/**\n * Models WITHOUT a zero-data-retention upstream, per the official CLI's own\n * registry (`command-code@1.65.2` `dist/cli.mjs`, unchanged from 1.65.0:\n * `modelSupportsZdr(id)` is exactly `!nonZdrSet.has(canonicalize(id))`, and\n * `knownModelSupportsZdr`\n * carries the same membership in the sibling route table — the union is this\n * set). The official docs (commandcode.ai/docs/resources/zdr) put it in prose\n * — \"99% of our models have ZDR-capable upstreams … only a small handful of\n * models are affected\" — so the CLI's exclusion list is the only per-model\n * evidence there is; a ZDR request naming one of these fails with HTTP 422\n * `cmd_zdr_no_providers` instead of routing through a provider that retains.\n *\n * Why a NEGATIVE set, and why \"not listed\" answers TRUE: 99% of the catalog is\n * covered, so the maintained difference is the exception list. This helper is\n * informational; the adapter sends the ZDR header for EVERY request when the\n * switch is on. The provider remains the routing authority and refuses an\n * unsupported model rather than silently dropping the privacy guarantee.\n *\n * `minimax/minimax-m3-free` is the one entry the public catalog\n * (`/provider/v1/models`) does not serve (it is CLI/pricing-visible and hidden\n * from the picker); it stays listed because the CLI carries it and a Go-plan\n * request can still name it.\n *\n * Keep in sync via the dsh-commandcode-upstream skill: the CLI's registry data\n * (its `zdr:{only:[…]}` provider routes and the per-provider `zdr`/`noTraining`\n * flags) is upstream-internal routing, not a per-model contract, so this table\n * is the snapshot of the exclusion set and nothing more. The 1.62.0 → 1.64.0\n * diff of that union is EMPTY: both anchors were extracted from both bundles\n * during the 2026-09-23 check and each carries the same 20 members — which is\n * how rare a change here is expected to be. The 1.64.0 → 1.65.0 diff (2026-09-24)\n * is the counterexample that proves the check still runs: exactly one member\n * joins (`stealth/space-bunny-alpha`), and it is in both anchors. `meituan/\n * LongCat-2.0` is the one member the two anchors disagree about (it is in\n * `modelSupportsZdr`'s set in both releases and in neither `knownModelSupportsZdr`\n * set), so the union is\n * what this table follows; reading only the sibling route table would drop it.\n */\nexport const KNOWN_NON_ZDR_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.8-Max-0902',\n 'meituan/LongCat-2.0',\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 'minimax/minimax-m3-free',\n 'poolside/laguna-s-2.1-free',\n 'sakana/fugu-ultra',\n // command-code@1.65.0 added `stealth/space-bunny-alpha` — the first change to\n // this set since the 1.62.0 check. It is in BOTH anchors of the 1.65.0 bundle\n // and the pricing page's own tip says it: \"Free while the preview lasts. Not\n // routed under ZDR.\"\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n 'stepfun/Step-5-Preview',\n 'xai/grok-4.5',\n 'xai/grok-4.6',\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n 'z-ai/glm-5.3-flashx',\n 'zai-org/GLM-5.2-Fast',\n])\n\n/**\n * Whether the CLI snapshot lists a ZDR-capable upstream for `modelId`. This is\n * informational, never a reason to omit the header when ZDR is enabled: the\n * provider may add coverage or lack capacity after this snapshot was taken.\n */\nexport function supportsZeroDataRetention(modelId: string): boolean {\n return !KNOWN_NON_ZDR_MODELS.has(modelId)\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 LongCat 2.0 (then\n * `meituan/LongCat-2.0:free`, now the paid `meituan/LongCat-2.0`; reasoning:!0,\n * 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 // command-code@1.65.2 corrected Step 3.5 Flash's registry context from\n // 1,000,000 to 262,144 tokens; the public catalog already served 262,144.\n // Reasoning and the absence of selectable efforts are unchanged.\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 text-only with automatic reasoning. The free promo\n // ended 2026-09-19 and the backend catalog renamed it from\n // `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`. The rename is\n // billing-only, so the new id keeps this entry: the pricing page still\n // carries `caps.reasoning: true` with no efforts, and command-code@1.58.0 —\n // the CLI release that retired the free tier — carries the new id with\n // `reasoning:!0` and no `reasoningEfforts`, one release after the backend\n // rename the 1.57.0 sync recorded here.\n 'meituan/LongCat-2.0',\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 * LongCat 2.0 (Go — a free promo until 2026-09-19, when the backend renamed\n * `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`); 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); command-code@1.56.0 added\n * `Qwen/Qwen3.8-Omni-Flash` (Go); command-code@1.57.0 added\n * `z-ai/glm-5.3-flashx` (Go); command-code@1.59.0 added `xai/grok-4.7` (GOAT)\n * and 1.60.0 added `stepfun/Step-5-Preview` (Go); command-code@1.62.0 added the\n * MiMo V2.6 family — `xiaomi/mimo-v2.6-flash` + `xiaomi/mimo-v2.6-pro` (Go) and\n * `xiaomi/mimo-v2.6-pro-ultraspeed` (GOAT) — so the 1.58.0 -> 1.62.0 window's\n * only tier changes are additions and the superset chain still holds. The\n * 1.62.0 -> 1.65.0 window continues the pattern: 1.64.0 added\n * `claude-opus-5-5` (Provider/Max), `gpt-6-sol` (Pro) and `gpt-6-luna` (Go),\n * and 1.65.0 added `stealth/space-bunny-alpha` (Go, every tier) — additions\n * only, no tier moves.\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 (50) ---\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.56.0 added Qwen 3.8 Omni Flash; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro) — the\n // same \"all\":true shape as the rest of the Qwen 3.8 family.\n 'Qwen/Qwen3.8-Omni-Flash': '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.64.0 added GPT-6 Luna on every plan including Go (the\n // opensource-category GPT-6 sibling): the pricing page's availability sets\n // individual-go true and the Go plan page lists it, while its premium-category\n // siblings Sol (Pro) and Astra (Provider/Max) do not.\n 'gpt-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). That\n // promo ended 2026-09-19: the pricing page dropped the deal and the free\n // slug, the public catalog renamed the id to `meituan/LongCat-2.0` (paid,\n // $0.30/$1.20/$0.006), and the docs list the new id. command-code@1.58.0\n // followed the backend: it adds the paid id and marks the retired `:free`\n // sibling `hidden` (\"LongCat 2.0 (Free)\"), so the CLI registry now agrees\n // with the catalog this map is keyed by.\n 'meituan/LongCat-2.0': '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 // command-code@1.60.0 added Step 5 Preview; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro), and the\n // Go plan page's rendered table lists it — while GOAT/Pro/Max list it too,\n // which is the superset chain this map encodes.\n 'stepfun/Step-5-Preview': 'go',\n // command-code@1.65.0 added Space Bunny Alpha; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro, the same\n // \"all\":true shape as the Qwen 3.8 family), so it is a Go model that every\n // higher plan also serves. Free during the stealth preview (see KNOWN_DEALS).\n 'stealth/space-bunny-alpha': '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 // command-code@1.62.0 added MiMo V2.6 Flash and MiMo V2.6 Pro on every tier;\n // the Go plan page lists both, and the GOAT-tier Pro UltraSpeed sibling does\n // NOT appear there — the pricing page's availability is what separates them\n // (individual-go: true for these two, false for UltraSpeed).\n 'xiaomi/mimo-v2.6-flash': 'go',\n 'xiaomi/mimo-v2.6-pro': 'go',\n 'z-ai/glm-5.3-flash': 'go',\n // command-code@1.57.0 added GLM-5.3 FlashX; the pricing page's embedded\n // availability grants every tier (individual-go through teams-pro) — the\n // same \"all\":true shape as its `z-ai/glm-5.3-flash` sibling.\n 'z-ai/glm-5.3-flashx': '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 (8 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 // command-code@1.59.0 added Grok 4.7 on GOAT and above: the pricing page's\n // availability sets individual-go false with goat/pro/provider/max/ultra\n // true (\"Available on GOAT and above\"), and the Go plan page's table does not\n // list it while GOAT's does.\n 'xai/grok-4.7': 'goat',\n // command-code@1.62.0 added MiMo V2.6 Pro UltraSpeed on GOAT and above, the\n // same split as its Grok 4.7 sibling (individual-go false; the Go plan page\n // does not list it, GOAT/Pro/Max do) — its two cheaper V2.6 siblings are Go\n // models and sit in the section above.\n 'xiaomi/mimo-v2.6-pro-ultraspeed': 'goat',\n // --- Pro (14 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 // command-code@1.64.0 added GPT-6 Sol on Pro and above: the pricing page's\n // availability sets individual-go/goat false with pro and above true, and the\n // Go and GOAT plan pages do not list it while Pro/Max do.\n 'gpt-6-sol': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider / Max (8) ---\n 'claude-fable-5-1': 'provider',\n 'claude-fable-5': 'provider',\n 'claude-opus-4-7': 'provider',\n 'claude-opus-4-8': 'provider',\n // command-code@1.64.0 added Claude Opus 5.5 on the Provider API only: the\n // pricing page's availability sets go/goat/pro/pro-v1 all false with\n // provider/max/ultra true, and the public catalog serves it with\n // supported_endpoints ['/messages'] — the Claude family's route, which the\n // adapter's `claude-*` prefix rule already sends down the CLI transport.\n 'claude-opus-5-5': '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 * Whether the picker lists `modelId` for a whole POOL of accounts: true when\n * at least one of them includes it. The picker's plan filter is asked this\n * rather than {@link modelVisibleInPlan} for a single account because the pool\n * — not any one account — is what serves a request: keying the list on\n * whichever account rotation happened to reach made models appear and vanish\n * as accounts rotated, and hid models the user's other accounts could run.\n *\n * An account whose facts are unknown counts as \"may include it\" (the same\n * fail-open rule `modelVisibleInPlan` applies one level down), and an empty\n * pool is \"show everything\": hiding a model somebody can run is the one\n * failure this filter must never cause.\n */\nexport function modelVisibleForAnyAccount(\n modelId: string,\n accounts: readonly (CommandCodeBillingAccess | undefined)[] | undefined,\n): boolean {\n if (accounts === undefined || accounts.length === 0) return true\n return accounts.some((access) => modelVisibleInPlan(modelId, access))\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 // command-code@1.61.0 put Grok 4.7 on a 40% off launch deal (\"Grok 4.7 40%\n // off\"), running 2026-09-21 -> 2026-09-27T23:59:59.999Z and reverting to\n // $2.00 in / $6.00 out. The expiry is stamped from the page's own `deal`\n // record so the badge lapses by itself: the vendored rate row already holds\n // the discounted figures ($1.20 in / $3.60 out / $0.30 cache read, doubling\n // past 200K), exactly like the other percentage deals here.\n 'xai/grok-4.7': { label: '40% off', expiresAt: '2026-09-27T23:59:59.999Z' },\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 promo ended 2026-09-19 (the pricing page's deal count\n // dropped 6 -> 5, its free count 4 -> 3, and the DEAL block no longer exists):\n // the entry that shipped from command-code@1.42.0 on is removed here rather\n // than left to badge a model the catalog now serves paid as\n // `meituan/LongCat-2.0` at $0.30/$1.20/$0.006.\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 used to be). Free requests cost no credits on every plan.\n 'inclusionai/ling-3.0-flash-sante:free': { label: 'FREE', free: true },\n // command-code@1.65.0 added Space Bunny Alpha as a stealth-preview free model\n // (\"Free while the stealth preview lasts\", 100% off, auto-applied) — a\n // permanent-style free deal like Ling's, so no expiresAt. It is NOT routed\n // under ZDR (see KNOWN_NON_ZDR_MODELS). The pricing page publishes its rates\n // as a literal zero, and `modelPriceTable()` serves free models explicitly at\n // zero, so no row is added to the vendored price table.\n 'stealth/space-bunny-alpha': { 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-opus-5-5', rates: [4, 20, 0.2, 5] },\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: 'glm-5.3-flashx', rates: [0.37, 1.25, 0.075] },\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: 'gpt-6-luna', rates: [0.1, 0.5, 0.01, 0.125], contextTiers: [{\"maxContext\":272000,\"rates\":[0.1,0.5,0.01,0.125]},{\"rates\":[0.2,0.75,0.02,0.25]}] },\n { id: 'gpt-6-sol', rates: [2, 10, 0.2, 2.5], contextTiers: [{\"maxContext\":272000,\"rates\":[2,10,0.2,2.5]},{\"rates\":[4,15,0.4,5]}] },\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: 'grok-4.7', rates: [1.2, 3.6, 0.3], contextTiers: [{\"maxContext\":200000,\"rates\":[1.2,3.6,0.3]},{\"rates\":[2.4,7.2,0.6]}] },\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: 'longcat-2.0', rates: [0.3, 1.2, 0.006] },\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: 'mimo-v2.6-flash', rates: [0.14, 0.28, 0.0028] },\n { id: 'mimo-v2.6-pro', rates: [0.435, 0.87, 0.0036] },\n { id: 'mimo-v2.6-pro-ultraspeed', rates: [4.35, 8.7, 0.036] },\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: 'qwen-3.8-omni-flash', rates: [0.15, 0.47, 0.016] },\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: 'step-5-preview', rates: [1, 2.7, 0.05] },\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 * Ask Command Code for plain response bodies. A DSH host using an incompatible\n * undici global dispatcher can lose response headers and leave compressed\n * JSON, SSE, and pre-stream error bodies undecoded.\n */\nexport const IDENTITY_ENCODING_HEADER = { 'accept-encoding': 'identity' } as const\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 or 401 against\n * the exact API key, so several slots sharing one key share one state. A\n * 429 that NAMED a usage window marks the window exhausted; a 429 that\n * named none is recorded as a plain throttle, which rotates the same way\n * but is never reported as an exhausted window (issue #54).\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 * - An account the user explicitly asked for — the manual pin\n * ({@link CommandCodeAccountPoolDeps.preferredId}) or a model rule's\n * routed account — is probed the same way when a mark would demote it, so\n * a fallback is never permanent (issue #51).\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/**\n * How long an explicitly selected account's rate-limit mark may stand before\n * its window is probed again. A 429 whose reset was never learned marks the\n * key `unknown`, which {@link accountUsable} refuses forever — deliberately,\n * because the all-marked revival pass is the only thing meant to clear it and\n * it costs one billing call per key. That is fine for a key nobody asked for,\n * and wrong for the one the user pinned: a single 429 would otherwise demote\n * the user's own selection until the process restarts (issue #51). The probe\n * is therefore allowed once per interval per key, which bounds an endpoint\n * that keeps failing while a successful probe resolves the mark for good.\n */\nconst EXPLICIT_ACCOUNT_PROBE_INTERVAL_MS = 60_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/**\n * Why a key stopped serving requests.\n *\n * `rate-limit` is a USAGE-WINDOW rejection: the provider named one of its\n * metered windows (`error.rateLimit.window`, or a message saying the plan's\n * usage limit was reached — the only two shapes the official CLI's own\n * `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the\n * plain 429: the provider refused the request without saying anything about a\n * window, so the key leaves rotation for now but the pool must not describe it\n * as an exhausted window. Collapsing the two is issue #54: the reporter's\n * account panel showed the five-hour window at 2% and the weekly one at 10%\n * while the turn failed with \"all 1 Command Code account(s) have exhausted\n * their usage window\".\n */\nexport type AccountRejection = 'rate-limit' | 'throttled' | '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 /**\n * The evidence behind the mark — what the pool may CLAIM when it reports\n * that no account can serve. `window`: the provider named a usage window, or\n * a `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429\n * that said nothing about a window (a burst limiter, or a model- or\n * spend-level limit the billing endpoint cannot show). `auth`: a 401.\n */\n cause: 'window' | 'throttle' | 'auth'\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/**\n * One account's real rate-limit state, probed from `/alpha/billing/credits`:\n * `exceeded` is true when ANY of the account's usage windows is spent, and\n * `resetAt` is the latest reset among them (the binding constraint — an open\n * five-hour window buys nothing while the weekly quota is exhausted).\n */\nexport interface AccountWindowProbe {\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 /**\n * Probe one key's usage windows — BOTH windows the endpoint publishes (the\n * five-hour and the weekly one), not just the five-hour one; see\n * {@link AccountWindowProbe}. Undefined when the probe itself failed.\n */\n probeWindow(apiKey: string): Promise<AccountWindowProbe | 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 — and an exhausted one is\n * re-probed on the way (see {@link CommandCodeAccountPool.resolveKey}), so\n * the fallback lasts only as long as the window really is exceeded.\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 * Clock seam for the explicit-account probe throttle. Tests drive it so the\n * \"the interval elapsed, probe again\" half of\n * {@link CommandCodeAccountPool.canProbeExplicit} is reachable without\n * waiting a real minute; production reads `Date.now()`.\n */\n now?(): number\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 /** Last explicit-revival probe attempt by API key (throttles a failing probe). */\n private readonly explicitProbes = new Map<string, number>()\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.tried` lists the keys this request has already used — the\n * just-rejected one included. They are removed from the resolution entirely,\n * which is what lets one request walk a four-account pool: an account-scoped\n * rejection that does not mark the key (no credits, a model outside the\n * account's plan) would otherwise be offered again on every attempt, and the\n * accounts behind it would never be reached.\n *\n * An explicit selection (the pin or a model rule) that a rate-limit mark\n * would demote is probed before the fallback serves, so \"falls back while\n * exhausted\" never becomes \"stays demoted until the process restarts\".\n */\n async resolveKey(options?: { tried?: readonly 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 // One filter for the whole resolution: the routed, pinned, rotating and\n // probe-revival paths must all agree on which accounts are still in play.\n const tried = options?.tried\n const available = tried === undefined || tried.length === 0\n ? accounts\n : accounts.filter((account) => !tried.includes(account.key))\n const preferred = this.deps.preferredId?.()\n // Every account was already tried in this request. Nothing can be handed\n // back: an account that is merely UNMARKED (a plan or balance rejection\n // marks nothing) leaves the caller's own rejection as the honest answer,\n // so return undefined and let it surface. When every account is marked\n // instead, the pool still owes its own diagnosis — the earliest window\n // reset, with the wait the retry policy sleeps on — and it is built from\n // the marks as they stand, without probing: a probe here would answer a\n // question this request cannot act on, and reviving a key mid-request\n // would make the diagnosis below describe an account that is usable again.\n const diagnoseOnly = available.length === 0\n if (diagnoseOnly) {\n if (selectActiveAccount(accounts, preferred) !== undefined) return undefined\n throw allAccountsUnusable(accounts)\n }\n const routed = selectAccountForModel(available, options?.model ?? '', this.deps.modelAccountRules?.())\n if (routed !== undefined) return this.pick(routed)\n const chosen = selectActiveAccount(available, preferred)\n if (chosen !== undefined) {\n // The explicit account is unusable while another one can serve — the\n // fallback path. Its mark is re-checked against the real window before\n // the user's own selection is demoted for good (issue #51).\n const explicit = this.explicitAccount(available, options?.model ?? '', preferred)\n if (\n explicit !== undefined\n && explicit.key !== chosen.key\n && this.canProbeExplicit(explicit)\n ) {\n const revived = await this.probeExplicit(explicit)\n if (revived !== undefined) return this.pick(revived)\n }\n return this.pick(chosen)\n }\n\n // Every account still in play is marked: probe the real windows before\n // giving up. Disabled (401) keys are not probed — an invalid key stays\n // invalid. A throwing probe counts as \"unknown\" (like a failed probe): it\n // must not turn the all-exhausted path into a raw rejection instead of\n // RATE_LIMIT.\n await Promise.all(available.map(async (account) => {\n if (account.state?.kind === 'disabled') return\n let probe: AccountWindowProbe | 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 return\n }\n // A known reset becomes a cooldown that expires by itself. An UNKNOWN one\n // must not: `until: 0` would read as \"never usable again\" to\n // {@link accountUsable} and take the account out of service for the rest\n // of the process — the very permanence this pool must not have. Keeping\n // the `unknown` mark leaves it eligible for the next probe. Either way the\n // cause becomes `window`: a probe that read a window as exceeded is\n // window evidence, whatever the key was originally marked for. A mark that\n // ALREADY carries a cooldown keeps it when this probe publishes no reset\n // — a known reset must never be thrown away for an unknown one.\n if (probe.resetAt > 0) {\n this.states.set(account.key, {\n kind: 'cooldown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: probe.resetAt,\n })\n } else if (account.state?.kind !== 'cooldown') {\n this.states.set(account.key, {\n kind: 'unknown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: 0,\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.) The tried\n // keys stay filtered out: a probe that clears one must not re-offer a key\n // this request already burned, which is what the adapter refuses anyway.\n const latestAccounts = await this.resolvedAccounts()\n const latest = tried === undefined || tried.length === 0\n ? latestAccounts\n : latestAccounts.filter((account) => !tried.includes(account.key))\n const revived = selectActiveAccount(latest, preferred)\n if (revived !== undefined) return this.pick(revived)\n\n // Nothing still in play can serve — but an account this request already\n // used may be UNMARKED, because an `unavailable` rejection (no credits, a\n // model outside this account's plan) deliberately marks nothing. That\n // rejection is the honest answer, and returning undefined is how the caller\n // gets to surface it. Throwing the pool's own diagnosis instead would name\n // the wrong cause, count only the tried-filtered subset, and — for\n // RATE_LIMIT — hand dsh-llm-retry a wait that turns a PERMANENT failure\n // into a ~15-minute stall. The no-account-left branch above applies exactly\n // this rule; the two disagreed before, on the very case issue #51's\n // follow-up is about.\n if (selectActiveAccount(latestAccounts, preferred) !== undefined) return undefined\n // The diagnosis always describes the POOL. A second resolution that came\n // back empty — a transient credential-store miss, not a configuration\n // change — would otherwise report \"every configured account (0) was\n // rejected with 401\", naming neither an account nor a real cause.\n throw allAccountsUnusable(latestAccounts.length > 0 ? latestAccounts : accounts)\n }\n\n /**\n * Record a rejection against one key. `rate-limit` marks the key's usage\n * WINDOW exhausted — as a `cooldown` until `resetAtMs` when the rejection\n * body named the provider's own reset time, otherwise as an `unknown` mark\n * whose window is probed lazily. `throttled` (the plain 429 that named no\n * window) marks the key with the `throttle` cause instead: it leaves rotation\n * exactly like a window mark does, but the pool's own diagnosis keeps saying\n * \"rate limited\" rather than inventing an exhausted window. A 401\n * (`invalid-credential`) disables the key until the stored credential\n * changes.\n *\n * `resetAtMs` is seconds-to-millis converted by the adapter from the\n * provider's `error.rateLimit.reset`: knowing the real reset immediately is\n * what keeps an exhausted account out of rotation for exactly as long as the\n * provider said. It only applies to a window mark; a plain throttle keeps the\n * window unknown on purpose, so a probe can still find out.\n */\n markRejected(apiKey: string, rejection: AccountRejection, resetAtMs?: number): void {\n if (rejection === 'invalid-credential') {\n this.states.set(apiKey, { kind: 'disabled', cause: 'auth', reason: 'invalid API key (401)', until: 0 })\n } else if (rejection === 'throttled') {\n // Deliberately NOT a cooldown from `resetAtMs`: a throttle carries no\n // window fact, and an `unknown` mark is what keeps the key eligible for\n // the window probe that turns a real window limit into a cooldown with\n // the provider's own reset (or revives the key when the window is open).\n this.states.set(apiKey, { kind: 'unknown', cause: 'throttle', reason: 'rate limited (429)', until: 0 })\n } else if (resetAtMs !== undefined && resetAtMs > Date.now()) {\n this.states.set(apiKey, { kind: 'cooldown', cause: 'window', reason: 'usage window exhausted (429)', until: resetAtMs })\n } else {\n this.states.set(apiKey, { kind: 'unknown', cause: 'window', reason: 'usage window exhausted (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 /**\n * The account the user explicitly asked for: the slot a model rule routes\n * the request to when that id exists among the resolved slots, else the\n * manually pinned slot. Consulted only on the fallback path — a usable\n * routed account already returned above — so unlike\n * {@link selectAccountForModel} it does NOT require the account to be\n * usable, which is exactly what {@link resolveKey} re-probes.\n */\n private explicitAccount(\n accounts: readonly ResolvedAccount[],\n model: string,\n preferredId: string | undefined,\n ): ResolvedAccount | undefined {\n const rule = matchModelRule(model, this.deps.modelAccountRules?.())\n const id = rule !== undefined && accounts.some((account) => account.slot.id === rule.account)\n ? rule.account\n : preferredId\n return id === undefined ? undefined : accounts.find((account) => account.slot.id === id)\n }\n\n /**\n * Whether an explicitly selected account's mark is due for a window probe.\n * Only an `unknown` mark (a 429 whose reset was never learned) is worth\n * re-probing: a `cooldown` already carries its reset time and expires by\n * itself, and a `disabled` (401) key stays out until the stored credential\n * changes. The interval bounds a probe endpoint that keeps failing.\n */\n private canProbeExplicit(account: ResolvedAccount): boolean {\n if (account.state?.kind !== 'unknown') return false\n const last = this.explicitProbes.get(account.key)\n return last === undefined || this.now() - last >= EXPLICIT_ACCOUNT_PROBE_INTERVAL_MS\n }\n\n /** The clock the probe throttle reads; injected so a test can travel in time. */\n private now(): number {\n return this.deps.now?.() ?? Date.now()\n }\n\n /**\n * Probe one explicitly selected account's window and apply the answer. A\n * window that is no longer exceeded drops the mark, so the user's own\n * selection serves again on this very request. An exceeded one is stamped\n * as a cooldown carrying the provider's reset time, after which\n * {@link accountUsable} lets the account back in with no further probe. A\n * probe that fails changes nothing: the mark stays `unknown` and the next\n * attempt waits out the interval.\n */\n private async probeExplicit(account: ResolvedAccount): Promise<ResolvedAccount | undefined> {\n this.explicitProbes.set(account.key, this.now())\n let probe: AccountWindowProbe | undefined\n try {\n probe = await this.deps.probeWindow(account.key)\n } catch {\n return undefined\n }\n if (probe === undefined) return undefined\n if (!probe.exceeded) {\n this.states.delete(account.key)\n // The throttle timestamp SURVIVES the revival. Deleting it read as \"this\n // key was never probed\", so the next request probed again — and the loop\n // that follows is exactly the one the interval exists to bound: the probe\n // says the window is open, the chat endpoint answers 429 anyway (a spend\n // cap or a model-level limit is invisible to `windowLimits`), the mark\n // returns to `unknown`, and the next request probes once more — one\n // billing GET plus one doomed upstream attempt per request, forever.\n // Keeping the stamp costs nothing when the revival was right: a serving\n // account is never probed at all, and the mark only comes back if the\n // provider rejects it again, which is when the interval should apply.\n return { slot: account.slot, key: account.key, state: undefined }\n }\n // A reset time is what makes the mark expire on its own; without one the\n // mark stays `unknown`, so a later probe can still learn it. The cause is\n // `window` either way: the probe read the account's own usage windows. A\n // mark that already carries a cooldown keeps it, exactly like the all-marked\n // pass: a known reset is never traded for an unknown one.\n if (probe.resetAt > 0) {\n this.states.set(account.key, {\n kind: 'cooldown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: probe.resetAt,\n })\n } else if (account.state?.kind !== 'cooldown') {\n this.states.set(account.key, {\n kind: 'unknown',\n cause: 'window',\n reason: account.state?.reason ?? 'usage window exhausted (429)',\n until: 0,\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 * The error for \"accounts exist but none of them can serve\". Three shapes, each\n * claiming only what the pool actually knows:\n *\n * - every account rejected with 401 → `INVALID_CREDENTIAL`;\n * - at least one account marked by a NAMED usage window (or by a probe that\n * read a window as exceeded) → the window diagnosis, naming the earliest\n * known reset when the provider published one;\n * - every mark a plain throttle (a 429 that said nothing about a window, and\n * no probe could confirm one) → a throttle diagnosis that says so. Claiming\n * \"all accounts have exhausted their usage window\" here is issue #54: the\n * report's account panel showed the five-hour window at 2% and the weekly\n * one at 10% while the turn failed with exactly that sentence.\n *\n * Shared by the all-marked tail of {@link CommandCodeAccountPool.resolveKey}\n * and by its already-tried diagnosis, so the two can never drift apart.\n *\n * The attached `providerRetryAfterMs` is the exact wait until the earliest\n * known window reset, so dsh-llm-retry sleeps through the window instead of\n * polling at its backoff cadence. It is capped at {@link RETRY_MAX_DELAY_MS}:\n * the executor honors a provider wait verbatim only at or below the policy's\n * `maxDelayMs` — a LONGER attached wait makes it abandon the retry entirely\n * (normal mode), which would turn \"poll until the window opens\" into \"fail\n * now\". Longer resets simply ride the capped local backoff and the probe\n * revival. A throttle diagnosis attaches none: its marks carry no reset.\n */\nfunction allAccountsUnusable(accounts: readonly ResolvedAccount[]): LlmError {\n const disabled = accounts.filter((account) => account.state?.kind === 'disabled')\n if (disabled.length === accounts.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 return new LlmError(\n `llm-commandcode: every configured Command Code account (${accounts.length}) was rejected with 401`\n + ' — check the stored API keys (Models page / settings) or the auth file'\n + `;已配置的 ${accounts.length} 个 Command Code 账户密钥均被拒绝(401)`\n + '——请在设置页检查存储的 API 密钥,或重新运行 command-code login',\n 'INVALID_CREDENTIAL',\n )\n }\n const marked = accounts\n .map((account) => account.state)\n .filter((state): state is CommandCodeAccountState => state !== undefined)\n // Only a `window` mark may be described as an exhausted usage window. A\n // throttle mark proves the provider refused the request, never that a\n // metered window is spent — and because it deliberately carries no reset\n // (`unknown`, so the next pass may probe the real windows), this answer has\n // no time to name either. dsh-llm-retry's own backoff paces the retries.\n const windowMarked = marked.filter((state) => state.cause === 'window')\n if (windowMarked.length === 0) {\n return new LlmError(\n `llm-commandcode: all ${accounts.length} Command Code account(s) are rate limited (429)`\n + ' — the provider did not report an exhausted usage window; retrying'\n + `;全部 ${accounts.length} 个 Command Code 账户被限流(429)`\n + '——服务商未报告用量窗口用尽,正在重试',\n 'RATE_LIMIT',\n )\n }\n const resets = windowMarked\n .filter((state) => state.kind === 'cooldown' && state.until > 0)\n .map((state) => state.until)\n const earliest = resets.length > 0 ? Math.min(...resets) : 0\n const wait = earliest > 0 ? Math.max(1000, earliest - Date.now()) : 0\n return new LlmError(\n `llm-commandcode: all ${accounts.length} Command Code account(s) have exhausted their usage window`\n + (earliest > 0\n ? `; the earliest window resets at ${clockLabel(earliest)}`\n : ' — the provider published no reset time for it')\n + ' — requests will succeed again after the reset (or add another account)'\n + `;已用尽全部 ${accounts.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 * 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 * The target IS the projected geometry — `{ width, height, maxBytes }` — which\n * the attachment service passes straight to its encoder.\n *\n * @module dsh-commandcode-provider/image-request\n */\n\nimport type { ImageAttachmentRef, ImageRequestTarget } 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 * 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 * `dsh-attachment` exports an equivalent `longEdgeDimensions`, but it does not\n * guard its inputs: a reference whose declared size is 0 or NaN — a malformed\n * or fabricated attachment record — would project to a zero-sized target and\n * make the encoder refuse the whole request. The guard is the reason this stays\n * local; `tests/image-tokens.test.ts` pins the degenerate cases.\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 encoded-byte budget.\n */\nexport function requestImageTarget(ref: ImageAttachmentRef): ImageRequestTarget {\n const projected = longEdgeDimensions(ref.width, ref.height, REQUEST_IMAGE_MAX_LONG_EDGE)\n return {\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 * Opt-in raw-stream trace for the Command Code transports.\n *\n * Why this exists: this route's failure mode of record is a response that ENDS\n * EARLY. The gateway, an intermediary proxy, or the network closes the socket\n * mid-generation, so the adapter's read loop sees `done` without ever seeing\n * the transport's terminal event. From inside the adapter those two endings are\n * indistinguishable — the provider cut the stream, a proxy timed out, or the\n * socket was dropped — and the only artifact that separates them is the raw\n * wire: which events actually arrived, when the last one landed, how long the\n * socket then sat silent, and how it ended. Without that, a truncated answer is\n * a report with no evidence attached.\n *\n * Enable it per process:\n *\n * ```sh\n * DSH_COMMANDCODE_TRACE=/tmp/cc-stream.jsonl dsh web\n * DSH_COMMANDCODE_TRACE=1 dsh web # -> $TMPDIR/dsh-commandcode-stream.jsonl\n * ```\n *\n * Any value that is not a flag is a path, and the explicit off-spellings\n * (`0`, `false`, `no`, `off`) are recognized as \"off\" rather than being taken\n * for a file name.\n *\n * Every model request appends one JSONL record per raw chunk plus lifecycle\n * records (`response`, `eof`, `idle-timeout`, `read-error`, `end`,\n * `stream-close`), each stamped with `at` — milliseconds since that request's\n * first byte. The chunk records carry the provider's own payload verbatim\n * (bounded per chunk), because a truncated answer is exactly what is being\n * diagnosed: treat the file as conversation content, not as a log safe to\n * share. It never carries the request body, an API key, or any request header.\n *\n * Deliberate trade-offs:\n * - OFF costs one `process.env` read per request.\n * - ON appends synchronously, one file open per chunk. The trace must survive\n * a host killed mid-diagnosis, and the microseconds it costs are irrelevant\n * beside the seconds-scale silences it is there to measure.\n * - A trace that cannot be written turns itself off instead of failing the\n * request it is observing: a diagnostic must never become the outage.\n *\n * @module\n */\n\nimport { appendFileSync, mkdirSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join } from 'node:path'\n\n/** Environment variable that turns the trace on. */\nexport const STREAM_TRACE_ENV = 'DSH_COMMANDCODE_TRACE'\n\n/** File used when the variable is set to a bare flag instead of a path. */\nexport const STREAM_TRACE_DEFAULT_FILE = 'dsh-commandcode-stream.jsonl'\n\n/**\n * Ceiling for ONE request's trace, in bytes.\n *\n * A long generation is megabytes of SSE; the interesting part is always the\n * tail, but records are appended in arrival order, so the cap is what keeps a\n * forgotten trace from filling a disk. Hitting it stops payload records;\n * one bounded `end` and `stream-close` record can still follow so a long\n * reasoning phase cannot hide the very terminal outcome being diagnosed.\n */\nexport const STREAM_TRACE_MAX_BYTES = 4 * 1024 * 1024\n\n/** One raw chunk is recorded verbatim up to this many characters. */\nexport const STREAM_TRACE_MAX_TEXT = 16 * 1024\n\n/** Values of {@link STREAM_TRACE_ENV} that mean \"trace to the default file\". */\nconst FLAG_VALUES = new Set(['1', 'true', 'yes', 'on'])\n\n/**\n * Values that explicitly mean OFF.\n *\n * A user turning the trace off writes `false` as readily as they write `1` to\n * turn it on, and without this set every one of these spellings fell through to\n * \"…so it must be a path\" — the trace switched ON and wrote the conversation to\n * a file NAMED `false` (or `0`, or `off`) in the process's working directory.\n */\nconst OFF_VALUES = new Set(['0', 'false', 'no', 'off'])\n\n/** What the adapter writes through; {@link openStreamTrace}'s disabled stand-in is inert. */\nexport interface StreamTrace {\n /** Whether records are actually being written. */\n readonly enabled: boolean\n /**\n * Append one record.\n *\n * @param event - short record name (`response`, `chunk`, `eof`, …).\n * @param fields - JSON-serializable payload; never pass credentials.\n */\n record(event: string, fields?: Record<string, unknown>): void\n /** Write the closing record; safe to call twice, and on a capped trace. */\n close(): void\n}\n\n/** The inert trace used whenever the switch is off. */\nconst OFF: StreamTrace = { enabled: false, record: () => undefined, close: () => undefined }\n\n/**\n * Resolve the trace file for this process.\n *\n * @param raw - the variable's raw value; defaults to the live environment.\n * @returns the file to append to, or undefined when the trace is off.\n */\nexport function resolveStreamTracePath(\n raw: string | undefined = process.env[STREAM_TRACE_ENV],\n): string | undefined {\n const value = raw?.trim()\n if (value === undefined || value === '') return undefined\n const lower = value.toLowerCase()\n if (OFF_VALUES.has(lower)) return undefined\n if (FLAG_VALUES.has(lower)) return join(tmpdir(), STREAM_TRACE_DEFAULT_FILE)\n return value\n}\n\n/**\n * Clamp one recorded payload so a single chunk cannot consume the whole cap.\n *\n * @param text - the text to record.\n * @param max - characters to keep, defaulting to {@link STREAM_TRACE_MAX_TEXT}.\n * @returns `text` unchanged, or its head plus a marker naming what was dropped.\n */\nexport function boundTraceText(text: string, max: number = STREAM_TRACE_MAX_TEXT): string {\n if (text.length <= max) return text\n return `${text.slice(0, max)}…[+${text.length - max} chars]`\n}\n\n/**\n * Open one request's trace.\n *\n * @param scope - what the records describe (the `provider/model` route).\n * @param options - `path` overrides the environment (tests pass a temp file);\n * `now` overrides the clock the `at` stamps are measured with.\n * @returns a writer that never throws and never fails the request.\n */\nexport function openStreamTrace(\n scope: string,\n options: { path?: string; now?: () => number } = {},\n): StreamTrace {\n const path = options.path ?? resolveStreamTracePath()\n if (path === undefined) return OFF\n const now = options.now ?? Date.now\n const startedAt = now()\n let written = 0\n let stopped = false\n let capped = false\n const terminals = new Set<string>()\n // The directory is created once, here, so the hot path is a single append.\n // A path that cannot be prepared disables the trace rather than throwing:\n // the request this observes must not depend on the observer.\n try {\n mkdirSync(dirname(path), { recursive: true })\n } catch {\n return OFF\n }\n const write = (record: Record<string, unknown>): void => {\n if (stopped) return\n const terminal = record.event === 'end' || record.event === 'stream-close'\n if (capped && !terminal) return\n if (terminal && terminals.has(String(record.event))) return\n let line: string\n try {\n line = `${JSON.stringify({ at: now() - startedAt, scope, ...record })}\\n`\n } catch {\n // A payload that cannot be serialized (a cycle, a BigInt) drops that\n // record only; the trace stays on for the records that do serialize.\n return\n }\n // Bound final metadata too: at most two 16 KiB records beyond the payload\n // cap. Count UTF-8 bytes, since reasoning often contains non-ASCII text.\n if (terminal) {\n if (Buffer.byteLength(line) > STREAM_TRACE_MAX_TEXT) return\n terminals.add(String(record.event))\n } else if (written + Buffer.byteLength(line) > STREAM_TRACE_MAX_BYTES) {\n capped = true\n line = `${JSON.stringify({ at: now() - startedAt, scope, event: 'trace-capped', bytes: written })}\\n`\n }\n try {\n appendFileSync(path, line)\n written += Buffer.byteLength(line)\n } catch {\n stopped = true\n }\n }\n write({ event: 'stream-open' })\n return {\n enabled: true,\n record(event, fields) {\n write(fields === undefined ? { event } : { event, ...fields })\n },\n close() {\n write({ event: 'stream-close', bytes: written })\n },\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 through command-code@1.65.2):\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 | cache-write-tokens | 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'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n ToolCallId,\n errorChain,\n IMAGE_OFFLOAD_REQUIRED_CODE,\n offloadedImageText,\n projectOffloadedImages,\n requiredImageOffload,\n resolveRetryPolicy,\n textOnlyImageText,\n type ImageBlock,\n type LlmErrorOptions,\n type LlmImageRequestBudget,\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 RequestMessage,\n type StreamChunk,\n type TokenUsage,\n} 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'\nimport { boundTraceText, openStreamTrace, STREAM_TRACE_ENV } from './stream-trace.ts'\n\nimport {\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n capabilityDescription,\n compareByPlan,\n modelVisibleForAnyAccount,\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.65.2'\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 * concatenated in the order the gateway sent it.\n *\n * Entries are read by their own text members rather than filtered on `type`:\n * DeepSeek sends `{ type: 'reasoning.text', text }` while the OpenAI family\n * sends `{ type: 'reasoning.summary', summary, format: 'openai-responses-v1' }`\n * — the same summary text the scalar `delta.reasoning` carries, in the\n * Responses protocol's vocabulary. A `type` filter would drop one family or the\n * other, and losing thinking is the failure this exists to prevent.\n *\n * `text` wins per entry, but an EMPTY `text` must not shadow a populated\n * `summary` (the Responses wire emits `text: ''` placeholders), so the fallback\n * tests for non-empty rather than merely present. Entries carrying neither\n * member — the encrypted blobs — contribute nothing, and no entry contributes\n * both, so a summary is never counted twice.\n *\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 const exact = stringValue(entry.text)\n const summary = stringValue(entry.summary)\n text += exact !== undefined && exact !== '' ? exact : (summary ?? '')\n }\n return text === '' ? undefined : text\n}\n\n/**\n * One SCALAR thinking delta, treating an empty string as \"this chunk carries\n * none\" — the same rule {@link reasoningDetailsText} applies inside the array.\n * The scalar and the array describe the same thinking, so an empty spelling of\n * one must not shadow populated text in the other (the Responses wire pads with\n * `text: ''`). `??` alone cannot express this: an empty string is not nullish,\n * so `reasoning: ''` beside a populated `reasoning_details` used to drop the\n * whole chunk's thinking.\n */\nfunction nonEmptyText(value: string | undefined): string | undefined {\n return value === undefined || value === '' ? undefined : value\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 *\n * Written with spaces rather than the CLI's underscores, because\n * {@link hasTerminalStreamMarker} normalizes the separator before matching:\n * a JSON body usually carries `premium credits exhausted` while the CLI's own\n * list is written `premium_credits_exhausted`, and both are the same refusal\n * (the pre-stream classifier normalizes identically).\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 normalized = message.toLowerCase().replaceAll('_', ' ')\n return TERMINAL_STREAM_ERROR_MARKERS.some((marker) => normalized.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 * Whether one rejection says \"ZDR requested, no ZDR-capable upstream\": the\n * provider spells the code `cmd_zdr_no_providers` in JSON error bodies and\n * `CMD_ZDR_NO_PROVIDERS` in plain-text ones (the official CLI's own\n * classifier checks both spellings, and its error text tells the user to\n * unset `CMD_ZDR`). Underscore-separated matching normalizes the separator, so\n * one comparison covers the variants — the same normalization the pre-stream\n * rejection classifier and `hasTerminalStreamMarker` already use.\n */\nconst ZDR_NO_PROVIDERS_PATTERN = /cmd[_\\s-]?zdr[_\\s-]?no[_\\s-]?providers/i\n\nfunction isZdrNoProviders(providerCode: string | undefined, providerDetail: string, errText: string): boolean {\n return ZDR_NO_PROVIDERS_PATTERN.test(providerCode ?? '')\n || ZDR_NO_PROVIDERS_PATTERN.test(providerDetail)\n || ZDR_NO_PROVIDERS_PATTERN.test(errText)\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 — and an explicit\n * refusal (`isRetryable: false`) or a terminal marker OUTRANKS a status, so a\n * 5xx carrying \"insufficient credits\" stays terminal instead of entering the\n * retry cadence as `SERVER`.\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 // An explicit refusal and a terminal marker both outrank the STATUS, so a 5xx\n // that carries \"insufficient credits\" (or `isRetryable: false`) cannot be\n // answered with `SERVER` — that put a permanent refusal back on\n // dsh-llm-retry's 1000-attempt cadence. Only a status with no such evidence\n // keeps the transient mapping, and an explicit `isRetryable: true` still\n // wins over everything.\n const retryable = isRetryable === true\n || (isRetryable === false || terminal\n ? false\n : (statusCode !== undefined ? retryableStatus : true))\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 RequestMessage[] -> 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/** The tool result one `role: 'tool'` message answers. */\ninterface ToolResultView {\n readonly toolCallId: string\n readonly isError?: boolean\n readonly content: readonly ContentBlock[]\n}\n\n/**\n * The tool result one message answers, or undefined when it answers none.\n *\n * The harness models a tool result as its own `role: 'tool'` message carrying\n * `toolCallId`/`isError` beside raw content blocks (a closed role map:\n * `MessageRoleMap.tool` is the only role a tool result can arrive on). Pairing\n * and emission MUST agree on this same view: otherwise a dropped result either\n * drops its call too (making the model forget completed work), or leaves an\n * unanswered call on the wire.\n */\nfunction toolResultOf(message: RequestMessage): ToolResultView | undefined {\n if (message.role !== 'tool') return undefined\n const { toolCallId, content } = message\n if (typeof toolCallId !== 'string' || toolCallId === '') return undefined\n return { toolCallId, isError: message.isError ?? false, content }\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 RequestMessage[]): {\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 const result = toolResultOf(message)\n if (result) resultIds.add(result.toolCallId)\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 }\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: ToolResultView): ToolResultMedia {\n const chunks: string[] = []\n const images: ImageAttachmentRef[] = []\n const seen = new Set<string>()\n for (const nested of block.content) {\n if (nested.type === 'text' || nested.type === 'reasoning') {\n if (nested.text) chunks.push(nested.text)\n continue\n }\n if (nested.type === 'image' && !seen.has(nested.attachment.attachmentId)) {\n seen.add(nested.attachment.attachmentId)\n images.push(nested.attachment)\n }\n }\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: RequestMessage): boolean {\n return message.content.some((block) => block.type === 'image')\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. The\n// offload set is a DURABLE surface fact: the adapter renders the surface's\n// `offloaded` marks with `projectOffloadedImages`, and when the history still\n// exceeds the budget it does NOT evict — it fails with\n// `IMAGE_OFFLOAD_REQUIRED` + `offloadImages`, which the default\n// `dsh-compaction-image-offload` plugin turns into one `image/offload` session\n// event and a retry. Every later request on the session then carries the same\n// placeholder text, across restore and fork, and the token meter stops counting\n// the evicted images as context. The budget is accounted in the encoded form,\n// because it is the base64 the wire actually carries that has to fit.\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/** One occurrence's exact request-version byte length, as the core counter wants it. */\ntype ImageVersionBytes = (block: { attachment: ImageAttachmentRef }) => number\n\n/**\n * The engine's durable-offload contract, as one object.\n *\n * Both members are required together: a half-populated policy would either lose\n * the surface's marks (re-sending evicted images as pixels) or lose the count\n * (silently sending an over-budget body), and neither is worth a partial\n * opt-in. The defaults are the engine's own helpers; the object exists so tests\n * can substitute a counting stub.\n */\nexport interface SurfaceImagePolicy {\n /** Render the surface's durable offload marks as placeholder text. */\n projectOffloadedImages: typeof projectOffloadedImages\n /** How many more leading retained occurrences must be offloaded. */\n requiredImageOffload: typeof requiredImageOffload\n}\n\n/** The engine's own helpers: what a process that injects nothing speaks. */\nconst ENGINE_IMAGE_POLICY: SurfaceImagePolicy = { projectOffloadedImages, requiredImageOffload }\n\n/**\n * The failure a route raises instead of evicting on its own. 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 members the core counter reads, plus the wire representation. */\ntype CoreImageBudget = Pick<\n LlmImageRequestBudget,\n 'representation' | 'maxBytes' | 'maxImages' | 'byteQuantum' | 'countQuantum'\n>\n\n/** The budget in the shape the core counter takes (representation + the rung). */\nfunction coreBudget(budget: RequestImageBudget): CoreImageBudget {\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 * Request options under one budget rung: the surface's durable marks become\n * placeholder text, and an over-budget history FAILS with the count to offload\n * instead of being evicted here. Throws rather than returning, so no caller can\n * accidentally send a body this route already knows is too large.\n *\n * The next rung is applied to the CURRENT projection, never to the raw history —\n * otherwise the 413 retry could reintroduce images the first rung had already\n * evicted.\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.\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).\n */\nasync function readRequestImage(\n attachments: AttachmentStore,\n ref: ImageAttachmentRef,\n): Promise<Uint8Array> {\n return (await attachments.readImageRequest(ref, requestImageTarget(ref))).data\n}\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 (the same placeholder text rides in every later request). A retained\n * occurrence on this route contributes no text at all — the pixels are inlined —\n * so its price is the family's visual-token count and nothing else.\n */\nfunction priceRequestImage(\n block: ImageBlock,\n model: string,\n imageCapable: boolean,\n): LlmImageRequestPrice {\n const ref = block.attachment\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 RequestMessage[],\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 const result = toolResultOf(message)\n if (message.role === 'user' && !result) {\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 // Both modern tool messages and legacy wrapped results use the same view.\n if (result) {\n if (!paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\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(result.toolCallId) ?? result.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(result.toolCallId) || 'unknown',\n output: result.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 RequestMessage[],\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 const result = toolResultOf(message)\n if (message.role === 'user' && !result) {\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 // Both modern tool messages and legacy wrapped results use the same view.\n if (result) {\n if (!paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\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(result.toolCallId) ?? result.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 * Whether requests enforce zero data retention by sending the\n * `x-cmd-zdr: 1` header (the same opt-in the official CLI exposes as\n * `CMD_ZDR=1`). Default false. Every chat request carries the header when\n * enabled. The provider refuses a model without a ZDR-capable upstream with\n * 422 `cmd_zdr_no_providers`; never retry that request without the header.\n * The decision endpoint (`/provider/v1/systemone`) is deliberately never\n * reached through this connection option — see `./systemone.ts`.\n */\n zdr?: boolean\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/**\n * Why a pre-stream rejection rotates to another account. `rate-limit` (a usage\n * window the provider NAMED), `throttled` (a 429 that named no window) and\n * `invalid-credential` are the three the pool records as marks; `unavailable`\n * is an account-scoped rejection that must NOT become a mark — the account's\n * key is valid and its windows may be open, the ACCOUNT just cannot serve THIS\n * request (no credits, a model outside its plan) — so the pool moves on\n * without remembering anything.\n *\n * The window/throttle split decides what the pool may CLAIM, never whether it\n * rotates: both leave rotation and mark the key, but only a named window lets\n * the pool report an exhausted usage window (issue #54).\n */\nexport type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable'\n\n/** What the rotation hook knows about the request it is rotating within. */\nexport interface AccountRotationContext {\n /** Every API key this request has already used, just-rejected key included. */\n tried: readonly string[]\n /** The provider's own reset time for a `rate-limit` rejection, in millis. */\n resetAtMs?: number\n}\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 before any response body streamed, for an account-scoped reason\n * (see {@link AccountRotationReason}). The host marks that key when the\n * reason warrants it and returns the next account's key to retry with, or\n * `undefined` to surface the failure. Only pre-stream rejections rotate — a\n * mid-stream failure never replays a partially consumed generation against\n * another account.\n *\n * `rotation.tried` lists every key this request has already used (the\n * just-rejected one included). The host must not offer one of them again:\n * with several accounts a rejection that does not mark the key (a plan or\n * balance rejection is model-specific, not account-fatal) would otherwise\n * re-offer the same account on every attempt and the pool could never reach\n * the accounts behind it.\n *\n * `rotation.resetAtMs` carries the provider's own reset time when the\n * rejection body published one, so the host can hold the key out until then\n * instead of waiting for a billing probe to learn the same fact.\n */\n rotateApiKey?: (\n rejectedKey: string,\n rejection: AccountRotationReason,\n connection: C,\n model?: string,\n rotation?: AccountRotationContext,\n ) => Promise<string | undefined>\n /**\n * Every API key the host can serve from, in rotation order and deduplicated\n * — the multi-account pool's own list. The picker's plan filter asks all of\n * them, because the pool (not any single account) is what serves a request;\n * a host without a pool omits this seam and the filter falls back to the key\n * that would serve the current request.\n */\n resolveAccountKeys?: () => Promise<readonly string[]>\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 engine's own\n * `projectOffloadedImages`/`requiredImageOffload`. Injecting a stub is how a\n * test observes the budget rungs a 413 walks.\n */\n imageOffload?: SurfaceImagePolicy\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' | 'invalid-response' | '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), `invalid-response`\n * (every call answered but its body was not usable JSON), or `network`\n * (no HTTP 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 */\ntype UsageEndpointFailure =\n | { kind: 'http'; status: number }\n | { kind: 'invalid-response'; status: number }\n | { kind: 'transport' }\n\nfunction classifyTotalFailure(\n failures: readonly string[],\n failed: readonly UsageEndpointFailure[],\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 if (failed.every((item) => item.kind === 'http' && item.status === 401)) {\n return 'invalid-key'\n }\n if (failed.every((item) => item.kind === 'http' && item.status >= 500)) {\n return 'service-unavailable'\n }\n if (failed.every((item) => item.kind === 'invalid-response')) return 'invalid-response'\n if (failed.every((item) => item.kind === 'transport')) 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 // Enforce ZDR on every chat request when selected. The provider is the\n // routing authority: an unsupported model (or unavailable ZDR capacity)\n // fails with 422 rather than sending the prompt through a retaining upstream.\n // Never omit the header based on a client-side capability snapshot.\n const zdr = connection.zdr === true\n const headers = protocol === 'cli'\n ? {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\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 ...(zdr ? { 'x-cmd-zdr': '1' } : {}),\n ...attributionHeaders(),\n }\n : {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\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. ZDR is the one header both\n // transports share: the Provider API documents `x-cmd-zdr: 1`\n // itself (commandcode.ai/docs/provider#zero-data-retention-zdr).\n ...(zdr ? { 'x-cmd-zdr': '1' } : {}),\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 /** Provider spelling, retained for terminal diagnostics rather than inferred from usage. */\n finishReason: string | undefined\n /**\n * command-code@1.65.2's standalone cache-write reading. The finish event's\n * totalUsage can report zero even though the request wrote cache entries;\n * the official CLI keeps this last valid event and uses it only as the\n * zero/missing fallback.\n */\n cliCacheWriteTokens: number | undefined\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 finishReason: undefined,\n cliCacheWriteTokens: undefined,\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 /**\n * The durable-offload contract, resolved once (tests may inject a stub). The\n * contract cannot change while the process runs.\n */\n private readonly surfaceOffload: SurfaceImagePolicy\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.surfaceOffload = deps.imageOffload ?? ENGINE_IMAGE_POLICY\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 ImageBlock[]) =>\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', ...IDENTITY_ENCODING_HEADER, ...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 no account in the pool can run. Fails open —\n // a billing-fetch problem, an unknown plan, or a positive on-demand\n // balance all keep the catalog visible, and the server remains the final\n // gate (403 MODEL_NOT_IN_PLAN). The catalog itself is never filtered:\n // resolveModel still serves every model.\n //\n // EVERY account's entitlement is consulted, not just the one that happens\n // to serve right now (issue #51's follow-up: 《卡片会切换》). Keying the\n // filter on the serving account made the picker's contents depend on which\n // account rotation had reached — a Pro model vanished while a Go account\n // served and came back later — and it hid models the user's OTHER accounts\n // could run, which no request could ever fix. The union is the honest\n // question for a pool, and it only works together with the entitlement\n // rotation in the connect loop: a model offered here because SOME account\n // includes it is served there by that account, after at most one rejected\n // attempt.\n const accesses = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess()\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) => modelVisibleForAnyAccount(model.id, accesses))\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 // Both Command Code transports send the complete active tool declaration\n // list on every request. They do not need a provider-native deferred\n // tool marker, but they can still consume the rc.2 harness projection:\n // `tool-addition` messages are ignored by the wire converters and the\n // projected `options.tools` already contains the newly active schema.\n // Advertising addition-only lets dsh keep one conversation/request\n // series when a plugin enables a tool mid-session; removals are handled\n // by omission from that active list, not by a removal event.\n toolUpdate: 'addition-only' 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 raw = apiKey ?? (await this.deps.resolveApiKey(connection))\n // The chat path validates the key through the harness's own helper (see\n // `resolveApiKey` in the plugin entry); every account endpoint must run the\n // same check, or a key carrying a character no HTTP header can hold throws\n // inside `fetch` BEFORE any I/O — once per endpoint — and the report reads\n // as \"the network is down\". The credential reference is read structurally:\n // it belongs to the host's resolved options, not to this adapter's\n // connection type, and it only names the key in the rejection message.\n const named = (connection as { apiKeyEnv?: unknown }).apiKeyEnv\n const ref = typeof named === 'string' && named !== '' ? named : 'the stored credential'\n const key = assertUsableApiKey(raw, 'llm-commandcode', ref)\n return {\n Authorization: `Bearer ${key}`,\n ...IDENTITY_ENCODING_HEADER,\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 invalid JSON bodies come\n * back without a record; only a fetch failure propagates to the caller.\n *\n * `timeoutMs` is the caller's budget for this one request. The default is the\n * CATALOG probe's short cap, which fits the picker's fail-open reads; the\n * usage report deliberately passes the connection's own request budget so an\n * account query is not held to a stricter (and invisible) limit than chat.\n */\n private async fetchEndpointJson(\n url: string,\n headers: Record<string, string>,\n timeoutMs: number = MODELS_TIMEOUT_MS,\n ): Promise<{ status: number; record?: Record<string, unknown>; invalidResponse?: boolean }> {\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(timeoutMs),\n })\n if (!response.ok) return { status: response.status }\n let parsed: unknown\n try {\n parsed = await response.json()\n } catch {\n return { status: response.status, invalidResponse: true }\n }\n return isRecord(parsed)\n ? { status: response.status, record: parsed }\n : { status: response.status, invalidResponse: true }\n }\n\n /**\n * Every account's billing facts behind the picker's plan filter, in the\n * pool's rotation order and cached per key for {@link BILLING_ACCESS_TTL_MS}\n * (so the extra accounts cost their three requests once per TTL, not once\n * per picker load). `undefined` means the filter cannot be evaluated at all\n * — no key resolved — which {@link modelVisibleForAnyAccount} reads as\n * \"show everything\".\n *\n * The serving account is only the first entry: with several accounts the\n * model list must not depend on which of them rotation happens to be using.\n */\n private async loadPoolBillingAccess(): Promise<readonly (CommandCodeBillingAccess | undefined)[] | undefined> {\n const keys = await this.poolAccountKeys()\n if (keys.length === 0) return undefined\n return Promise.all(keys.map((key) => this.loadBillingAccessForKey(key)))\n }\n\n /**\n * The API keys the picker's plan filter must consult: every account the host\n * can serve from, in rotation order, when the host exposes one. A host\n * without a pool (or without the seam) reports just the key that would serve\n * this request — exactly the pre-pool behaviour.\n */\n private async poolAccountKeys(): Promise<readonly string[]> {\n try {\n const keys = await this.deps.resolveAccountKeys?.()\n const usable = (keys ?? []).filter((key) => typeof key === 'string' && key !== '')\n if (usable.length > 0) return usable\n } catch {\n // Fall through to the single-key answer below.\n }\n try {\n return [await this.deps.resolveApiKey(this.deps.options())]\n } catch {\n return []\n }\n }\n\n /**\n * One account's billing facts, cached for {@link BILLING_ACCESS_TTL_MS} and\n * shared across concurrent callers. `undefined` means \"unknown — show\n * everything\" (fail-open).\n */\n private async loadBillingAccessForKey(apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\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 * Two failure modes are NOT \"the network is down\", and the report must say\n * so rather than let {@link classifyTotalFailure} blame the connection:\n *\n * - A key that no HTTP header can carry (a stray newline from a paste, a\n * full-width character) makes `fetch` throw a `TypeError` **before any\n * I/O**, for every endpoint at once. The chat path refuses such a key\n * through `assertUsableApiKey`; this path must too, and it answers\n * `blocked: 'invalid-key'` instead of four phantom transport failures.\n * - The four endpoints get the SAME per-request budget as a chat call\n * (`connection.requestTimeoutMs`, default 60 s), not the catalog's 10 s\n * probe budget: on a slow link a 10 s cap made every account query time\n * out while chat kept working, which is exactly a \"check your network\"\n * banner that never clears.\n */\n async getUsage(apiKey?: string): Promise<CommandCodeUsageReport> {\n const connection = this.deps.options()\n const base = connection.apiBase\n let headers: Record<string, string>\n try {\n headers = await this.accountHeaders(apiKey)\n } catch (error: unknown) {\n // An unusable key is a CREDENTIAL verdict, not a transport one. A\n // missing key still propagates (the caller renders the unconfigured\n // state); only the harness's own \"characters no header can carry\"\n // rejection — and a blank resolved key — becomes `invalid-key`.\n if (error instanceof LlmError && error.code === 'INVALID_CREDENTIAL') {\n return { failures: [error.message], blocked: 'invalid-key' }\n }\n throw error\n }\n const failures: string[] = []\n // Keep received-but-unreadable bodies separate from requests that never\n // received a response. The former used to be counted as \"network\".\n const failed: UsageEndpointFailure[] = []\n\n const getJson = async (path: string): Promise<Record<string, unknown> | undefined> => {\n try {\n const { status, record, invalidResponse } = await this.fetchEndpointJson(\n `${base}${path}`,\n headers,\n connection.requestTimeoutMs,\n )\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}${invalidResponse ? ' returned an unreadable or invalid JSON body' : ''}`)\n failed.push(invalidResponse ? { kind: 'invalid-response', status } : { kind: 'http', status })\n return undefined\n }\n return record\n } catch (error: unknown) {\n failures.push(`${path}: ${error instanceof Error ? error.message : String(error)}`)\n failed.push({ kind: 'transport' })\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, failed)\n if (blocked !== undefined) report.blocked = blocked\n\n return report\n }\n\n /**\n * Probe one account's real usage windows from `/alpha/billing/credits`. The\n * multi-account pool calls this when every account is marked exhausted: an\n * account whose windows no longer report `exceeded` is revived, and the\n * `resetAt` values feed the \"earliest reset\" error message.\n *\n * BOTH windows the endpoint publishes are read, not just `fiveHour`. An\n * account can have an open five-hour window and an exhausted WEEKLY quota at\n * the same time (the two are metered separately), and reading only the\n * shorter one revived such an account as \"usable\" — the pool then handed it\n * out, the provider rejected the request again, and the next all-marked pass\n * revived it once more, so a used-up account kept coming back (issue #51's\n * follow-up: \"切到一个不可用账号\"). `exceeded` is therefore true when ANY\n * published window is exceeded, and `resetAt` is the LATEST reset among the\n * exceeded ones — the binding constraint, because a clear five-hour window\n * buys nothing while the weekly quota is spent.\n *\n * Returns `undefined` when the probe itself failed (transport, non-200, or a\n * payload with no window limits at all) — a failed probe never changes pool\n * state. The monthly/purchased/free credit balances are deliberately NOT part\n * of this answer: they are balances rather than windows, they carry no reset\n * time, and the server remains the final gate on them.\n */\n async probeWindowLimits(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 if (windowLimits === undefined) return undefined\n let reported = false\n let exceeded = false\n let resetAt = 0\n for (const raw of [windowLimits.fiveHour, windowLimits.weekly]) {\n const window = isRecord(raw) ? parseWindowLimit(raw) : undefined\n if (window === undefined) continue\n reported = true\n if (!window.exceeded) continue\n exceeded = true\n // Same untrusted-magnitude rule as the rejection body's reset: a value\n // beyond the horizon is not a reset this route can act on, and pinning\n // a cooldown to it would keep the account out of rotation for the life\n // of the process (nothing probes a `cooldown`). Dropping it leaves the\n // mark `unknown`, which the next probe pass re-checks.\n if (window.resetAt > 0 && window.resetAt - Date.now() <= MAX_TRUSTED_RESET_MS) {\n resetAt = Math.max(resetAt, window.resetAt)\n }\n }\n // No window in the payload at all: nothing can be concluded, so the\n // caller keeps the mark (fail-safe, exactly like a failed probe).\n if (!reported) return undefined\n return { exceeded, resetAt: exceeded ? 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 // The session surface owns the offload set, so this throws\n // `IMAGE_OFFLOAD_REQUIRED` when more images must go; the retry then arrives\n // with the surface already updated.\n let requestOptions = withSurfaceOffload(options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[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 asks for another offload. Safe like the\n // rotation below: nothing streamed and the same key stays in use. The\n // stricter rung becomes another offload request rather than a local edit,\n // so the extra omissions are recorded on the session and survive the\n // retry. Zero here means the images are already gone and the body is\n // simply too big — fall through to the 413 diagnosis instead of asking\n // for an offload that cannot happen, which is also what keeps the branch\n // from looping.\n if (attempt.status === 413 && REQUEST_IMAGE_BUDGETS.length > 1) {\n const missing = this.surfaceOffload.requiredImageOffload(\n requestOptions.messages,\n coreBudget(REQUEST_IMAGE_BUDGETS[1]!),\n imageVersionBytes,\n )\n if (missing > 0) throw imageOffloadRequired(missing)\n }\n const rotate = this.deps.rotateApiKey\n // Account-scoped rejection (429/RATE_LIMITED, 401, or \"this account\n // cannot serve\"): retry the same body with another account when the host\n // has one. The tried set travels along so a rejection that does not mark\n // the key cannot make the pool re-offer it forever.\n const rejection = classifyAccountRejection(attempt.status, attempt.errText)\n if (\n rejection !== undefined\n && rotate !== undefined\n && options.signal?.aborted !== true\n && tried.size < MAX_ACCOUNT_ROTATIONS\n ) {\n const next = await rotate(apiKey, rejection.reason, connection, options.model, {\n tried: [...tried],\n ...(rejection.resetAtMs !== undefined && { resetAtMs: rejection.resetAtMs }),\n })\n if (next !== undefined && !tried.has(next)) {\n apiKey = next\n continue\n }\n }\n // The provider named a window limit — or refused the request as a plain\n // throttle — and no other account could serve. The turn must fail as a\n // RATE_LIMIT carrying that reset rather than as the generic\n // `PROVIDER_HTTP_ERROR` this status maps to: the CLI accepts the\n // `RATE_LIMITED` code on ANY status (a 400 is pinned by a test above), and\n // `PROVIDER_HTTP_ERROR` sits outside dsh-llm-retry's whitelist — so\n // without this the turn dies on the spot even though the provider said\n // exactly when the same request would work again.\n //\n // The two reasons keep their own wording: only a NAMED window may be\n // described as a spent window (issue #54), while a plain throttle says\n // what it is and leaves the window verdict to the pool's own diagnosis.\n //\n // A status that already maps to RATE_LIMIT (a plain 429) keeps the\n // mapping it had — `generateHttpError` owns the `Retry-After` header's cap\n // and finiteness rules there, and its tests pin them — unless the body\n // named its own reset, which is more precise.\n if (\n rejection !== undefined\n && (rejection.reason === 'rate-limit' || rejection.reason === 'throttled')\n && (rejection.resetAtMs !== undefined || attempt.status !== 429)\n ) {\n const reset = rejection.resetAtMs\n const wait = reset === undefined\n ? 0\n : Math.min(Math.max(1000, reset - Date.now()), RETRY_MAX_DELAY_MS)\n const when = reset === undefined ? undefined : new Date(reset).toISOString()\n const window = rejection.reason === 'rate-limit'\n throw new LlmError(\n (window\n ? 'llm-commandcode: the Command Code account is rate limited'\n : 'llm-commandcode: the Command Code account is rate limited (429)'\n + ' — the provider did not report an exhausted usage window')\n + (when === undefined ? '' : ` — the provider reports it resets at ${when}`)\n + (window\n ? ';当前 Command Code 账户已被限流'\n : ';当前 Command Code 账户被限流(429),服务商未报告用量窗口用尽')\n + (when === undefined ? '' : `,服务商给出的重置时间为 ${when}`),\n 'RATE_LIMIT',\n wait > 0 ? { providerRetryAfterMs: wait } : undefined,\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 // Raw-stream trace (opt-in via `DSH_COMMANDCODE_TRACE`): the only artifact\n // that can tell \"the provider closed this stream\" apart from \"our parser\n // missed the terminal event\" — see ./stream-trace.ts for why that\n // distinction is the whole diagnosis. Off, this is one environment read and\n // every call below is inert.\n const trace = openStreamTrace(`${options.provider}/${options.model}`)\n const streamStartedAt = Date.now()\n let chunkCount = 0\n let totalBytes = 0\n let lastChunkAt = streamStartedAt\n trace.record('response', {\n protocol,\n endpoint: protocol === 'cli'\n ? `${connection.apiBase}/alpha/generate`\n : `${connection.apiBase}/provider/v1/chat/completions`,\n status: response.status,\n attempts: tried.size,\n maxTokens,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n })\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 let finish: Extract<StreamChunk, { type: 'finish' }> | undefined\n let usage: TokenUsage | undefined\n let usageEmitted = false\n let endRecorded = false\n // Do not publish success until the assembled answer has been checked.\n // DSH converts an adapter throw into an error finish; throwing AFTER a\n // success finish would violate its single-terminal-event contract.\n function* handle(event: unknown): Generator<StreamChunk> {\n for (const chunk of handleEvent(asm, protocol, event)) {\n if (chunk.type === 'finish') finish = chunk\n else if (chunk.type === 'usage') usage = chunk.usage\n else yield chunk\n }\n }\n try {\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 trace.record('read-error', {\n chunks: chunkCount,\n bytes: totalBytes,\n silentMs: Date.now() - lastChunkAt,\n message: errorChain(error),\n })\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 trace.record('eof', {\n chunks: chunkCount,\n bytes: totalBytes,\n silentMs: Date.now() - lastChunkAt,\n totalMs: Date.now() - streamStartedAt,\n finishSeen: finish !== undefined,\n idleFired,\n buffered: buffer.length,\n })\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; it uses the same\n // terminal validation as events parsed in the line loop.\n yield* handle(parseStreamEventLine(buffer))\n }\n break\n }\n const text = decoder.decode(value, { stream: true })\n buffer += text\n chunkCount += 1\n totalBytes += value.byteLength\n lastChunkAt = Date.now()\n trace.record('chunk', {\n n: chunkCount,\n bytes: value.byteLength,\n text: boundTraceText(text),\n })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n yield* handle(parseStreamEventLine(line))\n }\n if (finish !== undefined) break\n }\n // Preserve the provider's usage even when this attempt fails. Usage is\n // cumulative, so only the latest sample is emitted, before the terminal.\n if (usage !== undefined) {\n usageEmitted = true\n yield { type: 'usage', usage }\n }\n if (finish !== undefined) {\n const failure = asm.sawContent ? undefined : emptyCompletionError(asm.finishReason, maxTokens, usage)\n trace.record('end', {\n outcome: failure === undefined ? 'finished' : failure.code === 'OUTPUT_TOKEN_LIMIT' ? 'output-token-limit' : 'empty',\n finishReason: asm.finishReason,\n ...(failure === undefined ? {} : { code: failure.code }),\n maxTokens,\n ...(usage === undefined ? {} : { usage }),\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: Date.now() - streamStartedAt,\n sawContent: asm.sawContent,\n })\n endRecorded = true\n if (failure !== undefined) throw failure\n yield finish\n } else {\n // The stream ended without its terminal event, and that is NOT a normal\n // ending — it must not be reported as one. Both transports terminate\n // explicitly (the CLI transport with a `finish` event, the Provider API\n // with a final `finish_reason` chunk), so an EOF here means the\n // response was closed mid-generation: the gateway, an intermediary\n // proxy, or the network. Synthesizing a clean `stop` is what turned a\n // truncated answer into a turn that just ended, with nothing in the UI\n // or the session log saying why. `dsh-llm-deepseek`'s `translate()`\n // raises this same code for this same condition (\"… stream ended before\n // message_stop\").\n const elapsed = Date.now() - streamStartedAt\n const detail = `${chunkCount} chunk(s), ${totalBytes} bytes, ${elapsed}ms`\n trace.record('end', {\n outcome: asm.sawContent ? 'stream-closed' : 'empty',\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: elapsed,\n sawContent: asm.sawContent,\n })\n endRecorded = true\n if (!asm.sawContent) {\n // Nothing usable came out of it (no visible text, no tool call): the\n // request has no tool action to replay, and this code is in the retry\n // policy's whitelist — the cut is absorbed instead of surfaced. A cut\n // during a long thinking phase lands here.\n throw new LlmError('Command Code returned an empty response;Command Code 返回了空响应,重试通常可恢复', 'EMPTY_RESPONSE')\n }\n throw new LlmError(\n `Command Code API stream from ${connection.apiBase} ended before its finish event (${detail})`\n + ' — the response was closed mid-generation, so this is not the model stopping by itself'\n + ';Command Code API 流式响应在结束事件之前被关闭(生成中途断流),并非模型主动结束——请重试'\n + `;若频繁出现,可用 ${STREAM_TRACE_ENV}=<文件路径> 抓取原始流以定位断流原因`,\n 'STREAM_CLOSED',\n )\n }\n } catch (error: unknown) {\n // A later read/provider error must not discard usage already received.\n if (!usageEmitted && usage !== undefined) yield { type: 'usage', usage }\n if (!endRecorded) {\n trace.record('end', {\n outcome: options.signal?.aborted ? 'aborted' : 'error',\n code: error instanceof LlmError ? error.code : 'unknown',\n finishReason: asm.finishReason,\n maxTokens,\n ...(usage === undefined ? {} : { usage }),\n sawContent: asm.sawContent,\n chunks: chunkCount,\n bytes: totalBytes,\n totalMs: Date.now() - streamStartedAt,\n })\n }\n throw error\n } finally {\n clearIdle()\n cleanup()\n trace.close()\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 === 422 && isZdrNoProviders(providerCode, providerDetail, errText)) {\n // Zero data retention refused (the `zdr` connection option is on): either\n // this model has no ZDR-capable upstream, or none had capacity at that\n // moment. Bilingual — the harness UI renders this message verbatim. The\n // code is matched shape-insensitively because the provider spells it both\n // ways (`cmd_zdr_no_providers` in the JSON error body, `CMD_ZDR_NO_PROVIDERS`\n // in plain-text ones, exactly as the official CLI's classifier reads it),\n // and the CLI's own user guidance is to unset CMD_ZDR.\n return new LlmError(\n `Command Code API error 422 (${detail}): zero data retention is enforced but no ZDR-capable`\n + ' upstream is available for this model — turn the ZDR setting off (or use another model)'\n + ';Command Code API 返回 422:已开启零数据保留(ZDR),但该模型当前没有可用的 ZDR 上游——'\n + '请关闭 ZDR 开关,或改用其他模型',\n 'PROVIDER_HTTP_ERROR',\n { status: 422 },\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 if (delta.trim() !== '') 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 'cache-write-tokens': {\n const cacheWrite = numberValue(event.cacheWriteTokens)\n if (cacheWrite !== undefined && cacheWrite >= 0) asm.cliCacheWriteTokens = cacheWrite\n break\n }\n case 'finish': {\n asm.finishReason = stringValue(event.finishReason)\n chunks.push(...closeText(asm), ...closeReasoning(asm))\n const usage = isRecord(event.totalUsage) ? event.totalUsage : undefined\n const capturedCacheWrite = asm.cliCacheWriteTokens\n if (usage || capturedCacheWrite !== undefined) {\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 reportedCacheWrite = numberValue(details?.cacheWriteTokens) ?? 0\n const cacheWrite = reportedCacheWrite === 0 && capturedCacheWrite !== undefined\n ? capturedCacheWrite\n : reportedCacheWrite\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 const outputDetails = isRecord(usage?.outputTokenDetails) ? usage.outputTokenDetails : undefined\n const reasoningTokens = numberValue(outputDetails?.reasoningTokens) ?? numberValue(usage?.reasoningTokens)\n if (reasoningTokens !== undefined) tokenUsage.reasoningTokens = reasoningTokens\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, GLM/Qwen/\n // Kimi answer with the DeepSeek-native `reasoning_content`, and the OpenAI\n // family answers with the scalar `reasoning` PLUS a `reasoning_details` array\n // whose entry is `{ type: 'reasoning.summary', summary }`. All three\n // spellings are read here, in that order, so no family's thinking is dropped\n // (measured live 2026-09-18, gpt-5.6-luna, 6/6 rounds: the scalar and the\n // array's `summary` carried the identical text every time). The\n // `reasoning_details` branch is a forward guard rather than the live path for\n // any family — every family that sends the array also sends a scalar\n // alongside it — so it only carries the text if that ever stops; it reads\n // `summary` as well as `text` precisely so the guard covers the family whose\n // array uses the other member.\n const reasoningDelta =\n nonEmptyText(stringValue(delta.reasoning))\n ?? nonEmptyText(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 if (contentDelta.trim() !== '') asm.sawContent = true\n chunks.push({ type: 'text-delta', index: asm.textIndex, text: contentDelta })\n }\n\n if (Array.isArray(delta.tool_calls)) {\n for (const rawCall of delta.tool_calls) {\n if (!isRecord(rawCall)) continue\n asm.sawContent = true\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 asm.finishReason = stringValue(choice.finish_reason)\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/** A terminal marker without text or tools is a failed attempt, not a completed turn. */\nfunction emptyCompletionError(reason: string | undefined, maxTokens: number, usage: TokenUsage | undefined): LlmError {\n const detail = `finish_reason=${reason ?? 'unknown'}, max_tokens=${maxTokens}, outputTokens=${usage?.outputTokens ?? 'unknown'}, reasoningTokens=${usage?.reasoningTokens ?? 'unknown'}`\n if (mapFinishReason(reason).kind === 'max-tokens') {\n // A length finish proves a generation limit, not how all tokens were spent.\n // Keep this outside the retry whitelist: replaying the identical budget\n // can repeatedly charge for reasoning without ever producing an answer.\n return new LlmError(\n `Command Code reached the output token limit without producing answer text or a tool call (${detail})`\n + ';Command Code 已达到输出 token 上限,但没有生成正文或工具调用;请调整思考强度,或在模型和接口上限内增加输出预算',\n 'OUTPUT_TOKEN_LIMIT',\n )\n }\n if (reason === 'content_filter' || reason === 'content-filter') {\n return new LlmError(`Command Code filtered the response (${detail});Command Code 拦截了响应,未生成正文或工具调用`, 'CONTENT_FILTER')\n }\n return new LlmError(\n `Command Code finished without producing answer text or a tool call (${detail})`\n + ';Command Code 返回了空响应(可能只有思考内容),重试通常可恢复',\n 'EMPTY_RESPONSE',\n )\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 */\n/**\n * Classify a pre-stream rejection that is about the ACCOUNT rather than about\n * the request, using the official CLI's own rules (command-code@1.56.0:\n * `parseWindowLimitError`, `isInsufficientCreditsRequestError`,\n * `parseSpendCapError` and the terminal-marker list\n * `[\"premium_credits_exhausted\", \"model_not_in_plan\", \"insufficient credits\"]`).\n * Undefined means \"not an account-scoped rejection\": a malformed request, an\n * oversized body or a context overflow must fail fast instead of walking the\n * whole account pool.\n *\n * Issue #51's follow-up is why this exists. Only 429/401 used to rotate, so\n * every other account-scoped rejection was terminal AND invisible to the pool:\n * an account that could not pay, or could not run the model, stayed \"usable\",\n * was handed out again on the next request, and produced the same error again\n * (\"切到一个不可用账号后就报 400,还挺频繁\"). The three reasons differ in what\n * the host should do with them, which is the caller's decision, not this\n * function's:\n *\n * - `rate-limit`: a usage WINDOW is spent. The code `RATE_LIMITED` is the\n * authoritative signal — the CLI accepts the code OR a 429 status — and the\n * body's `error.rateLimit` names the window and its `reset` (in seconds),\n * so the host can hold the account out until the provider's own reset time.\n * - `throttled`: the provider refused the request (429 or a bare\n * `RATE_LIMITED` code) without naming a usage window. It is account-scoped\n * like the above, so it rotates and marks the key the same way, but it is\n * NOT evidence that a metered window is spent: the CLI's own\n * `parseWindowLimitError` returns a window limit only when\n * `resolveWindowLabel` can name one, and a burst/model/spend limiter the\n * billing endpoint cannot see is exactly this shape (issue #54's report: a\n * 429 whose probe read five-hour 2% and weekly 10% while the error claimed\n * both were exhausted).\n * - `invalid-credential`: 401; the key itself is bad.\n * - `unavailable`: the key is fine but this account cannot serve: no credits\n * (`400 Insufficient credits`, the codes `INSUFFICIENT_CREDITS`,\n * `USAGE_EXCEEDED`, `PREMIUM_CREDITS_EXHAUSTED`, or a spend-cap wording)\n * or a model outside its plan (`MODEL_NOT_IN_PLAN`). Rotating must NOT mark\n * the account: the fact is about the model or the balance, it can change\n * without the key changing, and a `:free` model can still be served by an\n * account with an empty balance. These codes are recognized on EVERY\n * status — a 5xx that proxies the provider's own credits/plan body is\n * still an account fact, and only the prose scan is confined to 4xx.\n */\n\n/**\n * The provider's structured \"this account cannot serve this request\" codes.\n *\n * Status-independent on purpose, mirroring the CLI's classifier, which reads\n * the code before any status guard. A 5xx that carries one of these must not\n * be retried as a transient provider failure: the same request against the\n * same account cannot succeed, so the caller rotates past it (without marking\n * the key) instead of replaying it on the harness's retry cadence.\n */\nconst ACCOUNT_UNAVAILABLE_CODES: ReadonlySet<string> = new Set([\n 'USAGE_EXCEEDED',\n 'INSUFFICIENT_CREDITS',\n 'PREMIUM_CREDITS_EXHAUSTED',\n 'MODEL_NOT_IN_PLAN',\n])\n\nfunction classifyAccountRejection(status: number, errText: string): { reason: AccountRotationReason; resetAtMs?: number } | undefined {\n if (status === 429 || readProviderErrorCode(errText)?.toUpperCase() === 'RATE_LIMITED') {\n const evidence = readWindowLimitEvidence(errText)\n // A plain throttle carries no reset: an `error.rateLimit.reset` without a\n // window label is the provider saying \"come back later\", not \"this window\n // is spent\", and a mark pinned to it would be a window claim the body never\n // made.\n if (evidence.window === undefined) return { reason: 'throttled' }\n return evidence.resetAtMs === undefined\n ? { reason: 'rate-limit' }\n : { reason: 'rate-limit', resetAtMs: evidence.resetAtMs }\n }\n if (status === 401) return { reason: 'invalid-credential' }\n // The structured account codes are checked BEFORE the status guard, exactly\n // like `RATE_LIMITED` above: a gateway that proxies the provider's own\n // credits/plan rejection under a 5xx is still reporting a fact about this\n // account, and treating it as \"the provider is unavailable\" is what turned a\n // permanent refusal into a retried one — `SERVER` reaches dsh-llm-retry's\n // 1000-attempt cadence while the sibling accounts that could serve are never\n // consulted. The guard below therefore covers only the rejections with NO\n // such code, whose evidence is prose: a bare 5xx (or a status under 400) is\n // the provider being unavailable and must keep its retry cadence for every\n // account instead of being remembered against one. `tests/adapter.test.ts`\n // pins both halves.\n const code = readProviderErrorCode(errText)?.toUpperCase()\n if (code !== undefined && ACCOUNT_UNAVAILABLE_CODES.has(code)) return { reason: 'unavailable' }\n if (status < 400 || status >= 500) return undefined\n // Underscored and spaced spellings are the same words: a JSON body carries\n // `insufficient_credits` / `model_not_in_plan`, while the CLI's own marker\n // list is written with spaces. Normalizing the separator keeps both wire\n // spellings classified, and the explicit code list above covers a body that\n // carries a code and no message at all — which is exactly how the code-only\n // `INSUFFICIENT_CREDITS` body slipped through before.\n const lower = errText.toLowerCase().replaceAll('_', ' ')\n if (\n lower.includes('insufficient credits')\n || lower.includes('premium credits exhausted')\n || lower.includes('model not in plan')\n || /insufficient (credit|balance)/.test(lower)\n || /out of credit/.test(lower)\n || /not (available|included)[^.]{0,40}plan/.test(lower)\n || lower.includes('upgrade your plan')\n ) {\n return { reason: 'unavailable' }\n }\n return undefined\n}\n\n/** The machine-readable `error.code`/`error.type` of a pre-stream failure body. */\nfunction readProviderErrorCode(errText: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(errText)\n if (!isRecord(parsed)) return undefined\n const error = isRecord(parsed.error) ? parsed.error : parsed\n return stringValue(error.code) ?? stringValue(error.type)\n } catch {\n return undefined\n }\n}\n\n/**\n * How far ahead a provider-published reset may be and still be trusted.\n *\n * Generous on purpose: the weekly window is the longest this provider meters,\n * and the value is a plausibility bound rather than a policy. Beyond it the\n * reset is dropped rather than clamped, which leaves the account's mark\n * `unknown` — the state the pool's probe pass re-checks — instead of a\n * cooldown that never expires.\n */\nconst MAX_TRUSTED_RESET_MS = 30 * 24 * 60 * 60 * 1000\n\n/**\n * The usage-window evidence carried by a rejected request, mirroring the CLI's\n * `parseWindowLimitError` → `resolveWindowLabel`/`extractResetAtMs` pair.\n *\n * `window` is present only when the body actually names one: a\n * `error.rateLimit.window` of `fiveHour`/`weekly`/`daily`, or the\n * \"usage limit for your plan\" wording (read as `weekly` when it says so, else\n * `fiveHour`). That is the CLI's own bar for calling a rejection a WINDOW\n * limit, and it is what keeps a bare 429 — a burst limiter, a model-level\n * limit, a spend cap `windowLimits` cannot show — from being reported as an\n * exhausted window (issue #54).\n *\n * `resetAtMs` is the reset the body publishes: `error.rateLimit.reset` is\n * SECONDS (`1e3 * reset`, like the CLI), and a `resets at <ISO>` stamp in the\n * message is honored as the fallback. Either can be present without the other;\n * the window label is what decides the classification.\n */\nfunction readWindowLimitEvidence(errText: string): { window?: 'fiveHour' | 'weekly' | 'daily'; resetAtMs?: number } {\n let named: string | undefined\n let message = ''\n let seconds: number | undefined\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed)) {\n const error = isRecord(parsed.error) ? parsed.error : parsed\n const rateLimit = isRecord(error.rateLimit) ? error.rateLimit : undefined\n named = stringValue(rateLimit?.window)\n message = stringValue(error.message) ?? stringValue(parsed.message) ?? ''\n seconds = numberValue(rateLimit?.reset)\n }\n } catch {\n // A plain-text body carries no structured window; the message scan below\n // still reads its `resets at <ISO>` stamp.\n }\n const window = named === 'fiveHour' || named === 'weekly' || named === 'daily'\n ? named\n : /usage limit for your plan/i.test(message) || /usage limit for your plan/i.test(errText)\n ? (/weekly/i.test(message) ? 'weekly' : 'fiveHour')\n : undefined\n const stamp = /resets at (\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z)/i.exec(message)?.[1]\n ?? /resets at (\\d{4}-\\d{2}-\\d{2}T[\\d:.]+Z)/i.exec(errText)?.[1]\n const stamped = stamp === undefined ? undefined : Date.parse(stamp)\n const published = seconds !== undefined && seconds > 0\n ? Math.round(seconds * 1000)\n : stamped !== undefined && !Number.isNaN(stamped) ? stamped : undefined\n // A published reset is UNTRUSTED input, and two things break on a bogus\n // magnitude: `new Date(...).toISOString()` throws `RangeError: Invalid time\n // value` (replacing the intended RATE_LIMIT with an internal error), and a\n // mark pinned beyond the horizon becomes a `cooldown` no probe will ever\n // revisit — the account leaves rotation for the life of the process. A usage\n // window resets within days, so anything further out is not a reset this\n // route can act on: dropping it degrades the mark to `unknown`, which the\n // pool's probe pass re-checks.\n const resetAtMs = published !== undefined\n && Number.isFinite(published)\n && published - Date.now() <= MAX_TRUSTED_RESET_MS\n ? published\n : undefined\n return {\n ...(window === undefined ? {} : { window }),\n ...(resetAtMs === undefined ? {} : { resetAtMs }),\n }\n}\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 | 'blockedInvalidResponse' // received an unreadable response body\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 blockedInvalidResponse:\n '⚠️ Command Code 返回了无法读取的响应 — 请检查宿主的 HTTP 代理或响应解压配置',\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 blockedInvalidResponse:\n '⚠️ Command Code returned an unreadable response — check the host HTTP proxy or response decoding',\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 === 'invalid-response') {\n lines.push(commandCopy(locale, 'blockedInvalidResponse'), '')\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 */\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.\n *\n * `mode: 'strict'` carries a LAZY schema factory (`create()`), which the\n * registry requires and the Gateway validates with (`codec.create().parse`).\n * The schema is built by `makeStrictCodec` from the endpoint's hand-rolled\n * validator, so nothing here depends on a generated codec.\n */\ninterface StrictCodec<Output> {\n readonly mode: 'strict'\n readonly typeSymbol: string\n readonly create: () => TypertSchema<Output>\n}\n\n/** Use the same strict-codec shape for invocation parameters and results. */\nexport function makeStrictCodec<Output>(typeSymbol: string, schema: TypertSchema<Output>): StrictCodec<Output> {\n return { mode: 'strict', typeSymbol, create: () => schema }\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: makeStrictCodec(typeSymbol, 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 === 'invalid-response' || 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 // Every Host contribution must carry its reflection model. This hand-written\n // Remote deliberately has no generated reflection exports, so use the\n // official empty-model form rather than a cast that would leave registry\n // 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","/**\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 makeStrictCodec,\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/** Optional account target; the Host still checks it against saved slots. */\nconst loginTargetSchema: TypertSchema<string | undefined> = {\n parse(value: unknown): string | undefined {\n if (value === undefined || typeof value === 'string') return value\n return reject('targetRef')\n },\n}\n\n/** Build one login invocation descriptor. Only begin accepts an account ref. */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n const descriptor = makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n return method === 'loginBegin'\n ? {\n ...descriptor,\n parameters: [{\n name: 'targetRef', wire: 'targetRef', source: 'json',\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#CommandCodeLoginTargetRef`, loginTargetSchema),\n acceptsUndefined: true,\n }],\n }\n : descriptor\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(targetRef?: string): 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(targetRef?: string): Promise<CommandCodeLoginStatus> {\n const login = this.requireLogin()\n return login.begin(targetRef)\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 { IDENTITY_ENCODING_HEADER } from './response-encoding.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, targetRef?: string): Promise<void>\n /** Reject an account target that is not a saved slot before opening Studio. */\n validateTargetRef?(targetRef: string | undefined): void\n}\n\n/** Resolve a browser-login destination without allowing arbitrary credential writes. */\nexport function loginCredentialRef(\n targetRef: string | undefined,\n defaultRef: string,\n accounts: readonly { apiKeyEnv?: string }[],\n): string {\n if (targetRef === undefined) return defaultRef\n if (targetRef === defaultRef || !accounts.some((account) => account.apiKeyEnv === targetRef)) {\n throw new Error('the target account must be saved before browser sign-in')\n }\n return targetRef\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', ...IDENTITY_ENCODING_HEADER, 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 start that is still binding its port is REJOINED through\n * {@link CommandCodeLoginFlow.begin}'s in-flight promise, because the status\n * face cannot say `waiting` until that bind settles; a terminal state makes the\n * 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 /**\n * The start currently binding a port, if any. Every `begin()` that arrives\n * before it settles joins it: two independent starts would each bind their\n * own loopback server, and only the LAST one is reachable by\n * {@link CommandCodeLoginFlow.teardown} — the orphan keeps listening and\n * answering `/callback` for the process's lifetime, and ten of them exhaust\n * the port window so browser login dies until the Host restarts.\n */\n private starting: Promise<CommandCodeLoginStatus> | undefined\n /** A live attempt's destination; different rows may not rejoin it. */\n private targetRef: string | undefined\n /** A `cancel()` that arrived while a start was still binding (see {@link CommandCodeLoginFlow.cancel}). */\n private cancelPending = false\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(targetRef?: string): Promise<CommandCodeLoginStatus> {\n if (this.disposed) throw new Error('login flow has been disposed')\n this.deps.validateTargetRef?.(targetRef)\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) {\n if (this.targetRef !== targetRef) throw new Error('another account login is already in progress')\n return this.statusValue\n }\n // ...and rejoin a start that has not published `waiting` yet. Two GUI tabs\n // (or a Sign-in that follows a cancel which arrived too early to retire\n // anything) would otherwise each bind a loopback server; see `starting`.\n if (this.starting !== undefined) {\n if (this.targetRef !== targetRef) throw new Error('another account login is already in progress')\n return this.starting\n }\n this.cancelPending = false\n this.targetRef = targetRef\n const starting = this.startAttempt(targetRef)\n this.starting = starting\n try {\n return await starting\n } finally {\n if (this.starting === starting) this.starting = undefined\n }\n }\n\n /**\n * The binding half of {@link CommandCodeLoginFlow.begin}: one attempt, one\n * server, one published `waiting` status. Callers reach it only through\n * `begin()`'s single-flight fence.\n */\n private async startAttempt(targetRef: string | undefined): Promise<CommandCodeLoginStatus> {\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 // The attempt may have been retired while the port was being bound: a\n // `cancel()` (the panel's ×, or a quick Sign-in → Cancel → Sign-in) cannot\n // see a `waiting` status yet, and a `dispose()` may have unloaded the\n // plugin. Publishing `waiting` now would hand the user a live authUrl they\n // already asked to drop and start a watchdog nobody can reach, so the\n // freshly bound server is closed here instead.\n if (this.disposed || this.cancelPending) {\n const cancelled = !this.disposed\n this.cancelPending = false\n this.teardown()\n if (cancelled) this.setStatus({ state: 'failed', reason: 'cancelled' })\n return this.statusValue\n }\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, targetRef),\n (failure) => this.failFrom(attempt, failure),\n )\n return this.statusValue\n }\n\n /**\n * Cancel a waiting attempt; terminal states are untouched. A start that is\n * still binding a port is flagged instead of ignored — it cannot be torn\n * down from here (its server does not exist yet), so `startAttempt` observes\n * the flag once the bind settles and retires it.\n */\n cancel(): void {\n if (this.disposed) return\n if (this.statusValue.state === 'waiting') {\n this.teardown()\n this.setStatus({ state: 'failed', reason: 'cancelled' })\n return\n }\n if (this.starting !== undefined) this.cancelPending = true\n }\n\n /** Stop everything; a waiting attempt ends cancelled. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.cancelPending = false\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) {\n // Another attempt owns the tracked server. This one is unreachable by\n // every teardown path, so it is closed here — an orphaned listener\n // would answer /callback for the rest of the process's life and hold\n // a port out of the login window.\n closeServer(server)\n return\n }\n this.server = undefined\n // A post-listen error leaves a server that may still be listening;\n // close() is a no-op (safe) when it never bound or is already gone.\n closeServer(server)\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, targetRef: string | undefined): 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 this.deps.validateTargetRef?.(targetRef)\n await this.deps.storeKey(credentials, targetRef)\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 closeServer(this.server)\n this.server = undefined\n this.settle = undefined\n }\n}\n\n/** Close one loopback server without letting \"not running\"/\"already closed\" escape. */\nfunction closeServer(server: Server | undefined): void {\n try {\n server?.close()\n } catch {\n // The server never bound, or was already closed: nothing to release.\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'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.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 * 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 *\n * `preexisting` is the one fact `displaced` cannot carry: an `undefined`\n * `displaced` means EITHER \"the field was unset when we took over\" (give\n * `undefined` back on disable) OR \"the field already read `commandcode`\"\n * (touch nothing on disable — see {@link applyCommandCodeSearchSelection}).\n * Collapsing the two is what turned a user's own `searchProvider: commandcode`\n * pin into an auto-select — and then into `WEB_PROVIDER_AMBIGUOUS` on every\n * search — the moment this plugin was disabled or unloaded.\n */\nexport interface CommandCodeSearchSelection {\n owner: boolean\n displaced: string | undefined\n /** Whether the field already read `commandcode` when this plugin first took it over. */\n preexisting: boolean\n}\n\n/** Fresh selection state: the plugin starts out not owning the selection. */\nexport function commandCodeSearchSelection(): CommandCodeSearchSelection {\n return { owner: false, displaced: undefined, preexisting: false }\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 and\n * `preexisting` is set, so the later disable is a no-op rather than a guess\n * at the factory default. A \"no-op\" means the field is left ALONE: writing\n * that `undefined` back would destroy the user's own pin, and dsh-web reads\n * a cleared `searchProviderId` as auto-select — where a second usable\n * provider (the shipped `deepseek-official` is usable whenever a DeepSeek\n * key resolves) makes EVERY later search throw\n * `WEB_PROVIDER_AMBIGUOUS`.\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 // Three cases, and `displaced` alone cannot tell the last two apart:\n // a sibling's id (restore it), the field was unset (restore `undefined`),\n // or the field already read OUR id (touch nothing — see the disable\n // branch). `preexisting` carries that third case.\n state.preexisting = prior === COMMANDCODE_SEARCH_PROVIDER_ID\n state.displaced = state.preexisting ? 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 // Restore ONLY a selection this plugin actually took over. `preexisting`\n // means the field already read `commandcode` before we ever touched it\n // (a manual `searchProvider: commandcode` patch,\n // `$DSH_WEB_SEARCH_PROVIDER`, or a surviving runtime): assigning the\n // empty memory back would clear the user's own pin and hand the\n // selection to auto-select, which throws `WEB_PROVIDER_AMBIGUOUS` as\n // soon as a second provider is usable — while our own provider stays\n // registered either way.\n if (!state.preexisting) field.searchProviderId = state.displaced\n state.preexisting = false\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 ...IDENTITY_ENCODING_HEADER,\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 configuration files.`,\n hintDescriptions: { zh: `保存在凭据库(${ref}),不会写入配置文件。` },\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: ['commandGuard'],\n group: 'advanced',\n kind: 'boolean',\n label: 'AI command guard',\n descriptions: { zh: 'AI 命令安全预判' },\n hint: 'typesafe/jev judges whether a shell command is safe; sandbox escalations'\n + ' also need separate scope and necessity verdicts. All must be confident'\n + ' enough; everything else asks as usual. Off by default.',\n hintDescriptions: { zh: '由 typesafe/jev 判断 shell 命令是否安全;沙箱提权还要分别判断范围与必要性,三项都足够确定才自动放行,其余照常弹窗。默认关闭。' },\n // Off is the shipped default and the safe reading of an unset document.\n format: (value) => (value === true ? 'true' : 'false'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\n },\n {\n path: ['commandGuardLevel'],\n group: 'advanced',\n kind: 'select',\n label: 'Auto-approve threshold',\n descriptions: { zh: '自动放行阈值' },\n hint: 'How confident typesafe/jev must be before a command runs without asking. Default: medium.',\n hintDescriptions: { zh: 'typesafe/jev 需要多确定才免弹窗放行;默认「中」。' },\n // Mirrors COMMAND_GUARD_LEVELS / COMMAND_GUARD_LEVEL_THRESHOLDS in ./command-guard.ts.\n options: [\n { value: 'high', label: 'High (0.95, approves least)', descriptions: { zh: '高(0.95,放行最少)' } },\n { value: 'medium', label: 'Medium (0.9)', descriptions: { zh: '中(0.9)' } },\n { value: 'low', label: 'Low (0.8, approves most)', descriptions: { zh: '低(0.8,放行最多)' } },\n ],\n format: (value) => (value === 'high' || value === 'low' ? value : 'medium'),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === 'high' || trimmed === 'medium' || trimmed === 'low'\n ? { kind: 'set', value: trimmed }\n : undefined\n },\n },\n {\n path: ['zdr'],\n group: 'advanced',\n kind: 'boolean',\n label: 'Zero data retention (ZDR)',\n descriptions: { zh: '零数据保留(ZDR)' },\n hint: 'Route requests only through upstreams that retain nothing and never'\n + ' train on prompts (the CLI\\'s CMD_ZDR=1). Models without an available'\n + ' ZDR upstream fail instead of losing protection; ZDR is usually'\n + ' billed at higher pass-through rates. Off by default.',\n hintDescriptions: {\n zh: '请求只经由不留存数据、也不用于训练的上游(等价于 CLI 的 CMD_ZDR=1)。'\n + '没有可用 ZDR 上游的模型会报错,不会降级为非 ZDR 请求;'\n + 'ZDR 通常按更高的透传价计费。默认关闭。',\n },\n // Off is the shipped default and the safe reading of an unset document.\n format: (value) => (value === true ? 'true' : 'false'),\n parse: (text) => ({ kind: 'set', value: text.trim() === 'true' }),\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 settings\n // page stays 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 * Host-side client for Command Code's System One decision endpoint\n * (`POST {apiBase}/provider/v1/systemone`).\n *\n * `typesafe/jev` is **not a chat model**: it takes a `state` plus typed\n * questions and answers with probabilities, never text, and it never streams.\n * It is therefore absent from `/provider/v1/models` (so the picker can never\n * offer it) and must never be registered as a model route — this plugin uses it\n * as an internal advisor instead: the command guard in `./command-guard.ts`\n * asks it whether a shell command is safe to auto-approve.\n *\n * The three question types are the whole vocabulary (command-code@1.65.2\n * `systemOneRequestSchema`, unchanged since 1.64.0):\n *\n * - `noul` — \"is this true?\", optional `criteria: { true, false }` describing\n * each verdict. Answers with `noul`, the probability of *yes*.\n * - `choice` — \"which one?\", `criteria` maps each option key to its\n * description. Answers with `choice`, plus optional `confidence` and\n * `probabilities`.\n * - `score` — \"where on this rubric?\", `criteria` is an array of at least two\n * levels, lowest first. Answers with `score`, `legend` and `probabilities`.\n *\n * A request carries at most 20 questions and every answer is keyed by the\n * question id it belongs to. `usage` is reported per request, in tokens.\n *\n * Billing: free through 2026-09-24T23:59:59Z, then $0.042 per 1M input tokens\n * with output free. The model has **no ZDR-capable upstream**, so a request\n * carrying `x-cmd-zdr: 1` is refused with HTTP 422 `cmd_zdr_no_providers` —\n * this client never sends that header, and it must stay that way even though\n * the plugin now ships a ZDR switch for chat (`Config.zdr` → the `x-cmd-zdr: 1`\n * header per model, gated on `KNOWN_NON_ZDR_MODELS`): the decision endpoint is\n * reached through THIS module's own request path, never through the adapter's\n * chat connection, so the two cannot drift — and a deployment that later widens\n * ZDR must exclude this endpoint rather than route it through the switch.\n *\n * Auth is the plugin's ordinary chain (the multi-account pool, the credentials\n * seam, the CLI auth file) through the same `Authorization: Bearer <key>` and\n * `x-command-code-version` headers every other endpoint uses.\n *\n * @module dsh-commandcode-provider/systemone\n */\n\nimport { attributionHeaders } from '@deepseek-ai/dsh-llm'\nimport { COMMAND_CODE_CLI_VERSION } from './adapter.ts'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\n\n/** Path of the decision endpoint, relative to `apiBase`. */\nexport const SYSTEMONE_ROUTE = '/provider/v1/systemone'\n\n/** The one decision model the endpoint serves today (aliases: `jev`, `jev-latest`, `typesafe-ai/jev`). */\nexport const SYSTEMONE_MODEL = 'typesafe/jev'\n\n/** Server-enforced ceiling on questions per request (command-code@1.65.2 `zP`). */\nexport const SYSTEMONE_MAX_QUESTIONS = 20\n\n/** Milliseconds a decision may take before the caller gives up on it. */\nexport const SYSTEMONE_DEFAULT_TIMEOUT_MS = 1500\n\n/** A criterion description: free-form JSON, rendered to the model as context. */\nexport type SystemOneInstructions =\n | string\n | number\n | boolean\n | null\n | readonly SystemOneInstructions[]\n | { readonly [key: string]: SystemOneInstructions }\n\n/** One typed question. The `criteria` shape is fixed by the question's type. */\nexport type SystemOneQuestion =\n | {\n readonly type: 'noul'\n readonly instructions: SystemOneInstructions\n readonly criteria?: { readonly true?: SystemOneInstructions; readonly false?: SystemOneInstructions }\n }\n | {\n readonly type: 'choice'\n readonly instructions: SystemOneInstructions\n readonly criteria: { readonly [option: string]: SystemOneInstructions }\n }\n | {\n readonly type: 'score'\n readonly instructions: SystemOneInstructions\n readonly criteria: readonly SystemOneInstructions[]\n }\n\n/** One decision request: the situation, and the typed questions about it. */\nexport interface SystemOneRequest {\n /** Decision model id; defaults to {@link SYSTEMONE_MODEL} at the call site. */\n readonly model?: string\n /** The situation under judgement — text, or any JSON the question can refer to. */\n readonly state: SystemOneInstructions\n /** Questions keyed by a stable id, echoed in the answers. At most {@link SYSTEMONE_MAX_QUESTIONS}. */\n readonly questions: { readonly [id: string]: SystemOneQuestion }\n}\n\n/** One parsed answer. Only the members this plugin consumes are kept. */\nexport type SystemOneAnswer =\n | { readonly type: 'noul'; readonly noul: number }\n | {\n readonly type: 'choice'\n readonly choice: string\n readonly confidence?: number\n readonly probabilities?: Readonly<Record<string, number>>\n }\n | {\n readonly type: 'score'\n readonly score: number\n readonly confidence?: number\n readonly probabilities?: Readonly<Record<string, number>>\n }\n\n/** Per-request token usage as the endpoint reports it. */\nexport interface SystemOneUsage {\n readonly inputTokens?: number\n readonly outputTokens?: number\n}\n\n/** A parsed decision response. */\nexport interface SystemOneResponse {\n /** The model that answered, when the endpoint echoes one. */\n readonly model?: string\n /** Answers keyed by question id. */\n readonly answers: Readonly<Record<string, SystemOneAnswer>>\n /** Token usage, when the endpoint reports it. */\n readonly usage?: SystemOneUsage\n}\n\n/** Why a decision call produced no usable answer. */\nexport type SystemOneFailureKind =\n /** The request could not be built (no questions, too many, an invalid apiBase). */\n | 'invalid-request'\n /** No usable credential — the pool's own MISSING_CREDENTIAL / invalid-key surface. */\n | 'credential'\n /** The endpoint answered a non-2xx status. */\n | 'http'\n /** The connection failed before a response arrived. */\n | 'network'\n /** The decision did not arrive inside the caller's budget. */\n | 'timeout'\n /** The caller withdrew the request (the approval was answered elsewhere). */\n | 'aborted'\n /** A 2xx body that is not a decision response. */\n | 'invalid-response'\n\n/** The one error type this client throws. Callers fail closed on it. */\nexport class SystemOneError extends Error {\n constructor(\n message: string,\n readonly kind: SystemOneFailureKind,\n readonly status?: number,\n options?: { cause?: unknown },\n ) {\n super(message, options)\n this.name = 'SystemOneError'\n }\n}\n\n/** Everything the client needs beyond the request itself. */\nexport interface SystemOneDeps {\n /** Provider API base URL, read per call (settings-aware). */\n apiBase: () => string\n /** Resolve a usable API key from the plugin's own chain. */\n resolveApiKey: () => Promise<string>\n /** Injectable fetch (tests); defaults to the global `fetch`. */\n fetchImpl?: typeof fetch\n}\n\n/** Deadline plus the reason it fired, so a caller can tell a timeout from a withdrawal. */\ninterface SystemOneDeadline {\n readonly signal: AbortSignal\n /** Whether the caller's own signal was the one that aborted. */\n callerAborted: () => boolean\n /** Whether the timeout was the one that aborted. */\n timedOut: () => boolean\n /** Clear the timer and the caller listener; always called in a `finally`. */\n dispose: () => void\n}\n\n/**\n * Combine the caller's signal with a timeout, keeping the two distinguishable:\n * a timeout is this client's own budget expiring (the guard delegates to the\n * user) while a caller abort means the approval was already withdrawn (answer\n * nothing) — both fail closed, but the diagnosis must not lie about which.\n *\n * The timer is a plain `setTimeout` rather than `AbortSignal.timeout()`, whose\n * timer Node unrefs: with nothing else pending (a test double, a socket that\n * never opened) an unref'd timer lets the process exit while the promise is\n * still pending, which reads as a hang rather than as the timeout it is.\n */\nfunction deadlineOf(signal: AbortSignal | undefined, timeoutMs: number): SystemOneDeadline {\n const controller = new AbortController()\n let timedOut = false\n const timer = setTimeout(() => {\n timedOut = true\n controller.abort()\n }, timeoutMs)\n const onCallerAbort = (): void => controller.abort()\n if (signal !== undefined) {\n if (signal.aborted) controller.abort()\n else signal.addEventListener('abort', onCallerAbort, { once: true })\n }\n return {\n signal: controller.signal,\n callerAborted: () => signal?.aborted === true,\n timedOut: () => timedOut,\n dispose: () => {\n clearTimeout(timer)\n signal?.removeEventListener('abort', onCallerAbort)\n },\n }\n}\n\n/** Whether a caught value is an abort-shaped failure. */\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError')\n}\n\n/** Stop waiting for an operation that does not accept an AbortSignal. */\nfunction withinDeadline<T>(operation: Promise<T>, deadline: SystemOneDeadline, timeoutMs: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => {\n reject(deadline.callerAborted()\n ? new SystemOneError('decision request aborted', 'aborted')\n : new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout'))\n }\n deadline.signal.addEventListener('abort', onAbort, { once: true })\n operation.then(\n (value) => {\n deadline.signal.removeEventListener('abort', onAbort)\n resolve(value)\n },\n (error) => {\n deadline.signal.removeEventListener('abort', onAbort)\n reject(error)\n },\n )\n if (deadline.signal.aborted) onAbort()\n })\n}\n\n/** A finite number in `[0, 1]`, or undefined. */\nfunction probability(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1 ? value : undefined\n}\n\n/** A finite number, or undefined. */\nfunction finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\n/** A record of finite numbers (probabilities), or undefined when the shape is off. */\nfunction numberRecord(value: unknown): Readonly<Record<string, number>> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const out: Record<string, number> = {}\n for (const [key, entry] of Object.entries(value)) {\n const parsed = finite(entry)\n if (parsed === undefined) return undefined\n out[key] = parsed\n }\n return out\n}\n\n/**\n * Parse one answer entry strictly by its own `type`. A body whose answer does\n * not carry the member its type promises is rejected rather than defaulted:\n * an absent probability is exactly the case the caller must not read as \"safe\".\n *\n * @param value - one raw entry from the response's `answers` object.\n * @returns the parsed answer, or undefined when the entry is malformed.\n */\nexport function parseSystemOneAnswer(value: unknown): SystemOneAnswer | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const raw = value as Record<string, unknown>\n if (raw.type === 'noul') {\n const noul = probability(raw.noul)\n return noul === undefined ? undefined : { type: 'noul', noul }\n }\n if (raw.type === 'choice') {\n if (typeof raw.choice !== 'string' || raw.choice === '') return undefined\n const confidence = raw.confidence === undefined ? undefined : probability(raw.confidence)\n if (raw.confidence !== undefined && confidence === undefined) return undefined\n const probabilities = raw.probabilities === undefined ? undefined : numberRecord(raw.probabilities)\n if (raw.probabilities !== undefined && probabilities === undefined) return undefined\n return {\n type: 'choice',\n choice: raw.choice,\n ...(confidence === undefined ? {} : { confidence }),\n ...(probabilities === undefined ? {} : { probabilities }),\n }\n }\n if (raw.type === 'score') {\n const score = finite(raw.score)\n if (score === undefined) return undefined\n const confidence = raw.confidence === undefined ? undefined : probability(raw.confidence)\n if (raw.confidence !== undefined && confidence === undefined) return undefined\n const probabilities = raw.probabilities === undefined ? undefined : numberRecord(raw.probabilities)\n if (raw.probabilities !== undefined && probabilities === undefined) return undefined\n return {\n type: 'score',\n score,\n ...(confidence === undefined ? {} : { confidence }),\n ...(probabilities === undefined ? {} : { probabilities }),\n }\n }\n return undefined\n}\n\n/**\n * Parse a decision response body. Every answer entry must be well formed — one\n * malformed entry fails the whole response, because a partially understood\n * decision is not a decision. Unknown extra members are ignored so a server-side\n * addition cannot break the guard.\n *\n * @param value - the decoded JSON body.\n * @returns the parsed response, or undefined when the body is not one.\n */\nexport function parseSystemOneResponse(value: unknown): SystemOneResponse | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const raw = value as Record<string, unknown>\n const rawAnswers = raw.answers\n if (typeof rawAnswers !== 'object' || rawAnswers === null || Array.isArray(rawAnswers)) return undefined\n const entries = Object.entries(rawAnswers)\n if (entries.length === 0) return undefined\n const answers: Record<string, SystemOneAnswer> = {}\n for (const [id, entry] of entries) {\n const answer = parseSystemOneAnswer(entry)\n if (answer === undefined) return undefined\n answers[id] = answer\n }\n const usage = raw.usage === undefined ? undefined : parseUsage(raw.usage)\n if (raw.usage !== undefined && usage === undefined) return undefined\n return {\n ...(typeof raw.model === 'string' ? { model: raw.model } : {}),\n answers,\n ...(usage === undefined ? {} : { usage }),\n }\n}\n\n/** Parse the optional `usage` member; an unreadable one is a malformed body. */\nfunction parseUsage(value: unknown): SystemOneUsage | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const raw = value as Record<string, unknown>\n const inputTokens = raw.input_tokens === undefined ? undefined : finite(raw.input_tokens)\n if (raw.input_tokens !== undefined && inputTokens === undefined) return undefined\n const outputTokens = raw.output_tokens === undefined ? undefined : finite(raw.output_tokens)\n if (raw.output_tokens !== undefined && outputTokens === undefined) return undefined\n return {\n ...(inputTokens === undefined ? {} : { inputTokens }),\n ...(outputTokens === undefined ? {} : { outputTokens }),\n }\n}\n\n/** Validate the outgoing request where the server would only reject it with a 400. */\nfunction assertRequest(request: SystemOneRequest): void {\n const ids = Object.keys(request.questions)\n if (ids.length === 0) throw new SystemOneError('a decision request needs at least one question', 'invalid-request')\n if (ids.length > SYSTEMONE_MAX_QUESTIONS) {\n throw new SystemOneError(\n `a decision request carries at most ${SYSTEMONE_MAX_QUESTIONS} questions (got ${ids.length})`,\n 'invalid-request',\n )\n }\n for (const id of ids) {\n if (id.trim() === '') throw new SystemOneError('every decision question needs a non-empty id', 'invalid-request')\n }\n}\n\n/** Read the endpoint's error body into a one-line diagnosis. */\nasync function httpFailure(response: Response): Promise<SystemOneError> {\n let detail = ''\n try {\n const text = await response.text()\n const slice = text.trim().slice(0, 200)\n if (slice !== '') detail = `: ${slice}`\n } catch {\n // A body that cannot be read adds nothing; the status is the diagnosis.\n }\n return new SystemOneError(\n `Command Code decision request failed (HTTP ${response.status})${detail}`,\n 'http',\n response.status,\n )\n}\n\n/**\n * Run one decision request.\n *\n * @param deps - connection facts, credential chain and fetch seam.\n * @param request - the state and typed questions.\n * @param options - caller cancellation and the per-call budget.\n * @returns the parsed decision.\n * @throws {SystemOneError} on every failure path; callers fail closed.\n */\nexport async function runSystemOne(\n deps: SystemOneDeps,\n request: SystemOneRequest,\n options: { signal?: AbortSignal; timeoutMs?: number } = {},\n): Promise<SystemOneResponse> {\n assertRequest(request)\n const apiBase = deps.apiBase()\n if (!URL.canParse(apiBase)) {\n throw new SystemOneError(\n `Command Code decision request is misconfigured: apiBase ${JSON.stringify(apiBase)} is not a valid URL`,\n 'invalid-request',\n )\n }\n if (options.signal?.aborted === true) throw new SystemOneError('decision request aborted', 'aborted')\n const timeoutMs = options.timeoutMs ?? SYSTEMONE_DEFAULT_TIMEOUT_MS\n const deadline = deadlineOf(options.signal, timeoutMs)\n try {\n let key: string\n try {\n key = await withinDeadline(Promise.resolve().then(() => deps.resolveApiKey()), deadline, timeoutMs)\n } catch (error) {\n if (error instanceof SystemOneError && (error.kind === 'aborted' || error.kind === 'timeout')) throw error\n throw new SystemOneError(\n `Command Code decision request has no usable credential: ${error instanceof Error ? error.message : String(error)}`,\n 'credential',\n undefined,\n { cause: error },\n )\n }\n\n const body = {\n model: request.model ?? SYSTEMONE_MODEL,\n state: request.state,\n questions: request.questions,\n }\n\n // The credential chain can take a moment (the pool may probe a window), and\n // the caller may withdraw — or the budget may expire — while it runs. Re-check\n // before opening the connection: a real fetch would reject an aborted signal\n // on its own, but the diagnosis belongs to this client, and a deployment with\n // its own transport must not have to re-derive it.\n if (deadline.signal.aborted) {\n throw deadline.callerAborted()\n ? new SystemOneError('decision request aborted', 'aborted')\n : new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout')\n }\n\n let response: Response\n try {\n response = await (deps.fetchImpl ?? fetch)(`${apiBase.replace(/\\/$/, '')}${SYSTEMONE_ROUTE}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\n Authorization: `Bearer ${key}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n signal: deadline.signal,\n })\n } catch (error) {\n if (deadline.callerAborted()) throw new SystemOneError('decision request aborted', 'aborted', undefined, { cause: error })\n if (deadline.timedOut() || isAbortError(error)) {\n throw new SystemOneError(`decision request timed out after ${timeoutMs}ms`, 'timeout', undefined, { cause: error })\n }\n throw new SystemOneError(\n `Command Code decision request failed: ${error instanceof Error ? error.message : String(error)}`,\n 'network',\n undefined,\n { cause: error },\n )\n }\n\n if (!response.ok) throw await httpFailure(response)\n\n let payload: unknown\n try {\n payload = await response.json()\n } catch (error) {\n if (deadline.callerAborted()) throw new SystemOneError('decision request aborted', 'aborted', undefined, { cause: error })\n throw new SystemOneError('Command Code returned an unparseable decision body', 'invalid-response', undefined, { cause: error })\n }\n const parsed = parseSystemOneResponse(payload)\n if (parsed === undefined) {\n throw new SystemOneError('Command Code returned a decision body this plugin cannot read', 'invalid-response')\n }\n return parsed\n } finally {\n // Always: a live timeout timer would otherwise hold the process open, and a\n // caller listener would outlive the request it belongs to.\n deadline.dispose()\n }\n}\n","/**\n * The command guard: an AI second opinion on shell approvals.\n *\n * dsh already decides *that* a tool call needs approval (permission presets, the\n * sandbox's escalation path, `PreToolUse` hooks) and then asks the user. This\n * module inserts one answerer in front of the human: the Command Code decision\n * model `typesafe/jev` (see `./systemone.ts`) is asked whether the command is\n * safe to run without asking, and only a confident *yes* turns into a one-shot\n * `allowed-once` grant. A sandbox escalation is judged as a separate, explicit\n * decision: JEV must confirm both that the wider access has a narrow purpose and\n * that it is necessary, rather than treating a sandbox string as a harmless\n * detail. Everything else — a lower probability, a malformed answer, a timeout,\n * a rate limit, a missing key, a command we refuse to judge — delegates to the\n * next answerer with `next()`, which is the human.\n *\n * Why this seam and not the decision one: `approval/request` fires only after a\n * policy already decided to ask, so a grant here can never widen a policy (a\n * session under the strict `never` policy rejects before any answerer runs) and\n * never has to re-implement one. The same waterfall is what the browser's\n * approval panel answers through, so the guard must be registered with\n * `prepend: true` — otherwise that panel holds the request until the user\n * clicks and this answerer never runs at all.\n *\n * The approval payload carries only a `callId`, no arguments, so the command\n * text comes from a transparent observer on `tools/pre-execute` (which the tool\n * runtime dispatches for every execution, immediately before it resolves the\n * very ask we are answering). The observer always returns `next()`: it can\n * never change a decision, it only remembers what the call was.\n *\n * Fail-closed rules, in order, each of which delegates to the human:\n *\n * 1. the feature is off (the default);\n * 2. the ask is not about a shell tool, or we never saw its arguments;\n * 3. the command matches the hard denylist — those are never even sent to the\n * model;\n * 4. the command is too long to judge in full (a truncated state would invite a\n * verdict on a command the model did not see);\n * 5. a sandbox escalation lacks either explicit scope or necessity support;\n * 6. the decision call fails for any reason (timeout, HTTP, credential,\n * network, unreadable body);\n * 7. the primary probability or either escalation probability is below the\n * configured threshold.\n *\n * The model is billed per request ($0.042/1M input tokens once the free window\n * ends on 2026-09-24) and the endpoint has no ZDR upstream (its requests never\n * carry the `x-cmd-zdr` header the chat transports may send under `Config.zdr`),\n * so the decision is only ever asked about commands a policy already wanted a\n * human to look at, and identical decision contexts within one agent reuse\n * one result from an in-memory memo.\n *\n * @module dsh-commandcode-provider/command-guard\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport {\n type SystemOneQuestion,\n type SystemOneRequest,\n type SystemOneResponse,\n} from './systemone.ts'\n\n/** Tool names whose `arguments.command` this guard judges. */\nexport const COMMAND_GUARD_SHELL_TOOLS: readonly string[] = ['bash', 'pwsh']\n\n/** Question id the primary safety verdict is keyed by. */\nexport const COMMAND_GUARD_QUESTION_ID = 'safe'\n\n/** Question id for the narrow-purpose part of a sandbox escalation. */\nexport const COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID = 'escalation_scope'\n\n/** Question id for the necessity/proportionality part of a sandbox escalation. */\nexport const COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID = 'escalation_necessity'\n\n/**\n * The auto-approve strictness a user picks (`Config.commandGuardLevel`). Each\n * level is the probability every verdict must reach before the guard grants\n * `allowed-once`; a higher level approves less, on stronger evidence. Three\n * presets replace a free-form probability because the useful range is narrow\n * and a hand-typed 0.6 silently turns the guard into a rubber stamp.\n */\nexport type CommandGuardLevel = 'high' | 'medium' | 'low'\n\n/** The selectable levels, strictest first (the order the settings surfaces list them in). */\nexport const COMMAND_GUARD_LEVELS: readonly CommandGuardLevel[] = ['high', 'medium', 'low']\n\n/** Each level's probability threshold. */\nexport const COMMAND_GUARD_LEVEL_THRESHOLDS: Readonly<Record<CommandGuardLevel, number>> = {\n high: 0.95,\n medium: 0.9,\n low: 0.8,\n}\n\n/** The level an unset config reads as. */\nexport const COMMAND_GUARD_DEFAULT_LEVEL: CommandGuardLevel = 'medium'\n\n/** Probability of \"safe\" at or above which the guard grants `allowed-once` by default. */\nexport const COMMAND_GUARD_DEFAULT_THRESHOLD = COMMAND_GUARD_LEVEL_THRESHOLDS[COMMAND_GUARD_DEFAULT_LEVEL]\n\n/** The threshold for a stored level; anything unrecognized reads as the default level. */\nexport function commandGuardThreshold(level: unknown): number {\n return typeof level === 'string' && Object.hasOwn(COMMAND_GUARD_LEVEL_THRESHOLDS, level)\n ? COMMAND_GUARD_LEVEL_THRESHOLDS[level as CommandGuardLevel]\n : COMMAND_GUARD_DEFAULT_THRESHOLD\n}\n\n/**\n * Decision budget; the approval prompt must not wait longer than this. Fixed\n * rather than configurable: it only bounds how long a late verdict can delay\n * the prompt, and every failure (a timeout included) already falls back to\n * asking the user, so there is nothing for a user to tune. 3 s leaves room for\n * credential resolution plus one decision round trip on a slow link.\n */\nexport const COMMAND_GUARD_TIMEOUT_MS = 3000\n\n/**\n * Longest command the guard will send for judgement. A longer one is delegated\n * instead of truncated: a verdict on the first N characters of a command is a\n * verdict on a different command.\n */\nexport const COMMAND_GUARD_MAX_COMMAND_CHARS = 6000\n\n/** Executions remembered for their arguments, and decisions memoized. */\nexport const COMMAND_GUARD_CACHE_ENTRIES = 64\n\n/** How long one command's decision may be reused. */\nexport const COMMAND_GUARD_DECISION_TTL_MS = 10 * 60_000\n\n/** The resolved settings the guard reads per ask. */\nexport interface CommandGuardSettings {\n /** Master switch; the shipped default is off. */\n readonly enabled: boolean\n /** Minimum probability of \"safe\" that grants `allowed-once`. */\n readonly threshold: number\n /** Decision budget in milliseconds. */\n readonly timeoutMs: number\n}\n\n/**\n * Hard denylist: commands the guard never auto-approves, and never even sends\n * for judgement. Each entry is a deliberate, narrow reading of one destructive\n * family — the goal is not to classify every dangerous command (that is the\n * model's job) but to make sure the classics cannot be talked into a grant by a\n * persuasive-looking command string.\n *\n * Every pattern is allowed to OVER-match: a false positive costs one ordinary\n * human prompt, while a false negative would hand a destructive command to a\n * model that has to guess. That asymmetry is why `sudo` is matched anywhere in\n * the line rather than only in command position, and why `fdisk` is listed even\n * though `fdisk -l` only lists partitions.\n */\nexport const COMMAND_GUARD_DENY_LIST: readonly { readonly id: string; readonly pattern: RegExp }[] = [\n // Recursive force-delete of a root-ish, home, cwd or wildcard target.\n // Deleting a plain project-relative path is deliberately NOT here: that is a\n // normal operation the model is allowed to judge.\n {\n id: 'rm-root',\n pattern: /\\brm\\s+(?:-[a-zA-Z]*[rR][a-zA-Z]*f[a-zA-Z]*|-[a-zA-Z]*f[a-zA-Z]*[rR][a-zA-Z]*|--recursive[^\\n]*--force|--force[^\\n]*--recursive)\\s+(?:\\/|\\/\\*|~|~\\/\\*|\\$HOME(?:\\/\\*)?|\\*|\\.\\/\\*|\\.)(?:\\s|$)/,\n },\n { id: 'rm-home', pattern: /\\brm\\s+-[a-zA-Z]*[rR][a-zA-Z]*\\s+(?:~|\\$HOME)\\// },\n // Disk and filesystem primitives.\n { id: 'filesystem-write', pattern: /\\b(?:mkfs(?:\\.\\w+)?|wipefs|fdisk|parted|shred)\\b/ },\n { id: 'raw-device-write', pattern: /\\bdd\\b[^\\n]*\\bof=\\/dev\\// },\n { id: 'device-redirect', pattern: />{1,2}\\s*\\/dev\\/(?:sd|disk|nvme|hd)/ },\n { id: 'fork-bomb', pattern: /:\\s*\\(\\s*\\)\\s*\\{\\s*:\\s*\\|\\s*:\\s*&\\s*\\}\\s*;\\s*:/ },\n // Privilege and ownership.\n { id: 'privilege-escalation', pattern: /\\b(?:sudo|doas)\\b/ },\n { id: 'su', pattern: /\\bsu\\s/ },\n { id: 'chmod-world-write', pattern: /\\bchmod\\b[^\\n]*\\b(?:777|a\\+w|o\\+w)\\b/ },\n { id: 'chown-root', pattern: /\\bchown\\b[^\\n]*\\b(?:root|0):/ },\n // Git history, remote state and discarded work.\n { id: 'git-push', pattern: /\\bgit\\s+push\\b/ },\n { id: 'git-history-rewrite', pattern: /\\bgit\\s+(?:filter-branch|filter-repo)\\b/ },\n { id: 'git-hard-reset', pattern: /\\bgit\\s+reset\\s+--hard\\b/ },\n { id: 'git-clean-force', pattern: /\\bgit\\s+clean\\b[^\\n]*\\s-[a-zA-Z]*f/ },\n { id: 'git-discard-worktree', pattern: /\\bgit\\s+(?:checkout|restore)\\s+(?:--\\s+)?\\.(?:\\s|$)/ },\n { id: 'git-stash-drop', pattern: /\\bgit\\s+stash\\s+(?:drop|clear)\\b/ },\n // Publishing and uploading.\n { id: 'publish', pattern: /\\b(?:npm|pnpm|yarn|bun)\\s+publish\\b/ },\n { id: 'release-upload', pattern: /\\b(?:gh\\s+release|twine\\s+upload)\\b/ },\n { id: 'docker-push', pattern: /\\bdocker\\s+push\\b/ },\n { id: 'cloud-upload', pattern: /\\b(?:aws\\s+s3|gsutil|gcloud\\s+storage|az\\s+storage)\\b[^\\n]*\\b(?:cp|sync|mv|rm|rb)\\b/ },\n { id: 'remote-copy', pattern: /\\b(?:scp|rsync)\\b[^\\n]*(?::|@)/ },\n // A download piped straight into an interpreter.\n { id: 'pipe-to-shell', pattern: /\\b(?:curl|wget|fetch)\\b[^\\n|]*\\|\\s*(?:sudo\\s+)?(?:sh|bash|zsh|dash|ksh|python\\d*|node|ruby|perl)\\b/ },\n // Machine state and process control.\n { id: 'power', pattern: /\\b(?:shutdown|reboot|halt|poweroff)\\b/ },\n { id: 'kill-everything', pattern: /\\bkill\\s+(?:-9\\s+)?-1\\b|\\b(?:killall|pkill)\\s+-9\\b/ },\n // Credentials and shell history.\n {\n id: 'credential-write',\n pattern: /(?:>{1,2}|tee|cp|mv|rm|chmod|chown)\\s[^\\n]*(?:\\.ssh\\b|\\.aws\\b|\\.gnupg\\b|\\.commandcode\\/auth\\.json|id_rsa|id_ed25519)/,\n },\n { id: 'history-clear', pattern: /\\bhistory\\s+-c\\b|\\bunset\\s+HISTFILE\\b/ },\n // System and language-level installs (they run third-party code installers).\n { id: 'global-install', pattern: /\\b(?:npm|pnpm|yarn|bun)\\s+(?:i|install|add)\\s+(?:-g\\b|--global\\b)/ },\n { id: 'system-install', pattern: /\\b(?:apt|apt-get|dnf|yum|zypper|apk|pacman|brew)\\s+(?:install|remove|purge|uninstall|upgrade)\\b/ },\n { id: 'language-install', pattern: /\\b(?:pip3?|pipx|gem|cargo)\\s+(?:install|add)\\b/ },\n]\n\n/**\n * Why the guard refuses to judge a command, when it does.\n *\n * @param command - the raw command text.\n * @returns the matching denylist id, or undefined.\n */\nexport function denyReasonOf(command: string): string | undefined {\n for (const entry of COMMAND_GUARD_DENY_LIST) {\n if (entry.pattern.test(command)) return entry.id\n }\n return undefined\n}\n\n/** One shell command awaiting approval, as read from its tool execution. */\nexport interface ShellCommandFact {\n /** Tool name (`bash` / `pwsh`). */\n readonly tool: string\n /** The command itself. */\n readonly command: string\n /** The agent's own one-line description, when it wrote one. */\n readonly description?: string\n /** The call's working directory, when it named one. */\n readonly workdir?: string\n /** The wider sandbox mode this call asks for, when it is an escalation retry. */\n readonly sandboxPermissions?: string\n /** The asker's own explanation of why approval is needed. */\n readonly reason?: string\n}\n\n/** A non-empty string member, or undefined. */\nfunction stringMember(value: unknown, key: string): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const member = (value as Record<string, unknown>)[key]\n return typeof member === 'string' && member.trim() !== '' ? member : undefined\n}\n\n/**\n * Read a shell command out of a tool execution, or undefined when this call is\n * not one the guard judges (a different tool, or arguments without a command).\n *\n * @param name - the executed tool's name.\n * @param args - the execution's parsed `arguments`.\n * @returns the fact to judge, without the asker's reason (that arrives later).\n */\nexport function shellCommandOf(name: string, args: unknown): Omit<ShellCommandFact, 'reason'> | undefined {\n if (!COMMAND_GUARD_SHELL_TOOLS.includes(name)) return undefined\n const command = stringMember(args, 'command')\n if (command === undefined) return undefined\n const description = stringMember(args, 'description')\n const workdir = stringMember(args, 'workdir')\n const sandboxPermissions = stringMember(args, 'sandbox_permissions')\n return {\n tool: name,\n command,\n ...(description === undefined ? {} : { description }),\n ...(workdir === undefined ? {} : { workdir }),\n ...(sandboxPermissions === undefined ? {} : { sandboxPermissions }),\n }\n}\n\n/**\n * Build the decision request for one command.\n *\n * A normal approval asks one question. A call that explicitly requests a wider\n * sandbox gets the same safety question plus two veto questions. This keeps the\n * common case cheap while making the broader permission change an explicit\n * decision: JEV must agree that the extra access has a narrow purpose and is\n * necessary, not merely that the command text looks familiar.\n *\n * The agent's own `description` and the harness's `reason` are included as\n * context, but the criteria say the command text itself decides — a\n * model-written description is a claim, not evidence.\n *\n * @param fact - the command and its context.\n * @returns the request to send.\n */\nexport function buildSafetyRequest(fact: ShellCommandFact): SystemOneRequest {\n const escalated = fact.sandboxPermissions !== undefined\n const lines = [\n `Tool: ${fact.tool}`,\n 'Command:',\n fact.command,\n ...(fact.description === undefined ? [] : ['', `The agent describes this command as: ${fact.description}`]),\n ...(fact.workdir === undefined ? [] : ['', `Working directory: ${fact.workdir}`]),\n ...(fact.sandboxPermissions === undefined\n ? []\n : ['', `The harness is asking because this call requests a wider sandbox mode (${fact.sandboxPermissions}) than the one currently in force.`]),\n ...(fact.reason === undefined ? [] : ['', `The asker's reason for needing approval: ${fact.reason}`]),\n ]\n const question: SystemOneQuestion = {\n type: 'noul',\n instructions: escalated\n ? 'Is it safe to run this command right now WITHOUT asking the user first, including the requested sandbox escalation? Judge the command text itself; a description or stated reason is only a claim about it.'\n : 'Is it safe to run this command right now WITHOUT asking the user first? Judge the command text itself; a description is only a claim about it.',\n criteria: {\n true: escalated\n ? 'A normal, non-obfuscated read, build, or test operation whose outside-workspace effects are limited to conventional build/dependency caches or temporary files and are easily reversible: no unrelated user or system data is accessed, no data leaves the machine, and no credentials, git history or remote state are touched.'\n : 'Read-only, or its effects stay inside the current project and are trivially reversible: no data leaves the machine, nothing outside the project is modified, and no credentials, git history or remote state are touched.',\n false: 'Anything else. Broad or unrelated outside-workspace access, deleting or overwriting files outside the project, rewriting or publishing git history, uploading data anywhere, installing system or global packages, changing permissions, ownership or credentials, killing processes, running as another user or as root, piping a download into a shell, or a command obfuscated enough that its effect cannot be read.',\n },\n }\n const questions: Record<string, SystemOneQuestion> = {\n [COMMAND_GUARD_QUESTION_ID]: question,\n }\n if (escalated) {\n questions[COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID] = {\n type: 'noul',\n instructions: 'Is the requested wider sandbox access limited to a narrow, conventional purpose supported by this command, such as a build cache, dependency cache, or temporary directory, rather than unrelated user files, credentials, other projects, or the network?',\n criteria: {\n true: 'The wider access is plausibly limited to conventional local build/dependency caches or temporary files required by the command, with no unrelated host data or remote transfer in scope.',\n false: 'The command needs broad or unrelated host access, cannot establish a narrow purpose, or would use the wider permission to reach credentials, other projects, user files, or the network.',\n },\n }\n questions[COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID] = {\n type: 'noul',\n instructions: 'Is the requested sandbox escalation necessary and proportionate for this one command, rather than broader than the command needs? Treat the stated reason as a claim to check against the command, not as proof.',\n criteria: {\n true: 'The command and its stated purpose support a one-shot escalation that is needed for the task and is no broader than the requested effect requires.',\n false: 'The wider mode is unnecessary, broader than needed, unsupported by the command, or the command is too ambiguous to justify the extra authority.',\n },\n }\n }\n return {\n state: lines.join('\\n'),\n questions,\n }\n}\n\n/**\n * Read a probability out of a decision response.\n *\n * @param response - the parsed response.\n * @param questionId - the question id to read (defaults to the guard's own).\n * @returns the probability, or undefined when the answer is missing or is not\n * a `noul` verdict.\n */\nexport function safeProbabilityOf(\n response: SystemOneResponse,\n questionId: string = COMMAND_GUARD_QUESTION_ID,\n): number | undefined {\n const answer = response.answers[questionId]\n return answer !== undefined && answer.type === 'noul' ? answer.noul : undefined\n}\n\n/** The subset of a tool execution this guard reads. */\nexport interface GuardToolExecution {\n readonly callId: string\n readonly name: string\n readonly arguments: unknown\n readonly agent?: object\n}\n\n/** The subset of an approval request this guard reads. */\nexport interface GuardApprovalRequest {\n readonly toolName: string\n readonly callId?: string\n readonly reason?: string\n readonly signal?: AbortSignal\n readonly agent?: object\n}\n\n/** The approval vocabulary, from the harness's own closed set. */\nexport type GuardApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'\n\n/** What one ask resolved to, for logging and tests. */\nexport type CommandGuardVerdict =\n /** A confident \"safe\" — the caller grants `allowed-once`. */\n | {\n readonly kind: 'approve'\n readonly probability: number\n readonly source: 'model' | 'memo'\n /** The two explicit sandbox-escalation guard probabilities, when applicable. */\n readonly escalation?: {\n readonly scope: number\n readonly necessity: number\n }\n /** One-line excerpt of the command, for the audit log. */\n readonly command?: string\n }\n /** Delegate to the next answerer (the human). */\n | {\n readonly kind: 'delegate'\n readonly reason: string\n readonly probability?: number\n /** One-line excerpt of the command, when the guard got far enough to know it. */\n readonly command?: string\n }\n\n/**\n * One-line, length-bounded excerpt of a command for the log. The full text is\n * already in the session's tool call and was already sent to the decision\n * endpoint, so this adds no exposure — it is what makes \"why did this run\n * without asking?\" answerable from the log alone.\n */\nexport function commandExcerpt(command: string, limit = 160): string {\n const flat = command.replace(/\\s+/g, ' ').trim()\n return flat.length <= limit ? flat : `${flat.slice(0, limit - 1)}…`\n}\n\n/** Everything the guard needs beyond the two listeners. */\nexport interface CommandGuardDeps {\n /** Live settings, re-read per ask so a settings write lands on the next one. */\n settings: () => CommandGuardSettings\n /**\n * Run one decision. The binding owns the connection facts and the API key;\n * the guard owns the request and passes its own budget and cancellation.\n */\n decide: (\n request: SystemOneRequest,\n options: { signal?: AbortSignal; timeoutMs: number },\n ) => Promise<SystemOneResponse>\n /** Clock (tests). Defaults to `Date.now`. */\n now?: () => number\n /** One-line decision log (the harness logger, in the plugin entry). */\n log?: (message: string) => void\n}\n\n/** A memoized decision for one exact command. */\ninterface MemoEntry {\n readonly probability: number\n /** The two extra probabilities required by a sandbox escalation. */\n readonly escalation?: {\n readonly scope: number\n readonly necessity: number\n }\n readonly at: number\n}\n\ninterface ObservedExecution {\n readonly fact: Omit<ShellCommandFact, 'reason'>\n readonly agent: object | undefined\n}\n\n/**\n * The guard's stateful half: what was executed (by call id) and what has\n * already been decided (by agent and complete decision context), both bounded.\n *\n * The execution cache is the bridge between the two seams — `tools/pre-execute`\n * knows the arguments, `approval/request` knows the call id — and it is keyed by\n * call id with an agent-identity check when read: an entry for an execution\n * that never asked is never read, so there is nothing to clean up on the result\n * side (and the ask happens before the result anyway).\n */\nexport class CommandGuard {\n private readonly executions = new Map<string, ObservedExecution>()\n private decisions = new WeakMap<object, Map<string, MemoEntry>>()\n\n constructor(private readonly deps: CommandGuardDeps) {}\n\n /**\n * Remember one execution's command. Never throws, never changes a decision.\n *\n * @param execution - the execution about to run.\n */\n noteExecution(execution: GuardToolExecution): void {\n const callId = execution?.callId\n if (typeof callId !== 'string' || callId === '') return\n const fact = shellCommandOf(execution.name, execution.arguments)\n if (fact === undefined) return\n this.executions.delete(callId)\n this.executions.set(callId, { fact, agent: execution.agent })\n while (this.executions.size > COMMAND_GUARD_CACHE_ENTRIES) {\n const oldest = this.executions.keys().next()\n if (oldest.done === true) break\n this.executions.delete(oldest.value)\n }\n }\n\n /** Forget every remembered execution and decision (disposal, tests). */\n clear(): void {\n this.executions.clear()\n this.decisions = new WeakMap()\n }\n\n /**\n * Judge one approval request.\n *\n * @param request - the pending approval.\n * @returns the verdict; `approve` is the only outcome that grants anything.\n */\n async judge(request: GuardApprovalRequest): Promise<CommandGuardVerdict> {\n const settings = this.deps.settings()\n if (!settings.enabled) return { kind: 'delegate', reason: 'guard disabled' }\n const callId = request.callId\n if (callId === undefined) return { kind: 'delegate', reason: 'approval carries no call id' }\n const observed = this.executions.get(callId)\n if (observed === undefined || observed.agent !== request.agent) {\n return { kind: 'delegate', reason: 'the guard never saw this call for this agent' }\n }\n const fact = observed.fact\n const excerpt = commandExcerpt(fact.command)\n if (!COMMAND_GUARD_SHELL_TOOLS.includes(request.toolName)) {\n return { kind: 'delegate', reason: `not a shell tool (${request.toolName})` }\n }\n if (fact.command.length > COMMAND_GUARD_MAX_COMMAND_CHARS) {\n return {\n kind: 'delegate',\n reason: `command longer than ${COMMAND_GUARD_MAX_COMMAND_CHARS} characters`,\n command: excerpt,\n }\n }\n const denied = denyReasonOf(fact.command)\n if (denied !== undefined) {\n return { kind: 'delegate', reason: `denylisted command (${denied})`, command: excerpt }\n }\n\n const full: ShellCommandFact = {\n ...fact,\n ...(request.reason === undefined ? {} : { reason: request.reason }),\n }\n // Only an agent-scoped, identical decision state may reuse a verdict.\n // The same relative command can have different effects in another working\n // directory or sandbox mode; the asker's reason also changes the question.\n const memoKey = JSON.stringify(full)\n const now = this.deps.now?.() ?? Date.now()\n const agentDecisions = request.agent === undefined ? undefined : this.decisions.get(request.agent)\n const memo = agentDecisions?.get(memoKey)\n if (memo !== undefined) {\n if (now - memo.at < COMMAND_GUARD_DECISION_TTL_MS) {\n return this.verdict(memo, settings.threshold, 'memo', excerpt, full.sandboxPermissions !== undefined)\n }\n agentDecisions?.delete(memoKey)\n }\n\n let response: SystemOneResponse\n try {\n response = await this.deps.decide(buildSafetyRequest(full), {\n ...(request.signal === undefined ? {} : { signal: request.signal }),\n timeoutMs: settings.timeoutMs,\n })\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error)\n return { kind: 'delegate', reason: `decision unavailable: ${detail}`, command: excerpt }\n }\n const probability = safeProbabilityOf(response)\n if (probability === undefined) {\n return { kind: 'delegate', reason: 'the decision carried no safe verdict', command: excerpt }\n }\n let escalation: { readonly scope: number; readonly necessity: number } | undefined\n if (full.sandboxPermissions !== undefined) {\n const scope = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID)\n const necessity = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID)\n if (scope === undefined || necessity === undefined) {\n return {\n kind: 'delegate',\n reason: 'the decision carried no complete sandbox-escalation verdict',\n command: excerpt,\n }\n }\n escalation = { scope, necessity }\n }\n const memoEntry: MemoEntry = {\n probability,\n ...(escalation === undefined ? {} : { escalation }),\n at: now,\n }\n\n if (request.agent !== undefined) {\n const decisions = agentDecisions ?? new Map<string, MemoEntry>()\n decisions.set(memoKey, memoEntry)\n while (decisions.size > COMMAND_GUARD_CACHE_ENTRIES) {\n const oldest = decisions.keys().next()\n if (oldest.done === true) break\n decisions.delete(oldest.value)\n }\n this.decisions.set(request.agent, decisions)\n }\n return this.verdict(memoEntry, settings.threshold, 'model', excerpt, full.sandboxPermissions !== undefined)\n }\n\n /** Apply the threshold to the primary verdict and any escalation vetoes. */\n private verdict(\n entry: MemoEntry,\n threshold: number,\n source: 'model' | 'memo',\n command: string,\n escalated: boolean,\n ): CommandGuardVerdict {\n if (entry.probability < threshold) {\n return {\n kind: 'delegate',\n reason: `safe probability ${entry.probability.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n if (!escalated) {\n return { kind: 'approve', probability: entry.probability, source, command }\n }\n if (entry.escalation === undefined) {\n return { kind: 'delegate', reason: 'the cached sandbox-escalation verdict was incomplete', command }\n }\n if (entry.escalation.scope < threshold) {\n return {\n kind: 'delegate',\n reason: `sandbox scope probability ${entry.escalation.scope.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n if (entry.escalation.necessity < threshold) {\n return {\n kind: 'delegate',\n reason: `sandbox necessity probability ${entry.escalation.necessity.toFixed(3)} below ${threshold}`,\n probability: entry.probability,\n command,\n }\n }\n return {\n kind: 'approve',\n probability: entry.probability,\n source,\n ...(entry.escalation === undefined ? {} : { escalation: entry.escalation }),\n command,\n }\n }\n}\n\n/** The two listeners this module registers, typed structurally. */\ninterface CommandGuardEvents {\n on(\n event: 'tools/pre-execute',\n listener: (execution: GuardToolExecution, next: () => Promise<unknown>) => unknown,\n options?: { prepend?: boolean },\n ): unknown\n on(\n event: 'approval/request',\n listener: (\n request: GuardApprovalRequest,\n next: () => Promise<GuardApprovalOutcome>,\n ) => Promise<GuardApprovalOutcome> | GuardApprovalOutcome,\n options?: { prepend?: boolean },\n ): unknown\n}\n\n/**\n * Register the guard on a context that has the approval seam.\n *\n * Call this from inside `ctx.inject(['approval'], …)`: the seam's presence is\n * what makes the feature meaningful (no approval service means no asks), and\n * tying the listeners to that injected fiber is what makes them go away with it.\n *\n * @param ctx - the injected context (or a test double with `on`).\n * @param deps - settings, the decision client, clock and logger.\n * @returns a disposer for both listeners.\n */\nexport function applyCommandGuard(ctx: Context, deps: CommandGuardDeps): () => void {\n const guard = new CommandGuard(deps)\n const events = ctx as unknown as CommandGuardEvents\n\n const offPreExecute = events.on('tools/pre-execute', (execution, next) => {\n guard.noteExecution(execution)\n return next()\n }, { prepend: true })\n\n const offApproval = events.on('approval/request', async (request, next) => {\n // The disabled path is checked here as well as inside `judge()` so that a\n // guard nobody turned on costs one config read and logs nothing: an\n // approval prompt is an ordinary event in every session, and narrating\n // \"delegated, guard disabled\" for each one would be pure noise.\n try {\n if (!deps.settings().enabled) return next()\n } catch (error) {\n deps.log?.(`command guard failed: ${error instanceof Error ? error.message : String(error)}`)\n return next()\n }\n let verdict: CommandGuardVerdict\n try {\n verdict = await guard.judge(request)\n } catch (error) {\n // The guard must never be the reason an approval fails; the human path is\n // always still there.\n deps.log?.(`command guard failed: ${error instanceof Error ? error.message : String(error)}`)\n return next()\n }\n if (verdict.kind === 'approve') {\n deps.log?.(\n `command guard auto-approved a ${request.toolName} call`\n + ` (safe probability ${verdict.probability.toFixed(3)}`\n + `${verdict.escalation === undefined\n ? ''\n : `, sandbox scope ${verdict.escalation.scope.toFixed(3)}, necessity ${verdict.escalation.necessity.toFixed(3)}`}`\n + `, ${verdict.source}): ${verdict.command ?? '(command unknown)'}`,\n )\n return 'allowed-once'\n }\n deps.log?.(\n `command guard delegated a ${request.toolName} call: ${verdict.reason}`\n + `${verdict.command === undefined ? '' : ` — ${verdict.command}`}`,\n )\n return next()\n }, { prepend: true })\n\n return () => {\n guard.clear()\n for (const off of [offPreExecute, offApproval]) {\n if (typeof off === 'function') (off as () => void)()\n }\n }\n}\n","/**\n * Volatile-config helpers for dsh 0.1.7's schema-derived profile Config.\n *\n * 0.1.7 rewrote settings around profile Config: `settings.describe()` projects\n * each active entry's schema through `volatileForm()`, so a form contains ONLY\n * fields whose schema nodes carry `meta.volatile`, and a form edit is refused\n * unless its path lies beneath a marked node. On that generation the loader\n * resolves each marked top-level field into a readonly `Volatile<T>` reference\n * (`{ get() }`, frozen, written in place by the owning runtime) instead of a\n * plain value, commits later changes WITHOUT remounting the fiber, and\n * dispatches `loader/volatile-update` to the owning fiber.\n *\n * Two helpers keep the rest of the plugin reading a PLAIN `Config`:\n *\n * - `markVolatile(schema)` applies `.volatile()`, so 0.1.7's forms see every\n * field we mark. The declared type is preserved through the mark on purpose:\n * it changes what the schema PARSES to (a live reference), not the\n * plugin-facing `Config` shape every consumer reads.\n * - `unwrapVolatileConfig(config)` reads every top-level field through its\n * reference when one is present — returning a FRESH object per call, since\n * a reference's identity is stable while its value changes — and returns the\n * config untouched when none is.\n *\n * Only TOP-LEVEL fields are marked (form writes name top-level paths such as\n * `accounts` or `modelVisibility.<id>`, whose first segment is the marked\n * node), so one unwrap level is complete. The literal `apiKey` secret stays\n * unmarked on purpose: no settings surface writes it — the settings page and\n * the dsh-TUI section both write keys through the credentials seam — so it\n * keeps composition-only semantics, and a config-file edit to it reloading the\n * fiber is the correct behavior for a secret literal.\n *\n * @module dsh-commandcode-provider/config-volatile\n */\n\n/**\n * Mark one schema field volatile.\n *\n * `.volatile()` is unconditional: the mark is a schemastery 3.18.3 feature and\n * the only engine this bundle supports (`dsh 0.1.7-rc.2`) pins `~3.18.4`, so\n * the method is always present. It is reached through a structural member\n * rather than schemastery's own typing so the function can keep the caller's\n * declared field type, which is what lets `Config` stay the plain shape every\n * consumer reads while the schema parses to live references.\n *\n * @param schema - The field schema.\n * @returns The schema carrying `meta.volatile`.\n */\nexport function markVolatile<S>(schema: S): S {\n return (schema as S & { volatile(): S }).volatile()\n}\n\n/**\n * Mark every field of a Config field dict volatile, except the named\n * composition-only secrets (`apiKey` here, which no settings surface writes).\n *\n * @param fields - Freshly built field schemas.\n * @param skip - Field names that must stay unmarked.\n * @returns The field dict with every non-skipped field marked.\n */\nexport function markVolatileFields<D extends Record<string, unknown>>(\n fields: D,\n skip: readonly string[] = [],\n): D {\n return Object.fromEntries(\n Object.entries(fields).map(([name, schema]) => [name, skip.includes(name) ? schema : markVolatile(schema)]),\n ) as D\n}\n\n/** A resolved volatile config reference: the frozen `{ get() }` cosmokit hands out. */\nexport interface VolatileRef {\n get(): unknown\n}\n\n/**\n * Whether a resolved config value is a volatile reference.\n *\n * Duck-typed on the two properties `createVolatile` produces (frozen object\n * with a `get` method) rather than cosmokit's private `write` symbol, because\n * cosmokit is not a peer of this bundle. Config values are plain parsed JSON\n * (or `!!jsExpr` wrappers), which are never frozen, so the test cannot\n * misfire on an ordinary field.\n */\nexport function isVolatileRef(value: unknown): value is VolatileRef {\n return typeof value === 'object'\n && value !== null\n && !Array.isArray(value)\n && Object.isFrozen(value)\n && typeof (value as VolatileRef).get === 'function'\n}\n\n/**\n * Read one config object as PLAIN values.\n *\n * Every top-level field found to be a volatile reference is read through\n * `.get()` — freshly on every call, so a live update lands on the very next\n * read. The loader resolves EVERY marked node into a reference, unset fields\n * included, so a loader-parsed config always yields a fresh object here; the\n * pass-through for a field that is not a reference is what keeps the unmarked\n * `apiKey` literal readable.\n */\nexport function unwrapVolatileConfig<C>(config: C): C {\n const source = config as C & Record<string, unknown>\n if (typeof source !== 'object' || source === null) return config\n const plain: Record<string, unknown> = {}\n for (const [field, value] of Object.entries(source)) {\n plain[field] = isVolatileRef(value) ? value.get() : value\n }\n return plain as C\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 plugin's live profile Config (volatile fields, unwrapped per read) and\n * the credential seam, so a changed key, endpoint, or cache path reaches the\n * next request 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 { AccountRotationReason, 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, loginCredentialRef } 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'\nimport {\n COMMAND_GUARD_DEFAULT_LEVEL,\n COMMAND_GUARD_LEVELS,\n COMMAND_GUARD_TIMEOUT_MS,\n applyCommandGuard,\n commandGuardThreshold,\n type CommandGuardLevel,\n type CommandGuardSettings,\n} from './command-guard.ts'\nimport { runSystemOne } from './systemone.ts'\nimport { markVolatileFields, unwrapVolatileConfig } from './config-volatile.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_NON_ZDR_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 supportsZeroDataRetention,\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 } 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 * Whether the Command Code decision model (`typesafe/jev`) may auto-approve\n * shell commands that dsh was about to ask about. Defaults to FALSE: the\n * guard turns a model's opinion into a one-shot approval grant, so it is\n * opt-in, and the command text (plus the agent's own description of it) is\n * sent to Command Code to judge. Only commands a policy already wanted a\n * human to look at are ever judged, and only a confident \"safe\" verdict\n * (`commandGuardLevel`) skips the prompt — every other outcome, including\n * any failure of the decision call itself, delegates to the normal approval\n * flow. See `./command-guard.ts`.\n */\n commandGuard?: boolean\n /**\n * How confident every verdict must be before the guard skips the approval\n * prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower\n * level approves more, on less evidence. The decision budget is fixed\n * (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.\n */\n commandGuardLevel?: CommandGuardLevel\n /**\n * Whether requests enforce zero data retention: the provider then routes\n * them only through upstreams that keep no prompts/completions and never\n * train on them (its own opt-in, `CMD_ZDR=1` in the CLI / `x-cmd-zdr: 1` on\n * the Provider API). Defaults to FALSE: `zdr` changes WHERE a request is\n * served. Every chat request carries the header when enabled; a model with\n * no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` instead of\n * being routed through an upstream that retains data. ZDR capacity is\n * priced pass-through and usually costs more, and the price readout keeps\n * quoting the ordinary catalog rates (the real per-request price shows in\n * Command Code's Studio). The decision endpoint behind the command guard is\n * never ZDR-enforced — see `./systemone.ts`.\n */\n zdr?: 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\n/**\n * The Config schema: every field volatile except the composition-only `apiKey`\n * secret.\n *\n * dsh 0.1.7's settings forms are projected from the schema's `meta.volatile`\n * nodes, so an unmarked field would be invisible to AND unwritable from the\n * settings page and refused by form-edit path validation — and the loader\n * hands `apply()` a live reference per marked field, committing later writes\n * without remounting this fiber (the `loader/volatile-update` listener at the\n * bottom of `apply` covers the facts that are not re-derived per read).\n */\nexport const Config: z<Config> = z.object(markVolatileFields({\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 profile Config document\n // (the 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 // DELIBERATELY not volatile: no settings surface writes it (both the web\n // page and the dsh-TUI section write keys through the credentials seam), so\n // it stays composition-only, and a config-file edit to it reloading this\n // fiber is the correct behavior for a secret literal.\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 Config.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 // The command guard. The level list mirrors COMMAND_GUARD_LEVELS in\n // `./command-guard.ts`; the client's field spec mirrors it again (the browser\n // bundle cannot import that node-side module).\n commandGuard: z.boolean().default(false),\n commandGuardLevel: z.union([...COMMAND_GUARD_LEVELS]).default(COMMAND_GUARD_DEFAULT_LEVEL),\n // Off by default: turning it on changes which upstream serves the request\n // (and usually what it costs), so nobody gets ZDR routing by accident.\n zdr: z.boolean().default(false),\n lang: z.string().pattern(/^(zh|en)$/).default('zh' as const),\n}, ['apiKey']))\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 // The connection carries the switch; the adapter enforces it on every\n // chat request rather than depending on a client-side coverage snapshot.\n zdr: config.zdr === true,\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 // The raw composition config as handed to `apply`. Everything downstream\n // reads through `current()`, which unwraps volatile references on every call\n // — the loader commits a settings write IN PLACE on the reference, so a\n // cached plain snapshot would go stale on the very next write.\n const current = (): Config => unwrapVolatileConfig(config)\n const options = (): ResolvedCommandCodeOptions => resolveAdapterOptions(current())\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.probeWindowLimits(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 account-scoped rejection: mark the rejected key when the\n // reason warrants it and hand the adapter the next account's key. When\n // every account is exhausted the pool throws the RATE_LIMIT /\n // INVALID_CREDENTIAL error that names the earliest reset — that error, not\n // the raw provider rejection, is what the caller sees.\n rotateApiKey: async (\n rejectedKey: string,\n rejection: AccountRotationReason,\n _connection: ResolvedCommandCodeOptions,\n model?: string,\n rotation?: { tried: readonly string[]; resetAtMs?: number },\n ): Promise<string | undefined> => {\n // Only the two account-health reasons become marks: an `unavailable`\n // rejection (no credits, a model outside this account's plan) says\n // nothing durable about the key, so the pool rotates past it without\n // remembering — a `:free` model is still served by a credits-empty\n // account. `rate-limit` (a window the provider named) and `throttled` (a\n // 429 that named none) both mark, but with different causes, so the\n // pool's own diagnosis never reports a plain throttle as an exhausted\n // usage window (issue #54). The provider's own `resetAtMs`, when the body\n // carried one, turns the rate-limit mark into a cooldown that expires by\n // itself.\n if (rejection !== 'unavailable') pool.markRejected(rejectedKey, rejection, rotation?.resetAtMs)\n // The whole tried set, not just the rejected key, reaches the pool: a\n // rejection that does not mark the key would otherwise be re-offered on\n // every attempt and a four-account pool could never reach the accounts\n // behind it. The model rides along so model-routing rules pick the next\n // account for the same model. An EMPTY set must not be forwarded — the\n // pool reads it as \"nothing was tried\" and drops the filter this set\n // exists for, so it falls back to the rejected key like a missing one.\n const tried = rotation?.tried?.length ? rotation.tried : [rejectedKey]\n const resolved = await pool.resolveKey(\n model === undefined ? { tried } : { tried, 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 // The picker's plan filter asks about the whole pool, not just the account\n // that would serve right now: with several accounts on different plans,\n // keying the list on the serving one made models appear and vanish as\n // rotation moved between them (and hid models the other accounts could\n // run). Read live, so adding or removing an account applies to the next\n // picker load.\n resolveAccountKeys: async (): Promise<readonly string[]> => {\n const accounts = await pool.resolvedAccounts()\n return accounts.map((account) => account.key)\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 validateTargetRef: (targetRef): void => {\n loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? [])\n },\n storeKey: async ({ apiKey }: CommandCodeLoginCredentials, targetRef): Promise<void> => {\n const ref = credentialRef(loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? []))\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 command guard's live settings. Declared BEFORE the inject below\n // because an inject callback can run synchronously (when the seam is already\n // mounted) and a `const` declared after it would be a temporal-dead-zone\n // throw. Every fact is re-read per ask, so a settings write lands on the very\n // next approval.\n const commandGuardSettings = (): CommandGuardSettings => {\n const raw = current()\n return {\n enabled: raw.commandGuard === true,\n threshold: commandGuardThreshold(raw.commandGuardLevel),\n timeoutMs: COMMAND_GUARD_TIMEOUT_MS,\n }\n }\n\n // The command guard: an AI second opinion in front of the human approval\n // prompt. dsh's approval seam is an optional service, and the guard is only\n // meaningful where it exists (no approval service means no asks to answer at\n // all), so the listeners ride `ctx.inject(['approval'], …)` exactly like\n // `web` and `tuiSettingsSections`: a profile without the seam never activates\n // this fiber, and an engine that predates the service stays inert.\n //\n // The decision endpoint uses the plugin's ordinary credential chain and base\n // URL — no separate key — and every failure inside it delegates to the human\n // (`./command-guard.ts` documents the ladder).\n ctx.inject(['approval'], (approvalCtx) => {\n applyCommandGuard(approvalCtx, {\n settings: commandGuardSettings,\n decide: (request, decideOptions) => runSystemOne(\n {\n apiBase: () => options().apiBase,\n resolveApiKey: () => resolveApiKey(options()),\n },\n request,\n decideOptions,\n ),\n log: (message) => {\n ctx.logger.info(`llm-commandcode: ${message}`)\n },\n })\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 is an optional service. `configure({ auto: false })` declares that\n // this plugin ships its own page, so SettingsForms publishes no auto-generated\n // form for this entry; config IS the live source (volatile fields), and the\n // `loader/volatile-update` listener below is what re-applies the two facts\n // that are not re-derived per read. A profile without a settings service\n // simply keeps using the composition config `apply()` was handed.\n //\n // The one-time settings.yaml import needs no cooperation from here: the\n // section id and the profile entry id are the SAME string\n // (`llm-commandcode`), which is exactly the identity the engine's\n // `importLegacyDocument` looks the entry up by.\n ctx.inject(['settings'], (settingsCtx) => {\n settingsCtx.effect(() => {\n const dispose = settingsCtx.settings.configure({ auto: false }, ctx.fiber)\n return () => {\n dispose()\n }\n }, 'dsh-commandcode-provider: settings auto-form policy')\n })\n\n // The loader commits volatile config IN PLACE — no remount — and notifies the\n // OWNING fiber (`loader/volatile-update`, every value already committed\n // before dispatch). The facts that are not re-derived from `current()` per\n // use re-apply here: the web seam's selection (its private field is written,\n // not read back from config) and the TUI section (its option lists are frozen\n // into the declaration). Typed structurally because the event is declared by\n // `cordis-plugin-loader`, which is not a peer of this bundle.\n const loaderEvents = ctx as unknown as {\n on(event: 'loader/volatile-update', listener: () => void): unknown\n }\n ctx.effect(() => {\n const off = loaderEvents.on('loader/volatile-update', () => {\n applySearchSelection(current().webSearch ?? true)\n refreshTuiSettings?.()\n })\n return () => {\n if (typeof off === 'function') (off as () => void)()\n }\n }, 'dsh-commandcode-provider: volatile config updates')\n}\n"],"mappings":"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"}