@mars-sea/dsh-commandcode-provider 0.12.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -0
- package/README.md +7 -3
- package/README.zh-CN.md +8 -3
- package/lib/client.js +245 -69
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +177 -51
- package/lib/index.js +1642 -306
- package/lib/index.js.map +1 -1
- package/package.json +41 -38
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["record","record","stringField","reject","createNetServer","createHttpServer"],"sources":["../src/cost-facts.ts","../src/plan-tiers.ts","../src/capabilities.ts","../src/model-prices.ts","../src/wire-guards.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/display-format.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/config-volatile.ts","../src/index.ts"],"sourcesContent":["/** 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\n * 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 and no row carries both\n * today, so the combination becoming real is visible before it reaches a user.\n * This ordering is a latent choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // ORDER IS LOAD-BEARING: 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.\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 // The table is mutable, so an identity-keyed index can keep stale model\n // mappings after its rows are changed in place. The projection already\n // indexes its usage groups once per settlement; scan the small price table\n // here so every call observes the current rows.\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","/** Shared plan-tier presentation facts; safe to inline into the browser bundle. */\n\nexport const PLAN_TIER_ORDER = ['go', 'goat', 'pro', 'provider', 'max'] as const\n\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\nexport const PLAN_ORDER: Readonly<Record<string, number>> = Object.fromEntries(\n PLAN_TIER_ORDER.map((tier, index) => [tier, index]),\n)\n","/**\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 here is synced from official sources — the command-code CLI\n * bundle's model table (`dist/cli.mjs`, re-verified at command-code@1.68.0) and\n * the official plan/pricing/model docs; see the dsh-commandcode-upstream skill\n * for the extraction procedures. Keeping the snapshot in its own module\n * confines those frequent sync diffs here: src/adapter.ts holds only the stable\n * wire/runtime logic. The read helpers live here too, for the same reason.\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\nimport { peakHour } from './cost-facts.ts'\nimport { PLAN_LABELS, PLAN_ORDER } from './plan-tiers.ts'\nexport { PLAN_LABELS, PLAN_ORDER } from './plan-tiers.ts'\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n // Re-verified against the authoritative command-code@1.68.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 '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; same effort 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 // command-code@1.68.0; the five-level set shared with the rest of the Sonnet /\n // Opus family. It takes the \"recommended\" slot from `claude-sonnet-5`.\n 'claude-sonnet-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.39.1 dropped `medium`; the 1.39.2 table ships these three.\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0.\n 'deepseek/deepseek-v4.1-flash': ['low', 'high', 'max'],\n // command-code@1.67.0; the same three-level set as its `deepseek-v4.1-flash`\n // sibling, whose throughput-focused variant this is.\n 'deepseek/deepseek-v4.1-flash-fast': ['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 // command-code@1.39.3; it previously reasoned automatically with no levels.\n 'moonshotai/Kimi-K3': ['low', 'high', 'max'],\n // command-code@1.43.0.\n 'google/gemini-3.8-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n // command-code@1.60.0; same three-level set as its Step 3.x Flash siblings,\n // which still reason automatically with no levels and 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; same four-level set as Grok 4.6. 1.61.0 put it on a\n // 40% off launch deal (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; same effort set as its `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: selectable levels in command-code@1.45.0, `max` added to\n // 1.3 in 1.48.0 (1.3-contributor keeps the four-level set).\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 '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; the full five-level set.\n 'gpt-6-astra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.64.0: Claude Opus 5.5 and the GPT-6 Sol / Luna pair, the only\n // registry additions in the 1.62.0 -> 1.64.0 train; all three reason with the\n // same five-level set as `gpt-6-astra`.\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; it previously reasoned automatically with no levels\n // and lived in KNOWN_THINKING_MODELS. The hidden\n // `minimax/minimax-m3-free` sibling gained the same set in the bundle.\n 'MiniMaxAI/MiniMax-M3': ['low', 'medium', 'high'],\n // command-code@1.65.0. Free during the stealth preview (see KNOWN_DEALS) and\n // NOT routed under ZDR (see KNOWN_NON_ZDR_MODELS).\n 'stealth/space-bunny-alpha': ['low', 'medium', 'high'],\n // command-code@1.66.0. A three-level set offering `xhigh` INSTEAD of `high` —\n // the GLM 5.3 / 5.2 family's shape, unlike Space Bunny Alpha's. Free during\n // the stealth preview and NOT routed under ZDR (see the tables above).\n 'stealth/pixel-canary': ['low', 'medium', 'xhigh'],\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; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'Qwen/Qwen3.8-Max-0902',\n // command-code@1.56.0; Vision per the official registry and inputModalities.\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; Vision per the official registry and inputModalities.\n 'claude-opus-5-5',\n 'claude-opus-5',\n 'claude-sonnet-4-6',\n 'claude-sonnet-5',\n // command-code@1.68.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'claude-sonnet-5-5',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0; Vision per the official registry and inputModalities.\n 'deepseek/deepseek-v4.1-flash',\n // command-code@1.67.0; Vision per the official registry and inputModalities.\n 'deepseek/deepseek-v4.1-flash-fast',\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; Vision per the official registry and inputModalities.\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; Vision per the official registry and inputModalities.\n 'gpt-6-astra',\n // command-code@1.64.0 added the GPT-6 Sol / Luna pair; Vision per the\n // official registry and inputModalities.\n 'gpt-6-luna',\n 'gpt-6-sol',\n // command-code@1.44.0 added Muse Spark 1.3 and its Contributor sibling; both\n // are Vision per the official registry and inputModalities.\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.66.0; Vision per the official registry (the docs models page\n // lists it in the Stealth group) and the CLI's inputModalities.\n 'stealth/pixel-canary',\n // command-code@1.65.0; Vision per the official registry and inputModalities.\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n // command-code@1.60.0; Vision per the official registry and inputModalities.\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 (text-only in 1.46.0).\n 'xai/grok-4.6',\n // command-code@1.59.0; Vision per the official registry and inputModalities.\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. None carries a reasoning flag in any\n // source, so no effort or 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; Vision per the official registry and inputModalities.\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.68.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 of both\n * is this set. Reading only the sibling route table would drop `meituan/\n * LongCat-2.0`, which appears in `modelSupportsZdr` alone (re-read from the\n * 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: the two stealth-preview\n * rows sit in BOTH sets, so LongCat is the only divergence). The official docs (commandcode.ai/docs/resources/\n * zdr) put it in prose — \"99% of our models have ZDR-capable upstreams … only\n * a small handful of models are affected\" — so the CLI's exclusion list is\n * the only per-model evidence there is; a ZDR request naming one of these\n * fails with HTTP 422 `cmd_zdr_no_providers` instead of routing through a\n * 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. It is a rare change:\n * 20 members held across 1.62.0 → 1.64.0, 1.65.0 and 1.66.0 each added exactly\n * one (the two stealth-preview models below), 1.67.0 added one\n * (`deepseek/deepseek-v4.1-flash-fast`), and 1.68.0 changed nothing — 23\n * members as of 2026-09-29.\n */\nexport const KNOWN_NON_ZDR_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.8-Max-0902',\n // command-code@1.67.0. The 1.67.0 artifact lists it in BOTH anchor sets, so\n // the CLI's own ZDR predicate excludes it. Unlike the stealth previews below,\n // the pricing page carries no ZDR note for this row — the artifact is the\n // evidence, and the sibling `deepseek-v4.1-flash` stays ZDR-covered.\n 'deepseek/deepseek-v4.1-flash-fast',\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, in BOTH anchors. The pricing page's own tip agrees:\n // \"Free while the preview lasts. Not routed under ZDR.\"\n 'stealth/space-bunny-alpha',\n // command-code@1.66.0 added `stealth/pixel-canary` — the second stealth-preview\n // free model, and like its sibling it is not routed under ZDR. Re-read from\n // the 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: it is listed in BOTH\n // anchor sets in all three, so an earlier note here claiming it entered\n // through `modelSupportsZdr` alone was wrong. The pricing page's own tip says\n // it either way: \"Free while the preview lasts. Not routed under ZDR.\"\n 'stealth/pixel-canary',\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 marks `reasoning:!0` but defines no\n * selectable `reasoning_effort` levels — they think automatically, with\n * Command Code driving the depth. `KNOWN_EFFORTS` (which mirrors the CLI's\n * effort map exactly) stays the sole source for selectable effort levels, and\n * this snapshot is not surfaced in the picker's compact description — it exists\n * for programmatic consumers.\n *\n * Source: the bundled model table (dist/cli.mjs), cross-checked with\n * https://commandcode.ai/docs/reference/cli/models. Keep in sync via the\n * dsh-commandcode-upstream skill; a model that GAINS selectable efforts leaves\n * this set for `KNOWN_EFFORTS` (Tencent Hy4 Preview, Kimi K3, the Muse Spark\n * family and MiniMax M3 all took that path).\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 then — 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 * `requiresMessagesEndpoint()` additionally treats any `claude-*` id as\n * Messages-only, so a Claude model added upstream (`claude-opus-5-5` in\n * command-code@1.64.0 was the first this snapshot missed) is still routed\n * correctly by an un-updated plugin instead of hard-failing with the 400\n * above. The worst case of that rule going stale the other way (upstream\n * teaching `/provider/v1/chat/completions` to serve Claude) is one model\n * riding the CLI transport it already works on.\n *\n * Keep in sync when models ship (see the dsh-commandcode-upstream skill).\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`,\n * `/docs/plans/max` and `/docs/resources/pricing-limits`). Each plan's model\n * list is a superset of the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.\n * Models absent from every plan list (Claude Opus/Fable, Fugu Ultra) are\n * Provider-tier. Re-verified at command-code@1.68.0 (2026-09-29): 84 catalog\n * ids at 53/62/76/84 cumulative, a strict superset chain — every release since\n * 1.49.0 has been additive with no tier move, and per-entry tags below name the\n * release that added each row.\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 (53) ---\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; listed on the Go plan page.\n 'Qwen/Qwen3.8-Max-0902': 'go',\n // command-code@1.56.0; the pricing page's embedded availability grants every\n // tier (individual-go through teams-pro) — the \"all\":true shape shared by the\n // Qwen 3.8 family and the stealth-preview models below.\n 'Qwen/Qwen3.8-Omni-Flash': 'go',\n // command-code@1.39.0; Go-tier like the rest of the DeepSeek V4 family.\n 'deepseek/deepseek-v4-flash-fast': 'go',\n // command-code@1.53.0; every plan including Go.\n 'deepseek/deepseek-v4.1-flash': 'go',\n // command-code@1.67.0; individual-go true, so Go-tier like the rest of the\n // DeepSeek V4 family.\n 'deepseek/deepseek-v4.1-flash-fast': '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; the opensource-category GPT-6, on every plan including\n // Go, unlike its premium-category siblings Sol (Pro) and Astra (Provider/Max).\n 'gpt-6-luna': 'go',\n // command-code@1.42.0 added the free LongCat 2.0 on every plan; that promo\n // ended 2026-09-19 and the catalog renamed the id to the paid\n // `meituan/LongCat-2.0` ($0.30/$1.20/$0.006), which keeps this slot. The CLI\n // followed in command-code@1.58.0, marking the retired `:free` sibling\n // `hidden`, so its registry now agrees with the catalog this map is keyed by.\n 'meituan/LongCat-2.0': 'go',\n // command-code@1.52.0; free on every plan (\"up to 100 requests a day\"),\n // successor to the retired `inclusionai/ling-3.0-flash-free` promo.\n 'inclusionai/ling-3.0-flash-sante:free': 'go',\n // command-code@1.44.0; on every plan including Go, like its 1.2 Contributor\n // 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; every tier, and listed by the Go/GOAT/Pro/Max plan\n // pages alike — the superset chain this map encodes.\n 'stepfun/Step-5-Preview': 'go',\n // command-code@1.66.0; all-tiers availability, so a Go model every higher\n // plan also serves. Free during the stealth preview (see KNOWN_DEALS).\n 'stealth/pixel-canary': 'go',\n // command-code@1.65.0; all-tiers availability. Free during the stealth\n // 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 the MiMo V2.6 family; these two are on every tier\n // (the Go plan page lists both), while the Pro UltraSpeed sibling is GOAT —\n // individual-go is what separates them.\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; the \"all\":true shape shared with its\n // `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 (9 more) ---\n // command-code@1.68.0; individual-go false, individual-goat true — \"Available\n // on GOAT and above\", one tier ABOVE its `claude-sonnet-5` predecessor, which\n // sits in the Pro block below.\n 'claude-sonnet-5-5': 'goat',\n 'google/gemini-3.7-flash': 'goat',\n // command-code@1.43.0; \"Available on GOAT and above\", like the rest of the\n // 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; \"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; \"Available on GOAT and above\" (individual-go false).\n 'xai/grok-4.7': 'goat',\n // command-code@1.62.0; GOAT and above, the same split as its Grok 4.7\n // sibling. Its two cheaper V2.6 siblings are Go, 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; Pro and above (individual-go/goat false).\n 'gpt-6-sol': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider / Max (8) ---\n // command-code@1.40.0; Provider/Max exactly like its `claude-fable-5`\n // predecessor — individual-provider/max/ultra and teams-pro only.\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; Provider API only (go/goat/pro/pro-v1 all false), and\n // the catalog serves it with supported_endpoints ['/messages'] — the Claude\n // route, which the adapter's `claude-*` prefix rule already sends down the\n // CLI transport.\n 'claude-opus-5-5': 'provider',\n 'claude-opus-5': 'provider',\n // command-code@1.49.0; on Max.\n 'gpt-6-astra': 'provider',\n 'sakana/fugu-ultra': 'provider',\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 `dist/cli.mjs`, re-verified unchanged\n * through command-code@1.68.0): subscription `planId` prefix → display name and\n * the plan's monthly credit total. This is the account's own subscription\n * (from `/alpha/billing/subscriptions`) — distinct from {@link KNOWN_PLANS},\n * 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, shown as a `FREE`\n * badge; it degrades to a plain discount once the deal lapses.\n *\n * A deal whose promo ENDS is removed here rather than left to lapse on\n * `expiresAt`: the pricing page drops the entry, so a lapsed row would badge a\n * model the catalog now serves at full price (Grok 4.7 reverts to $2.00 in /\n * $6.00 out after its 2026-09-27 window).\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 '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; the expiry is stamped from the page's own `deal`\n // record so the badge lapses by itself, while the vendored rate row keeps the\n // discounted figures ($1.20 in / $3.60 out / $0.30 cache read, doubling past\n // 200K) — exactly like the other percentage deals here.\n 'xai/grok-4.7': { label: '40% off', expiresAt: '2026-09-27T23:59:59.999Z' },\n 'poolside/laguna-s-2.1-free': { label: 'FREE', free: true },\n // command-code@1.52.0; free \"up to 100 requests a day\" with no published end\n // date, so a permanent-style deal like the stealth previews below.\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, no\n // published end date), and command-code@1.66.0 added Pixel Canary on\n // identical terms. Neither is routed under ZDR (see\n // KNOWN_NON_ZDR_MODELS), and the pricing page publishes both at a literal\n // zero, which `modelPriceTable()` serves from these deals — so neither gets a\n // row in the vendored price table.\n 'stealth/space-bunny-alpha': { label: 'FREE', free: true },\n 'stealth/pixel-canary': { 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 * Exactly five models carry the page's `timeOfDay` block (the five rows below).\n * The picker shows the *current* state as a compact label (`Peak`/`Half`)\n * matching the English noun style of the other markers (`Image`, `FREE`), so a\n * developer can tell at a glance whether calling the model right now is cheap\n * or expensive.\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. A rate that is\n * internally consistent can still be the wrong row (the V4 Flash Vision (exp)\n * variant is priced from the page's own `timeOfDay` block, not from 2× its own\n * off-peak figures), which is why the vendored price table\n * (`./model-prices.ts`) is synced from the page and not hand-kept.\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; the same `timeOfDay` block as the other three\n // (off-peak $0.15/$0.60, peak $0.30/$1.20, 01–04 & 06–10 UTC Mon–Fri).\n 'deepseek/deepseek-v4.1-flash',\n // command-code@1.67.0; the same 01–04 & 06–10 UTC Mon–Fri windows and the same\n // 2026-08-16T16:00Z effective date, at its own rates (off-peak\n // $0.16/$0.58/$0.016, peak $0.32/$1.16/$0.032) — note these are NOT 2× the\n // sibling's, so this row must come from its own `timeOfDay` block.\n 'deepseek/deepseek-v4.1-flash-fast',\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 return peakHour(now, PEAK_HOUR_RANGES)\n}\n\n/**\n * As {@link isPeakPricingHour}, plus the {@link KNOWN_PEAK_PRICING} membership\n * test; `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 * 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 pricing\n * page publishes, which is what lets the composer price a session in dollars.\n * Every figure is USD per 1,000,000 tokens.\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.\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 * Discounted rows carry both price sets. The page publishes a deal's\n * PROMOTIONAL rates as the row's ordinary figures and its pre-discount\n * `listRates` alongside, so the generator copies both and the table picks\n * between them with `dealLabel()`'s clock. That keeps a lapsed discount from\n * pricing a session below what the provider now charges — the same \"a stale\n * snapshot never shows a lapsed discount\" rule the picker badge follows, applied\n * to dollars rather than to a label. The page's own `discountPercent` is NOT\n * used for this: it is a marketing figure that does not divide out (MiMo V2.5's\n * \"98% off\" prices three buckets at 5.7×, 14.3× and 57× of list).\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 only the rows.\n * `--check` reports drift without writing (exit 1 on drift, exit 2 when the\n * page could not be read, so a network failure never reads as \"up to date\").\n * Everything else in this file — this doc, the types, the slug rules, the\n * 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, dealLabel, isFreeModel } from './capabilities.ts'\nimport { PLAN_ORDER } from './plan-tiers.ts'\n\n/** One pricing-page context band: the rates charged inside `maxContext` tokens. */\ninterface ModelPriceContextTier {\n readonly maxContext?: number\n readonly rates: readonly number[]\n /**\n * The band's pre-discount rates, present only for a row carrying a deal. See\n * {@link ModelPriceRow.listRates}.\n */\n readonly listRates?: readonly number[]\n}\n\n/**\n * A model's per-model monthly allowance, in USD, per plan tier.\n *\n * This is the page's `planAllowanceUsd`: how much of the plan's monthly credit\n * pool this ONE model may draw. It is not extra money — every allowance draws\n * on the same pool — and the page publishes it for GOAT and Pro only (\"the\n * boost is a per-model allowance, so it lives on the plans that have them\"), so\n * there is no `go`, `max` or `provider` figure to read. Deals are baked in:\n * `MiniMaxAI/MiniMax-M3` carries `$47 / $57` precisely because its 2× promotion\n * is already folded into the allowance.\n */\nexport interface ModelAllowance {\n readonly goat: number\n readonly pro: number\n}\n\n/**\n * The plan tiers a per-model allowance exists for, cheapest first. Ordering\n * matters: {@link allowanceTierForWeight} matches a tier weight against these\n * rather than against hard-coded numbers, so this table and the subscription\n * table cannot drift apart silently.\n */\nconst ALLOWANCE_TIERS = ['goat', 'pro'] as const\n\n/**\n * Which allowance bracket a plan-tier weight belongs to, or undefined when that\n * plan has no per-model allowance.\n *\n * Weights come from `KNOWN_SUBSCRIPTION_PLANS` (go 0 · goat 1 · pro 2 ·\n * provider 3 · max/ultra 4) and {@link PLAN_ORDER} is the same scale, which is\n * what makes the lookup exact: Go, Provider, Max and Ultra have no published\n * allowance, and answering with a neighbouring tier's figure would be a\n * fabricated number rather than a missing one.\n */\nexport function allowanceTierForWeight(\n tierWeight: number | undefined,\n): keyof ModelAllowance | undefined {\n if (tierWeight === undefined) return undefined\n return ALLOWANCE_TIERS.find((tier) => PLAN_ORDER[tier] === tierWeight)\n}\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 *\n * `listRates` appears only on rows whose page record carries a `deal`: those\n * `rates` are the PROMOTIONAL figures, and `listRates` is what the row reverts\n * to when the deal lapses. {@link modelPriceTable} picks between the two with\n * the same clock {@link dealLabel} uses, so a discount that has expired stops\n * pricing a session at the promotional rate even before the next sync — the\n * badge and the dollars always agree. A permanent deal (no `expiresAt`) never\n * lapses, and a row with no `listRates` has nothing to fall back to.\n *\n * `allowance` is a different KIND of number from everything else here: dollars\n * per month, not dollars per million tokens. It never enters the price table —\n * {@link modelAllowanceFor} serves it to the settings page instead.\n */\ninterface ModelPriceRow {\n readonly id: string\n readonly rates: readonly number[]\n readonly listRates?: readonly number[]\n readonly peak?: readonly number[]\n readonly allowance?: ModelAllowance\n readonly contextTiers?: readonly ModelPriceContextTier[]\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], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-fable-5-1', rates: [10, 50, 0.25, 12.5], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-haiku-4-5', rates: [1, 5, 0.1, 1.25], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-opus-4-6', rates: [5, 25, 0.5, 6.25], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-opus-4-7', rates: [5, 25, 0.5, 6.25], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-opus-4-8', rates: [5, 25, 0.5, 6.25], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-opus-5', rates: [5, 25, 0.5, 6.25], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-opus-5-5', rates: [4, 20, 0.2, 5], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-sonnet-4-6', rates: [3, 15, 0.3, 3.75], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-sonnet-5', rates: [2, 10, 0.2, 2.5], allowance: { goat: 20, pro: 20 } },\n { id: 'claude-sonnet-5-5', rates: [2, 10, 0.2, 2.5], allowance: { goat: 10, pro: 20 } },\n { id: 'deepseek-v4-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { goat: 60, pro: 70 } },\n { id: 'deepseek-v4-flash-fast', rates: [0.28, 0.56, 0.07], allowance: { goat: 20, pro: 30 } },\n { id: 'deepseek-v4-flash-vision-exp', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { goat: 20, pro: 30 } },\n { id: 'deepseek-v4-pro', rates: [0.66, 1.98, 0.022], peak: [1.32, 3.96, 0.044], allowance: { goat: 20, pro: 30 } },\n { id: 'deepseek-v4.1-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { goat: 60, pro: 70 } },\n { id: 'deepseek-v4.1-flash-fast', rates: [0.16, 0.58, 0.016], peak: [0.32, 1.16, 0.032], allowance: { goat: 60, pro: 70 } },\n { id: 'fugu-ultra', rates: [5, 30, 0.5], allowance: { goat: 20, pro: 20 } },\n { id: 'gemini-3.1-flash-lite', rates: [0.25, 1.5, 0.03], allowance: { goat: 20, pro: 20 } },\n { id: 'gemini-3.5-flash', rates: [1.5, 9, 0.15], allowance: { goat: 20, pro: 20 } },\n { id: 'gemini-3.5-flash-lite', rates: [0.3, 2.5, 0.03], allowance: { goat: 20, pro: 20 } },\n { id: 'gemini-3.6-flash', rates: [1.5, 7.5, 0.15], allowance: { goat: 20, pro: 20 } },\n { id: 'gemini-3.7-flash', rates: [1.5, 7.5, 0.15, 0.08334], allowance: { goat: 40, pro: 50 } },\n { id: 'gemini-3.8-flash', rates: [1.5, 7.5, 0.15], allowance: { goat: 40, pro: 50 } },\n { id: 'glm-5', rates: [1, 3.2, 0.2], allowance: { goat: 20, pro: 30 } },\n { id: 'glm-5.1', rates: [1.4, 4.4, 0.26], allowance: { goat: 20, pro: 30 } },\n { id: 'glm-5.2', rates: [1.4, 4.4, 0.26], allowance: { goat: 70, pro: 80 } },\n { id: 'glm-5.2-fast', rates: [3, 10.25, 0.5], allowance: { goat: 20, pro: 30 } },\n { id: 'glm-5.3', rates: [1.4, 4.4, 0.26], allowance: { goat: 20, pro: 30 } },\n { id: 'glm-5.3-flash', rates: [0.15, 0.5, 0.03], allowance: { goat: 40, pro: 50 } },\n { id: 'glm-5.3-flashx', rates: [0.37, 1.25, 0.075], allowance: { goat: 20, pro: 30 } },\n { id: 'gpt-5.3-codex', rates: [2, 8, 0.5, 0], allowance: { goat: 20, pro: 20 } },\n { id: 'gpt-5.4', rates: [2.5, 15, 0.25, 0], allowance: { goat: 20, pro: 20 } },\n { id: 'gpt-5.4-mini', rates: [0.75, 4.5, 0.075, 0], allowance: { goat: 20, pro: 20 } },\n { id: 'gpt-5.5', rates: [5, 30, 0.5, 0], allowance: { goat: 20, pro: 20 } },\n { id: 'gpt-5.6-luna', rates: [0.2, 1.2, 0.02, 0.25], allowance: { goat: 20, pro: 30 }, 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], allowance: { goat: 70, pro: 80 }, 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], allowance: { goat: 20, pro: 20 }, 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], allowance: { goat: 20, pro: 20 }, 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], allowance: { goat: 20, pro: 30 }, 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], allowance: { goat: 20, pro: 20 }, 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], allowance: { goat: 20, pro: 30 } },\n { id: 'grok-4.6', rates: [2, 6, 0.5], allowance: { goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":200000,\"rates\":[2,6,0.5]},{\"rates\":[4,12,1]}] },\n { id: 'grok-4.7', rates: [1.2, 3.6, 0.3], listRates: [2, 6, 0.5], allowance: { goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":200000,\"rates\":[1.2,3.6,0.3],\"listRates\":[2,6,0.5]},{\"rates\":[2.4,7.2,0.6],\"listRates\":[4,12,1]}] },\n { id: 'inkling', rates: [1, 4.05, 0.17], allowance: { goat: 20, pro: 30 } },\n { id: 'inkling-small', rates: [0.5, 1.2, 0.1], allowance: { goat: 20, pro: 30 } },\n { id: 'kimi-k2.5', rates: [0.6, 3, 0.1], allowance: { goat: 20, pro: 30 } },\n { id: 'kimi-k2.6', rates: [0.95, 4, 0.16], allowance: { goat: 20, pro: 30 } },\n { id: 'kimi-k2.7-code', rates: [0.95, 4, 0.19], allowance: { goat: 60, pro: 70 } },\n { id: 'kimi-k2.7-code-highspeed', rates: [1.9, 8, 0.38], allowance: { goat: 20, pro: 30 } },\n { id: 'kimi-k3', rates: [3, 15, 0.3], allowance: { goat: 20, pro: 30 } },\n { id: 'longcat-2.0', rates: [0.3, 1.2, 0.006], allowance: { goat: 50, pro: 60 } },\n { id: 'mimo-v2.5', rates: [0.14, 0.28, 0.0028], listRates: [0.8, 4, 0.16], allowance: { goat: 30, pro: 40 } },\n { id: 'mimo-v2.5-pro', rates: [0.435, 0.87, 0.0036], listRates: [2, 6, 0.4], allowance: { goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-flash', rates: [0.14, 0.28, 0.0028], allowance: { goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-pro', rates: [0.435, 0.87, 0.0036], allowance: { goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-pro-ultraspeed', rates: [4.35, 8.7, 0.036], allowance: { goat: 10, pro: 20 } },\n { id: 'minimax-m2.5', rates: [0.3, 1.2, 0.03], allowance: { goat: 20, pro: 30 } },\n { id: 'minimax-m2.7', rates: [0.3, 1.2, 0.06], allowance: { goat: 20, pro: 30 } },\n { id: 'minimax-m3', rates: [0.3, 1.2, 0.06], listRates: [0.6, 2.4, 0.12], allowance: { goat: 47, pro: 57 } },\n { id: 'muse-spark-1.1', rates: [1.25, 4.25, 0.15], allowance: { goat: 20, pro: 20 } },\n { id: 'muse-spark-1.2', rates: [1.25, 4.25, 0.15], allowance: { goat: 20, pro: 30 } },\n { id: 'muse-spark-1.2-contributor', rates: [0.1, 0.2, 0.002], allowance: { goat: 20, pro: 30 } },\n { id: 'muse-spark-1.3', rates: [1.25, 4.25, 0.15], allowance: { goat: 20, pro: 30 } },\n { id: 'muse-spark-1.3-contributor', rates: [0.1, 0.2, 0.002], allowance: { goat: 20, pro: 30 } },\n { id: 'nemotron-3-ultra', rates: [0.6, 2.4, 0.12], allowance: { goat: 20, pro: 30 } },\n { id: 'qwen-3.6-max', rates: [1.3, 7.8, 0.26, 1.63], allowance: { goat: 20, pro: 30 } },\n { id: 'qwen-3.6-plus', rates: [0.5, 3, 0.1], allowance: { goat: 33, pro: 43 }, 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], allowance: { goat: 20, pro: 30 }, 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], allowance: { goat: 33, pro: 43 } },\n { id: 'qwen-3.7-plus', rates: [0.4, 1.6, 0.08, 0.5], allowance: { goat: 33, pro: 43 }, 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], allowance: { goat: 70, pro: 80 } },\n { id: 'qwen-3.8-flash', rates: [0.16, 0.47, 0.016], allowance: { goat: 20, pro: 30 } },\n { id: 'qwen-3.8-max', rates: [2, 6, 0.25, 2.5], allowance: { goat: 20, pro: 30 } },\n { id: 'qwen-3.8-max-0902', rates: [2, 6, 0.25], allowance: { goat: 20, pro: 30 } },\n { id: 'qwen-3.8-omni-flash', rates: [0.15, 0.47, 0.016], allowance: { goat: 20, pro: 30 } },\n { id: 'step-3.5-flash', rates: [0.09, 0.3, 0.02], allowance: { goat: 20, pro: 30 } },\n { id: 'step-3.7-flash', rates: [0.2, 1.15, 0.04], allowance: { goat: 20, pro: 30 } },\n { id: 'step-5-preview', rates: [1, 2.7, 0.05], allowance: { goat: 20, pro: 30 } },\n { id: 'tencent/hy3-paid', rates: [0.14, 0.58, 0.035], allowance: { goat: 70, pro: 80 } },\n { id: 'tencent/hy4-preview', rates: [0.834, 2.501, 0.042], allowance: { goat: 20, pro: 30 } },\n { id: 'typesafe/jev', rates: [0.042, 0, 0], allowance: { goat: 20, pro: 30 } },\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 map\n * of eighty 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 only ever\n // emits rows with the three published rates, so a short row is a broken table\n // 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/**\n * Build the full price row the browser prices a session with.\n *\n * Every figure switches together: once the deal stops being live, the base\n * rates AND each context band come from the pre-discount set, so a session\n * priced after a promotion ends can never mix the two.\n */\nfunction wireRow(id: string, slug: string, row: ModelPriceRow, now: number): CommandCodeModelPrice {\n // `dealLabel()` answers undefined both for \"no deal\" and for \"deal expired\";\n // `listRates` exist only on discounted rows, so the pair settles which set\n // applies. A row with one and not the other falls back to its current rates.\n const promotional = dealLabel(id, now) !== undefined\n const price: CommandCodeModelPrice = {\n id,\n slug,\n ...ratesOf(promotional ? row.rates : (row.listRates ?? row.rates)),\n }\n if (row.peak !== undefined) price.peak = ratesOf(row.peak)\n if (row.contextTiers !== undefined) {\n price.contextTiers = row.contextTiers.map((tier) => ({\n ...ratesOf(promotional ? tier.rates : (tier.listRates ?? tier.rates)),\n ...(tier.maxContext === undefined ? {} : { maxContext: tier.maxContext }),\n }))\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. Free models are served\n * explicitly at zero so the composer can say so instead of showing nothing; the\n * peak windows travel with the table so the browser applies the very schedule\n * this snapshot knows instead of restating it.\n *\n * `now` (defaults to `Date.now()`) resolves lapsed promotions: a discounted row\n * whose `expiresAt` has passed is served at its pre-discount `listRates`, the\n * same instant {@link dealLabel} stops showing its badge. The table is rebuilt\n * per request, so that switch needs no redeploy.\n */\nexport function modelPriceTable(now: number = Date.now()): 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, now))\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, now))\n }\n\n return {\n models,\n peakHours: PEAK_HOUR_RANGES.map(([start, end]) => [start, end] as [number, number]),\n }\n}\n\n/** Slug-keyed view of the rows, built once: neither table nor allowance mutates. */\nconst ROWS_BY_SLUG: ReadonlyMap<string, ModelPriceRow> = new Map(\n MODEL_PRICE_ROWS.map((row) => [row.id, row]),\n)\nconst KNOWN_SLUGS: ReadonlySet<string> = new Set(ROWS_BY_SLUG.keys())\n\n/**\n * The per-model monthly allowance for a CATALOG model id, or undefined when the\n * page carries none (a model without a price row, or the free stealth previews\n * the estimator array omits).\n *\n * Resolution rides the same slug rules as the price table, so\n * `MiniMaxAI/MiniMax-M3` finds the row the page files under `minimax-m3` — the\n * settings page must not grow a second mapping that can drift from this one.\n * The settings page asks for a model only while rendering a list it already\n * has, so this stays a pure lookup with no clock: an allowance is not\n * time-dependent (a plan's figure does not lapse the way a promotional rate\n * does; when the page re-prices it, the next sync carries it).\n */\nexport function modelAllowanceFor(modelId: string): ModelAllowance | undefined {\n const slug = priceSlugFor(modelId, KNOWN_SLUGS)\n if (slug === undefined) return undefined\n return ROWS_BY_SLUG.get(slug)?.allowance\n}\n\n","/** Non-throwing value guards for untrusted provider payloads. */\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport function stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nexport function numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nexport function booleanValue(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\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'\nimport { isRecord } from './wire-guards.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 => isRecord(v) ? v : 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 // One pass over the groups replaces the two linear `find` scans; the\n // first index wins, matching `find` on duplicate keys.\n const byKey = new Map<string, number>()\n groups.forEach((g, i) => { const key = costGroupKey(g, table); if (!byKey.has(key)) byKey.set(key, i) })\n const groupKey = costGroupKey(group, table)\n if (previous) {\n const old = byKey.get(costGroupKey(previous, table))\n if (old !== undefined) for (const k of COST_TOKEN_KEYS) groups[old]!.tokens[k] -= previous.tokens[k]\n }\n const targetIdx = byKey.get(groupKey)\n let target = targetIdx === undefined ? undefined : groups[targetIdx]\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 subscription's 5-hour window is metered, and a user with several wants a\n * request that hits one account's limit to continue on the next without a\n * visible failure. Rotation is passive: a key is marked only on a real\n * pre-stream rejection, and when nothing can serve, marked keys are revived by\n * probing their real usage windows.\n *\n * The non-obvious rules — which rejection may be REPORTED as a spent window, why\n * a fallback is never permanent, what an explicitly selected account's probe\n * costs — are stated at the members below, and recorded in full in AGENTS.md.\n *\n * Cordis-free like the adapter: every host fact arrives through injected thunks,\n * so node tests can drive the pool 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 attached to the all-exhausted `RATE_LIMIT`.\n * Must equal the adapter's `backoff.maxDelayMs`: dsh-llm-retry honors a\n * provider wait verbatim only at or below that cap — a longer one abandons the\n * retry instead of falling back to local backoff, turning \"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. Without this, a single 429 on the user's pinned\n * account demotes it until the process restarts (issue #51); probing at most\n * once per interval per key bounds a probe endpoint that keeps failing.\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, split by EVIDENCE — what the pool may\n * claim about it — rather than by what it does.\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 plain\n * 429: the key leaves rotation for now, but the provider said nothing about a\n * window, so the pool must not describe one as exhausted. Collapsing the two is\n * issue #54: a bare 429 was reported as a spent window while the account card\n * showed both windows barely used.\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 that\n * no account can serve. `window`: the provider named a usage window, or a\n * `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429 that\n * said nothing about a window (a burst limiter, or a model-/spend-level limit\n * 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 /** Probe one key's usage windows (BOTH windows the endpoint publishes); undefined when it failed. */\n probeWindow(apiKey: string): Promise<AccountWindowProbe | undefined>\n /**\n * The manually selected account slot id, re-read per resolution. It serves\n * whenever it is usable; an unknown id or an exhausted preferred account falls\n * back to the first usable slot — and an exhausted one is re-probed on the way\n * (see {@link CommandCodeAccountPool.resolveKey}), so the fallback lasts only\n * 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. A matching, usable routed account serves before the\n * preferred/rotation selection; an unusable one falls back to the normal\n * 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, so the \"the interval\n * elapsed\" half of {@link CommandCodeAccountPool.canProbeExplicit} is testable\n * without 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 extra\n * account's credential reference). 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 is\n * usable, otherwise the first usable account in rotation order; undefined when\n * no account is usable. Shared by the pool (request path) and the plugin entry\n * (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 usable, else\n * the manually preferred account when usable, else the first usable account\n * in rotation order. Returns `undefined` when no account resolves any key,\n * or when an account this request already used is still UNMARKED — the\n * caller's own rejection is the honest answer then. Throws `RATE_LIMIT` /\n * `INVALID_CREDENTIAL` when every account is marked.\n *\n * `options.tried` lists the keys this request already used; they are removed\n * from the resolution entirely, which is what lets one request walk a\n * four-account pool. An explicit selection (pin or model rule) that a\n * rate-limit mark would demote is probed first, so a fallback never becomes\n * permanent (issue #51). Rules re-read per resolution, so settings apply live.\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: an UNMARKED account\n // leaves the caller's own rejection as the honest answer; when every\n // account is marked instead, the pool owes its own diagnosis — built from\n // the marks as they stand, WITHOUT probing (a probe here answers a\n // question this request cannot act on).\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 one): it must\n // 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 this.stampWindowMark(account, probe)\n }))\n\n // Re-resolve once: the probe pass above may have revived keys, and both the\n // revival check and the error classification read the same post-probe\n // snapshot. (Each resolvedAccounts() re-runs the async seams, so two calls\n // is the minimum here.) The tried keys stay filtered out: a probe that\n // cleared one must not re-offer a key this request already burned.\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 used\n // may be UNMARKED, because an `unavailable` rejection (no credits, a model\n // outside this account's plan) deliberately marks nothing, and that\n // rejection is the honest answer: returning undefined is how the caller\n // surfaces it. The pool's own diagnosis would name the wrong cause, count\n // only the tried subset, and hand dsh-llm-retry a wait that turns a\n // PERMANENT failure into a ~15-minute stall. The all-tried branch above\n // applies exactly this rule.\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. A `throttled` rejection (the plain 429\n * that named no window) marks the key with the `throttle` cause, leaving\n * rotation exactly like a window mark but keeping the pool's own diagnosis at\n * \"rate limited\" rather than inventing an exhausted window. `rate-limit`\n * marks a `cooldown` until `resetAtMs` when the body named the provider's own\n * reset, otherwise an `unknown` mark whose window is probed lazily.\n * `invalid-credential` (401) disables the key until the stored credential\n * changes.\n *\n * `resetAtMs` is seconds-to-millis converted by the adapter from\n * `error.rateLimit.reset`; it applies to a window mark only. A plain throttle\n * keeps its 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 the `unknown` mark is what keeps the key eligible for\n // the window probe that can still find a real one.\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\n * `assertUsableApiKey()`, which trims it, and reports that trimmed form back\n * to {@link markRejected}: returning the raw value would file every 429/401\n * mark under a key no later lookup can find — rotation would re-offer the same\n * account, the account card would show no mark, and the usage endpoints would\n * 401 while chat kept working.\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 the\n * request to when that id exists among the resolved slots, else the manually\n * pinned slot. Consulted only on the fallback path, so — unlike\n * {@link selectAccountForModel} — it does NOT require the account to be usable,\n * 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` carries its reset and expires by itself, and a\n * `disabled` (401) key stays out until the stored credential changes. The\n * 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 as\n * 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. The\n // stamp costs nothing when the revival was right: a serving account is\n // never probed at all.\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` — see `stampWindowMark`.\n this.stampWindowMark(account, probe)\n return undefined\n }\n\n /**\n * Stamp a probe-read window onto one key. A known reset becomes a cooldown\n * that expires by itself; without one the mark stays `unknown`, so a later\n * probe can still learn it — and a mark that already carries a cooldown\n * keeps it, never trading a known reset for an unknown one. The cause is\n * `window` either way: a probe that read a window as exceeded IS window\n * evidence, whatever the key was marked for. An `until: 0` cooldown would\n * read as \"never usable again\" to {@link accountUsable}, so `unknown` it is.\n */\n private stampWindowMark(account: ResolvedAccount, probe: AccountWindowProbe): void {\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 /** 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.\n * Claiming \"all accounts have exhausted their usage window\" here is issue\n * #54: a bare 429 was reported that way while the account card showed both\n * windows barely used.\n *\n * The attached `providerRetryAfterMs` is the exact wait until the earliest known\n * window reset, so dsh-llm-retry sleeps through the window instead of polling at\n * its backoff cadence. It is capped at {@link RETRY_MAX_DELAY_MS} — see there for\n * why a longer attached wait is worse than a capped one; longer resets simply\n * ride the capped local backoff and the probe revival. A throttle diagnosis\n * attaches none: its marks carry no reset.\n *\n * Shared by the all-marked tail of {@link CommandCodeAccountPool.resolveKey} and\n * by its already-tried diagnosis, so the two can never drift apart.\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 metered\n // window is spent — and because it carries no reset (`unknown`, so the next\n // pass may probe), this answer has no time to name one. dsh-llm-retry's own\n // 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 (`{ width, height, maxBytes }`, passed straight to its\n * encoder).\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 * @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.\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. This local guard is the ONLY\n * reason the function is not imported; do not replace it with the upstream one.\n * `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 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, so the estimate is per\n * FAMILY, using each vendor's published rule, and the families are recognised\n * by the catalog id (which names the vendor). Every formula is stated here\n * rather than imported: the only in-tree implementations live inside the\n * official adapters, and this plugin deliberately does not depend on those\n * protocols. These are ESTIMATES for context accounting, not invoices — the\n * provider's own usage remains authoritative for a completed request.\n *\n * @module dsh-commandcode-provider/image-tokens\n */\n\nimport { longEdgeDimensions, REQUEST_IMAGE_MAX_LONG_EDGE } 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 to the request long edge (never\n * 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, REQUEST_IMAGE_MAX_LONG_EDGE)\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, a proxy or the network closes the socket mid-generation,\n * so the adapter's read loop sees `done` without the transport's terminal event.\n * A provider cut, a proxy timeout and a dropped socket are indistinguishable\n * from inside the adapter; only the raw wire separates them — which events\n * arrived, when the last one landed, how long the socket then sat silent.\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 read as \"off\" rather than as a file name.\n *\n * Every model request appends one JSONL record per raw chunk plus lifecycle\n * records (`request`, `response`, `eof`, `idle-timeout`, `read-error`, `end`,\n * `stream-close`), each stamped with `streamId` and `at` — milliseconds since\n * the trace opened, before connecting. `stream-open.startedAt` is Unix time in\n * milliseconds, so interleaved calls and session logs can be correlated.\n *\n * PRIVACY: the chunk records carry the provider's own payload verbatim, because\n * a truncated answer is exactly what is being diagnosed — treat the file as\n * conversation content, not as a log safe to share. The request-side record\n * records structural counts and SHA-256 fingerprints only; it never carries the\n * raw request body, an API key, or any request header. Keep it that way.\n *\n * Trade-offs: OFF costs one `process.env` read per request; ON appends\n * synchronously, one file open per chunk, because the trace must survive a host\n * killed mid-diagnosis. A trace that cannot be written turns itself off rather\n * than failing the request it observes — a diagnostic must never become the\n * outage.\n *\n * @module\n */\n\nimport { appendFileSync, mkdirSync } from 'node:fs'\nimport { randomUUID } from 'node:crypto'\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 and 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 only: one\n * bounded `end` and `stream-close` can still follow, so a long reasoning phase\n * 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` 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 const streamId = randomUUID()\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, streamId, ...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, streamId, 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', startedAt })\n return {\n get enabled() { return !stopped && !capped },\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 * Owns the two chat transports (`/alpha/generate`, `/provider/v1/chat/completions`),\n * message conversion, SSE/JSONL parsing, the catalog + its on-disk cache, and\n * the pre-stream account rotation loop. The wire protocol is\n * reverse-engineered (command-code@1.28.4, re-verified through 1.68.0);\n * AGENTS.md holds the full protocol record.\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 { createHash, randomUUID } from 'node:crypto'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef, RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ProviderRequestId,\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 { allowanceTierForWeight } from './model-prices.ts'\nimport { boundTraceText, openStreamTrace, STREAM_TRACE_ENV } from './stream-trace.ts'\nimport { booleanValue, isRecord, numberValue, stringValue } from './wire-guards.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/** Keep the two user-facing languages and error metadata together. */\nfunction bilingual(code: string, en: string, zh: string, options?: LlmErrorOptions): LlmError {\n return new LlmError(`${en};${zh}`, code, options)\n}\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.68.0'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\n\n/**\n * The output budget this bundle asks for, and the ceiling it will never exceed.\n *\n * 131 072, chosen against a measured provider limit rather than a round guess.\n * Probing `/alpha/generate` directly on 2026-09-28: 64 000 → 200, 131 072 → 200,\n * 196 608 → 200, **200 000 → 200, 200 704 → 400**, 1 000 000 → 400. The server\n * therefore caps `max_tokens` at 200 000, and it does so identically for a\n * 262 144-window model (`stealth/pixel-canary`) and a 1 000 000-window one\n * (`stealth/space-bunny-alpha`) — the cap is global, not per model. 131 072\n * keeps a 35 % margin under it while covering the real output ceiling of the\n * models that have one (Claude 64 K, Gemini 64 K, several at 128 K).\n *\n * The old 64 000 was never a provider requirement: it cost nothing in latency\n * (a 64 000 request answered headers in 1.28 s against 1.57 s for 131 072) but\n * it did cap what a model could ever say in one turn.\n *\n * This is only an UPPER bound. `requestContextBudget` lowers it per request\n * from the prompt actually being sent, so raising the ceiling cannot push a\n * large session over its window.\n */\nexport const DEFAULT_GENERATE_MAX_TOKENS = 131_072\n\n/**\n * The fallback when the catalog carries no output ceiling for a model.\n *\n * `/provider/v1/models` publishes only `context_length` — no output limit — so\n * the catalog cannot learn one per model and derives a stand-in from the\n * window instead. Kept equal to {@link DEFAULT_GENERATE_MAX_TOKENS} on purpose:\n * a lower value here would silently re-cap every request through\n * `Math.min(contextLength, this)` before the ceiling above is ever consulted.\n */\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 131_072\n/** Preserve a small usable answer budget when the heuristic overshoots. */\nconst MIN_CONTEXT_OUTPUT_TOKENS = 1_024\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/**\n * Head-of-request timeout: how long to wait for the first response byte.\n *\n * 300 s, and that number is the official CLI's, not a round choice. Decompiled\n * from `command-code@1.66.0`: its `createNodeTransport` fetch passes only the\n * caller's `signal` and sets no timeout at all, so the model request inherits\n * Node/undici's own default — measured at 301.0 s against a local server that\n * accepts the connection and never sends headers. The previous 60 s default was\n * five times stricter than the CLI it emulates, and being stricter only ever\n * costs legitimate requests: a slow upstream first token on the Provider API\n * route can outlast 60 s, and the official CLI simply waits it out. Measured\n * headers (2026-09-28, 26 250-token prompt, `max_tokens: 16` to separate the\n * header from the generation): `/alpha/generate` 2.12 / 2.56 / 2.75 s,\n * `/provider/v1/chat/completions` 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap\n * with the Provider API route varying over a 2.5 s span against the CLI route's\n * 0.6 s. A gateway that is genuinely dead now takes longer to name itself,\n * which is what the consecutive-timeout streak exists to bound (three\n * attempts, then a diagnosis instead of another re-send).\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 300_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\n// ---------------------------------------------------------------------------\n\n/** A size-and-hash summary safe to put in an opt-in diagnostic trace. */\ninterface ValueFingerprint {\n bytes: number\n sha256: string\n}\n\n/** Hash one request value without retaining or logging its contents. */\nfunction fingerprintValue(value: unknown): ValueFingerprint {\n let serialized: string\n try {\n serialized = JSON.stringify(value) ?? String(value)\n } catch {\n serialized = String(value)\n }\n return {\n bytes: Buffer.byteLength(serialized),\n sha256: createHash('sha256').update(serialized).digest('hex'),\n }\n}\n\n/**\n * Structural request facts for issue #64's cache diagnosis.\n *\n * This deliberately records hashes and counts, never the prompt, tool\n * descriptions, image bytes, headers, or credentials. `body` catches changes\n * in any wire field; the named sections make a changed system/tools/messages\n * prefix visible without making the trace a copy of the conversation.\n */\nfunction requestFingerprint(protocol: CommandCodeProtocol, body: Record<string, unknown>): Record<string, unknown> {\n const params = protocol === 'cli' ? recordOrEmpty(body.params) : body\n const messages = Array.isArray(params.messages) ? params.messages : []\n const tools = Array.isArray(params.tools) ? params.tools : []\n return {\n protocol,\n model: typeof params.model === 'string' ? params.model : undefined,\n threadId: typeof body.threadId === 'string' ? body.threadId : undefined,\n body: fingerprintValue(body),\n config: fingerprintValue(body.config),\n system: fingerprintValue(protocol === 'cli' ? params.system : messages.filter((m) => isRecord(m) && m.role === 'system')),\n tools: {\n count: tools.length,\n ...fingerprintValue(tools),\n },\n messages: {\n count: messages.length,\n roles: messages.map((message) => isRecord(message) && typeof message.role === 'string' ? message.role : 'unknown'),\n ...fingerprintValue(messages),\n // Whole-history hashes change on every append. Per-message hashes let\n // adjacent requests identify the first changed byte-bearing message.\n items: messages.map((message) => fingerprintValue(message)),\n },\n }\n}\n\n/** Only provider correlation headers, never a wholesale response-header dump. */\nconst RESPONSE_ID_HEADERS = ['x-request-id', 'request-id', 'x-trace-id', 'x-generation-id', 'traceparent'] as const\n\nfunction responseIdentifiers(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {}\n for (const name of RESPONSE_ID_HEADERS) {\n const value = diagnosticId(headers.get(name))\n if (value !== undefined) result[name] = value\n }\n return result\n}\n\nfunction diagnosticId(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 && value.length <= 512 ? value : undefined\n}\n\n/** Small, JSON-only response facts that DSH can retain on the assistant source. */\ninterface ResponseMetadata {\n protocol: CommandCodeProtocol\n headers: Record<string, string>\n responseId?: string\n generationId?: string\n providerRequestId?: string\n traceId?: string\n}\n\nfunction captureResponseIdentifiers(metadata: ResponseMetadata, event: unknown): void {\n if (!isRecord(event)) return\n // An OpenAI completion id or an AI SDK response-metadata id names the\n // response. A tool-call id does not, so never collect generic CLI event ids.\n if ((metadata.protocol === 'openai' && Array.isArray(event.choices)) || event.type === 'response-metadata') {\n const id = diagnosticId(event.id)\n if (id !== undefined) metadata.responseId = id\n }\n for (const name of ['generationId', 'providerRequestId', 'traceId'] as const) {\n const id = diagnosticId(event[name])\n if (id !== undefined) metadata[name] = id\n }\n}\n\nfunction hasResponseIdentifiers(metadata: ResponseMetadata): boolean {\n return Object.keys(metadata.headers).length > 0 || metadata.responseId !== undefined\n || metadata.generationId !== undefined || metadata.providerRequestId !== undefined || metadata.traceId !== undefined\n}\n\n/** Keep the provider's request id on DSH's durable failure, when it supplied one. */\nfunction failureWithRequestId(error: unknown, metadata: ResponseMetadata): unknown {\n const id = metadata.providerRequestId ?? metadata.headers['x-request-id'] ?? metadata.headers['request-id']\n if (!(error instanceof LlmError) || error.failure.requestId !== undefined || id === undefined) return error\n return new LlmError(error.message, error.code, {\n ...error.failure,\n requestId: ProviderRequestId(id),\n ...(error.cause === undefined ? {} : { cause: error.cause }),\n })\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 }` — the same summary text the\n * scalar `delta.reasoning` carries. A `type` filter would drop one family, and\n * losing thinking is the failure this exists to prevent. `text` wins per entry,\n * but an EMPTY `text` must not shadow a populated `summary` (the Responses wire\n * emits `text: ''` placeholders), so the fallback tests for non-empty rather\n * than merely present. Encrypted-blob entries carry neither member and\n * contribute nothing; no entry carries both, so nothing is 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: ''`), and `??` alone cannot express that.\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/** A gateway refusal observed for an over-reserved request, but not unique to that cause. */\nconst AMBIGUOUS_SIZE_REJECTION = /\\bmodel could not complete the request\\b/i\n\n/**\n * The advice floor for a Provider-API timeout: doubling a 60 s budget is still\n * short for a slow upstream first token, so the suggestion never goes below 5\n * minutes. Capped by `RETRY_MAX_DELAY_MS` rather than the schema's timer\n * ceiling on purpose — a single header wait that outlasts the whole retry\n * backoff is not a budget, and clamping to the engine constant would also pull\n * a runtime dependency into the bundle.\n */\nconst MIN_SUGGESTED_TIMEOUT_MS = 300_000\n\n/**\n * Why one attempt saw no response headers, and what the user can do about it.\n *\n * The TRANSPORT is the reliable signal; the request size is not — and the\n * mechanism is read straight out of the official CLI rather than inferred from\n * a timing. `createNodeTransport` passes only the caller's `signal` and sets no\n * timeout, so the two routes differ in WHO answers the headers:\n * `/alpha/generate` has the gateway answer them before the model starts, while\n * `/provider/v1/chat/completions` cannot answer until its upstream emits a\n * first token, so whatever that upstream is doing is charged to the header\n * wait. Measured 2026-09-28 (26 250-token prompt, `max_tokens: 16`):\n * `/alpha/generate` 2.12 / 2.56 / 2.75 s, `/provider/v1/chat/completions`\n * 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap, with the Provider API route\n * swinging across 2.5 s where the CLI route moved 0.6 s. A larger prompt moves\n * neither, which is why an earlier draft that branched on a 1 MiB body\n * threshold was wrong: size is not the variable here. Only the route decides.\n *\n * @param protocol - the transport the attempt used.\n * @param timeoutMs - the header budget that just expired.\n */\nexport function headersTimeoutAdvice(\n protocol: CommandCodeProtocol,\n timeoutMs: number,\n): { cause: 'gateway' | 'upstream-first-token'; suggestionMs?: number } {\n if (protocol === 'openai') {\n return {\n cause: 'upstream-first-token',\n // That route charges the upstream's time-to-first-token to this wait, so\n // a larger budget is the one thing that can help when it expires.\n suggestionMs: Math.min(RETRY_MAX_DELAY_MS, Math.max(timeoutMs * 2, MIN_SUGGESTED_TIMEOUT_MS)),\n }\n }\n return { cause: 'gateway' }\n}\n\n/**\n * How many consecutive header timeouts on ONE unchanged payload stop being a\n * blip. The retry policy whitelists `TIMEOUT` with `maxRetries: 1000` and a\n * 500 ms → 15 min backoff, which is right for a provider that says when to\n * come back but wrong for a gateway that simply never answers: the reporter\n * saw the identical multi-megabyte body re-sent for hours (issue #67) instead\n * of a diagnosis. Three is where a 60 s budget has already spent three\n * minutes waiting, so the cost of being wrong is bounded and the user gets an\n * answer either way.\n */\nconst MAX_CONSECUTIVE_HEADER_TIMEOUTS = 3\n\n/** UTF-8 byte length, computed only on the timeout path so a large body is encoded once, not per attempt. */\nfunction utf8ByteLength(text: string): number {\n return new TextEncoder().encode(text).length\n}\n\n/**\n * The thrown headers timeout, worded for the cause it actually has.\n *\n * Every earlier version of this message said \"通常是网络或代理问题\" for both\n * transports, which is actively wrong for a large `/provider/v1/chat/completions`\n * prompt: there the model simply needs longer than any budget, and a user sent\n * to check their proxy never finds anything. The code stays `TIMEOUT` (still\n * retryable) in both branches — only the diagnosis and the advice change.\n */\nfunction headersTimeoutError(input: {\n protocol: CommandCodeProtocol\n endpoint: string\n body: string\n timeoutMs: number\n cause: unknown\n}): LlmError {\n const { protocol, endpoint, timeoutMs, cause } = input\n const bytes = utf8ByteLength(input.body)\n const megabytes = `${(bytes / 1_048_576).toFixed(1)} MB`\n const advice = headersTimeoutAdvice(protocol, timeoutMs)\n if (advice.cause === 'upstream-first-token') {\n const suggestion = advice.suggestionMs ?? timeoutMs\n return bilingual(\n 'TIMEOUT',\n `Command Code API request to ${endpoint} did not respond within ${timeoutMs}ms: this route withholds response headers until the upstream model emits its first token, and it did not start within the budget. Raise \"Request timeout\" in the plugin's advanced settings to ${suggestion}ms, or compact the session or start a new one. The request body was ${megabytes}, but size is not the cause here — a slow upstream is. ${errorChain(cause)}`,\n `Command Code API 请求在 ${timeoutMs} 毫秒内未收到响应:该路由要等上游模型吐出第一个 token 才返回响应头,而上游在预算内没有开始作答。可在插件「高级」设置里把「请求超时」调到 ${suggestion} 毫秒,或压缩上下文 / 新开会话。本次请求体约 ${megabytes},但体积不是原因——慢的是上游。(${errorChain(cause)})`,\n { cause },\n )\n }\n return bilingual(\n 'TIMEOUT',\n `Command Code API request to ${endpoint} did not respond within ${timeoutMs}ms: the gateway returned no response headers at all — it answers headers itself before the model replies. This is usually provider queueing, a Go-plan capacity limit, or a network/proxy path problem; a longer timeout will not help, but retrying usually recovers. The request body was ${megabytes}, and size is not the cause on this route. ${errorChain(cause)}`,\n `Command Code API 请求在 ${timeoutMs} 毫秒内未收到响应:网关完全没有返回响应头——它会在模型开始回答前先返回响应头。这通常是服务商排队、Go 套餐容量限制,或网络/代理链路问题;调大超时不会有帮助,重试通常可恢复。本次请求体约 ${megabytes},而在该路由上体积不是原因。(${errorChain(cause)})`,\n { cause },\n )\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, the Provider API transport as a top-level `error` member of\n * 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). Order is 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. Reported as retryable `SERVER` instead, the adapter resent\n * the byte-identical oversized request up to `maxRetries` times and the\n * session could never recover (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.\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 bilingual(\n CONTEXT_WINDOW_EXCEEDED_CODE,\n `Command Code stream error: ${message}`,\n 'Command Code API 拒绝了这次请求:内容超出模型上下文窗口。正在压缩上下文后重试;如仍失败,请新建会话或减少上下文',\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` and handed to dsh-llm-retry's 1000-attempt cadence.\n // An explicit `isRetryable: true` still 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). The gateway validates every function\n// schema's ROOT as an object schema and rejects the whole request otherwise.\n// Tool schemas do not always come from the harness's own typed builder: 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.\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 * Only the root is touched and every path returns a copy: the harness may\n * deep-freeze the caller's schema.\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, the last\n// fallback in the plugin entry's resolution order. 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\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 — as a `reasoning` block on\n// `/alpha/generate` (the official CLI's `toWireMessages` shape) and as\n// `reasoning_content` on `/provider/v1/chat/completions` — because DeepSeek's\n// thinking-mode contract requires the previous chain of thought to be passed\n// back whenever tool calls are in play (issue #34). Only tool calls with a\n// paired tool result are 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 (`MessageRoleMap.tool` is\n * the only role a tool result can arrive on). Pairing and emission MUST agree\n * on this same view, or a dropped result either drops its call too (making the\n * model forget completed work) or leaves an 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, and the harness log keeps the\n * 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: a turn's carriers are\n * emitted as a group after the whole tool group (issue #33), so position\n * cannot carry the association — and every `read_image` result renders the\n * same envelope text, so two parallel calls would produce two identical\n * notes. The id is the WIRE id, the one the model saw on the `tool-call` and\n * on the tool message just above, so an overlong cross-provider id is named\n * by the alias that replaced it. Count and pixel dimensions are appended\n * when the tool's own text does not already state them.\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 offload set is a DURABLE surface fact, not a local edit: the adapter\n// renders the surface's `offloaded` marks with `projectOffloadedImages`, and a\n// history that still exceeds the budget 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. The budget is accounted in the\n// encoded form, because it is the base64 the wire actually carries that has to\n// 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 count is the\n * ONE thing the harness needs: `dsh-compaction-image-offload` records it as an\n * `image/offload` event, marks that many oldest retained occurrences, and\n * 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, reason: 'budget' | 'cache' = 'budget'): LlmError {\n const options: LlmErrorOptions & { offloadImages: number } = { offloadImages: missing }\n return new LlmError(\n reason === 'cache'\n ? `commandcode cache-aware image history: ${missing} already-seen oldest image occurrence(s) must be offloaded before replay.`\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 cacheOffloadModel?: string,\n): GenerateOptions {\n const marked = policy.projectOffloadedImages(options.messages, (ref) => offloadedImageText(ref))\n const messages = marked === options.messages ? options.messages : [...marked]\n const budgetMissing = policy.requiredImageOffload(messages, coreBudget(budget), imageVersionBytes)\n const cacheMissing = cacheOffloadModel === undefined ? 0 : seenImageOffloadCount(messages, cacheOffloadModel)\n const missing = Math.max(budgetMissing, cacheMissing)\n if (missing > 0) throw imageOffloadRequired(missing, cacheMissing > budgetMissing ? 'cache' : 'budget')\n return messages === options.messages ? options : { ...options, messages }\n}\n\n/**\n * Count retained images already followed by an answer from this same model.\n * The current tool result's image has not yet been seen by the model and must\n * stay on the wire. The engine can only offload durable user/tool input nodes;\n * assistant output and request-only input have no selectable surface event.\n */\nfunction seenImageOffloadCount(messages: readonly RequestMessage[], model: string): number {\n let lastAnswer = -1\n for (let index = 0; index < messages.length; index++) {\n const message = messages[index]!\n if (message.role === 'assistant'\n && message.source.kind === 'model'\n && message.source.provider === 'commandcode'\n && message.source.model === model) lastAnswer = index\n }\n if (lastAnswer < 0) return 0\n let count = 0\n for (let index = 0; index < lastAnswer; index++) {\n const message = messages[index]!\n if ((message.role !== 'user' && message.role !== 'tool') || message.id === undefined) continue\n for (const block of message.content) {\n if (block.type === 'image') count++\n }\n }\n return count\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<RequestImageAttachment> {\n return attachments.readImageRequest(ref, requestImageTarget(ref))\n}\n\ntype ReadRequestImage = (ref: ImageAttachmentRef) => Promise<RequestImageAttachment>\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 (which\n * is what stops the meter counting an evicted image as context): a model that\n * 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 final `/alpha/generate` wire format.\n * The official CLI accepts a base64 source internally, then toWireMessages()\n * sends a data URL plus mimeType. Use the request version's media type because\n * readImageRequest() can transcode the stored image to JPEG or WebP.\n */\nasync function imageToCommandCode(\n ref: ImageAttachmentRef,\n readImage: ReadRequestImage,\n): Promise<{ type: 'image'; image: string; mimeType: string }> {\n const version = await readImage(ref)\n return {\n type: 'image',\n image: `data:${version.mediaType};base64,${Buffer.from(version.data).toString('base64')}`,\n mimeType: version.mediaType,\n }\n}\n\ninterface MessageCodec {\n encodeImage: (ref: ImageAttachmentRef, readImage: ReadRequestImage) => Promise<unknown>\n encodeUser: (parts: unknown[]) => unknown\n encodeAssistant: (\n message: Extract<RequestMessage, { role: 'assistant' }>,\n paired: ReadonlySet<string>,\n wireIds: ReadonlyMap<string, string>,\n ) => unknown | undefined\n encodeTool: (result: ToolResultView, media: ToolResultMedia, wireId: string, toolName: string) => unknown\n}\n\n/**\n * The common pairing and image-carrier ordering for both transports. Each\n * codec owns its wire shape: CLI content blocks and Chat Completions\n * reasoning/tool calls differ beyond the image envelope.\n */\nasync function convertMessages(\n messages: readonly RequestMessage[],\n readImage: ReadRequestImage | undefined,\n codec: MessageCodec,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired, names: toolNames } = pairedToolCalls(messages)\n const wireIds = wireToolCallIds(paired)\n // Consecutive tool results must precede user image carriers, including when\n // an assistant turn has several parallel calls.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n const encodeImage = (ref: ImageAttachmentRef): Promise<unknown> => {\n if (!readImage) {\n throw new LlmError('Image input requires the durable attachment service', 'UNSUPPORTED_CONTENT')\n }\n return codec.encodeImage(ref, readImage)\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') parts.push(await encodeImage(block.attachment))\n }\n if (parts.length > 0) out.push(codec.encodeUser(parts))\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const assistant = codec.encodeAssistant(message, paired, wireIds)\n if (assistant !== undefined) out.push(assistant)\n continue\n }\n\n if (!result || !paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\n const wireId = wireIds.get(result.toolCallId) ?? result.toolCallId\n out.push(codec.encodeTool(result, media, wireId, toolNames.get(result.toolCallId) || 'unknown'))\n if (media.images.length > 0) {\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireId) }]\n for (const attachment of media.images) carried.push(await encodeImage(attachment))\n pendingImages.push(codec.encodeUser(carried))\n }\n }\n flushPendingImages()\n return out\n}\n\nconst ccMessageCodec: MessageCodec = {\n encodeImage: imageToCommandCode,\n encodeUser: (parts) => ({ role: 'user', content: parts }),\n encodeAssistant: (message, paired, wireIds) => {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n else if (block.type === 'reasoning') 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 return parts.length > 0 ? { role: 'assistant', content: parts } : undefined\n },\n encodeTool: (result, media, wireId, toolName) => ({\n role: 'tool',\n content: [{\n type: 'tool-result',\n toolCallId: wireId,\n toolName,\n output: result.isError\n ? { type: 'error-text', value: toolResultTextForWire(media) }\n : { type: 'text', value: toolResultTextForWire(media) },\n }],\n }),\n}\n\nasync function messagesToCC(\n messages: readonly RequestMessage[],\n readImage?: ReadRequestImage,\n): Promise<unknown[]> {\n return convertMessages(messages, readImage, ccMessageCodec)\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: ReadRequestImage,\n): Promise<{ type: 'image_url'; image_url: { url: string } }> {\n const version = await readImage(ref)\n return {\n type: 'image_url',\n image_url: {\n url: `data:${version.mediaType};base64,${Buffer.from(version.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 */\nconst openAiMessageCodec: MessageCodec = {\n encodeImage: imageToOpenAI,\n encodeUser: (parts) => {\n const hasImage = parts.some((part) => (part as { type?: string }).type === 'image_url')\n return !hasImage && parts.length === 1\n ? { role: 'user', content: (parts[0] as { text: string }).text }\n : { role: 'user', content: parts }\n },\n encodeAssistant: (message, paired, wireIds) => {\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: { name: block.name, arguments: block.arguments },\n }))\n if (text === '' && reasoning === '' && toolCalls.length === 0) return undefined\n const assistant: Record<string, unknown> = { role: 'assistant', content: text === '' ? null : text }\n if (reasoning !== '') assistant.reasoning_content = reasoning\n if (toolCalls.length > 0) assistant.tool_calls = toolCalls\n return assistant\n },\n encodeTool: (_result, media, wireId) => ({\n role: 'tool',\n tool_call_id: wireId,\n content: toolResultTextForWire(media),\n }),\n}\n\nasync function messagesToOpenAI(\n messages: readonly RequestMessage[],\n readImage?: ReadRequestImage,\n): Promise<unknown[]> {\n return convertMessages(messages, readImage, openAiMessageCodec)\n}\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\n * 300s, the official CLI's own budget — see\n * {@link DEFAULT_REQUEST_TIMEOUT_MS}).\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 * Opt-in CLI cache mitigation: after this same model has answered with an\n * image in its history, ask dsh's durable image-offload surface to replace\n * that image before the next replay. This protects the growing text prefix\n * when Command Code's multimodal cache retreats to the first image, but the\n * model cannot inspect the old pixels again without a fresh tool/user image.\n */\n offloadSeenImagesForCache?: boolean\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 */\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 — so the pool moves on without remembering anything.\n *\n * The window/throttle split decides what the pool may CLAIM, never whether it\n * rotates (issue #54); the evidence that separates them is in\n * {@link classifyAccountRejection}.\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. `rotation.resetAtMs` carries the provider's own\n * reset time when the rejection body published one, so the host can hold the\n * key out until then instead of waiting for a billing probe to learn the\n * 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/**\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, name the root cause instead of letting the degraded per-endpoint\n * view hide it behind a generic \"partial data\" note.\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 request-image resolver; set only when the request carries images. */\n readImage: ReadRequestImage | undefined\n}\n\n/** UUID shape accepted by the official CLI's `toWireThreadId` helper. */\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n// UUIDv5's URL namespace. Keep this stable so a restored DSH session retains\n// the same provider thread ID across Host restarts.\nconst THREAD_ID_NAMESPACE = Buffer.from('6ba7b8119dad11d180b400c04fd430c8', 'hex')\n\n/**\n * Map the harness session identity to the CLI transport's UUID thread ID.\n *\n * The official CLI creates one thread ID per agent run and reuses it for the\n * tool-loop requests that follow. DSH stamps its loop-owned session ID onto\n * GenerateOptions, but ordinary IDs are `session-<UUID>`, not bare UUIDs.\n * UUIDv5 gives every non-UUID session ID a stable, wire-compatible mapping.\n * An already valid UUID remains unchanged; a one-shot call without a session\n * ID still gets a fresh thread ID.\n * This alone does not establish cache affinity (issue #64's A/B found none).\n */\nfunction cliThreadId(sessionId: string | undefined): string {\n if (!sessionId) return randomUUID()\n if (UUID_PATTERN.test(sessionId)) return sessionId\n const digest = createHash('sha1')\n .update(THREAD_ID_NAMESPACE)\n .update('dsh-commandcode-provider/session/')\n .update(sessionId)\n .digest()\n digest[6] = (digest[6]! & 0x0f) | 0x50\n digest[8] = (digest[8]! & 0x3f) | 0x80\n const hex = digest.toString('hex', 0, 16)\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\n/**\n * The CLI wire's explicit system-section form.\n *\n * The official CLI's current transport sends system text as an array and marks\n * stable sections with Anthropic-compatible ephemeral cache control. DSH's\n * adapter has one already-folded system string rather than the CLI's internal\n * section list, so preserve that text as one cacheable section. This does not\n * recover the CLI's separate static/dynamic boundaries or guarantee a hit.\n */\nfunction cliSystem(systemText: string): string | Record<string, unknown>[] {\n if (!systemText) return ''\n return [{\n type: 'text',\n text: systemText,\n cache_control: { type: 'ephemeral' },\n }]\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: cliSystem(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: cliThreadId(options.sessionId),\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\ninterface RequestContextBudget {\n maxTokens: number\n /** The originally requested reservation would press against the known window. */\n sizePressure: boolean\n}\n\n/**\n * Estimate the text the selected transport actually sends. JSON framing and\n * punctuation each get a token; ordinary ASCII words get one, with an extra\n * allowance for long identifiers. UTF-8 bytes / 4 tracks the measured CJK\n * case better than the engine's UTF-16 characters / 4. This is a heuristic,\n * never proof that a prompt cannot fit: a valid long English prompt can still\n * be larger under this estimate than under the provider's tokenizer.\n */\nfunction estimateWireInputTokens(\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n messages: readonly RequestMessage[],\n model: string,\n): number {\n const params = protocol === 'cli' ? recordOrEmpty(body.params) : body\n // Inline image data is transfer encoding, not model-visible text. Count\n // those occurrences using the same per-model visual prices as the meter.\n const wire = JSON.stringify(params, (_key, value: unknown) =>\n typeof value === 'string' && /^data:[^,]*;base64,/.test(value) ? '[image]' : value)\n let tokens = 0\n for (const match of wire.matchAll(/[A-Za-z0-9_]+|[^\\x00-\\x7f]+|[^\\s]/gu)) {\n const part = match[0]!\n if (/^[A-Za-z0-9_]+$/.test(part)) {\n tokens += 1 + Math.ceil(Math.max(0, part.length - 12) / 4)\n } else if (part.charCodeAt(0) > 127) {\n tokens += Math.ceil(Buffer.byteLength(part) / 4)\n } else {\n tokens += 1\n }\n }\n for (const message of messages) {\n for (const block of message.content) {\n if (block.type === 'image') tokens += priceRequestImage(block, model, true).visualTokens\n }\n }\n return tokens\n}\n\nfunction requestContextBudget(\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n messages: readonly RequestMessage[],\n model: string,\n contextWindow: number | undefined,\n requestedMaxTokens: number,\n): RequestContextBudget {\n if (contextWindow === undefined) return { maxTokens: requestedMaxTokens, sizePressure: false }\n const estimatedInput = estimateWireInputTokens(protocol, body, messages, model)\n const headroom = Math.min(16_384, Math.max(2_048, Math.ceil(contextWindow * 0.02)))\n const available = Math.floor(contextWindow - estimatedInput - headroom)\n // A heuristic overestimate must not reject a request that could succeed.\n // Send a small output reservation and let a provider's explicit overflow\n // signal invoke the harness's compaction path if the prompt truly is too big.\n const floor = Math.min(requestedMaxTokens, MIN_CONTEXT_OUTPUT_TOKENS, Math.max(1, Math.floor(contextWindow / 8)))\n return {\n maxTokens: Math.min(requestedMaxTokens, Math.max(floor, available)),\n sizePressure: estimatedInput >= contextWindow / 4\n && estimatedInput + requestedMaxTokens + headroom >= contextWindow,\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 /** Observe headers even on rejected attempts before rotation/fallback. */\n onResponse: (response: Response) => void\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). Returns\n * the live response plus its cleanup, or the rejection facts for the rotation\n * loop to classify. Every failure path cleans up before returning or throwing;\n * on success the caller-abort listener outlives the connect phase (it aborts a\n * stalled body read), so the 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 // Serialized once: the timeout path needs its exact byte length for the\n // large-input diagnosis, and re-stringifying a multi-MB body per attempt\n // would be pure waste on a route that can retry.\n const serializedBody = JSON.stringify(body)\n try {\n response = await fetchImpl(endpoint, {\n method: 'POST',\n headers,\n body: serializedBody,\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 headersTimeoutError({\n protocol, endpoint, body: serializedBody,\n timeoutMs: connection.requestTimeoutMs, 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 bilingual(\n 'TRANSPORT',\n `Command Code API request to ${endpoint} failed: ${errorChain(error)}`,\n 'Command Code API 请求连接失败——通常是网络或代理问题,请检查网络或代理设置后重试',\n { cause: error },\n )\n }\n\n deps.onResponse(response)\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 * Consecutive header timeouts for the last request shape, counted ACROSS\n * `stream()` calls: dsh-llm-retry re-invokes this same instance, so this is\n * the only place a streak can live. One slot rather than a map is the point —\n * the claim is \"consecutive\", and a single record cannot grow.\n */\n private headerTimeoutStreak: { fingerprint: string; count: number } | undefined\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 * Grade one failed attempt: a headers timeout that repeats on an unchanged\n * payload eventually leaves the retryable whitelist.\n *\n * `providerRetryPolicy()` cannot express this itself — dsh-llm's\n * `NormalRetryPolicyConfig` carries a single scalar `maxRetries` next to the\n * code list, so there is no per-code limit to lower. Escalating from here is\n * the only way to keep `RATE_LIMIT` / `SERVER` / `TRANSPORT` retryable (each\n * carries a real \"try again later\" signal) while stopping the one code that,\n * repeated unchanged, only burns the user's session.\n *\n * @returns the error to surface: unchanged for any other failure, the\n * original timeout below the threshold, and a terminal one at it.\n */\n private gradeHeaderTimeout(\n error: unknown,\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n timeoutMs: number,\n ): unknown {\n const timedOut = error instanceof LlmError && error.code === 'TIMEOUT'\n if (!timedOut) return error\n const fingerprint = `${protocol}:${fingerprintValue(body).sha256}`\n const count = this.headerTimeoutStreak?.fingerprint === fingerprint\n ? this.headerTimeoutStreak.count + 1\n : 1\n this.headerTimeoutStreak = { fingerprint, count }\n if (count < MAX_CONSECUTIVE_HEADER_TIMEOUTS) return error\n // Reset so a later attempt starts a fresh streak instead of failing at once.\n this.headerTimeoutStreak = undefined\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\n `Command Code API stopped retrying: the gateway returned no response headers on ${count} consecutive attempts at the same request, each after the full ${timeoutMs}ms budget, so this is not a network blip — it is provider queueing, a Go-plan capacity limit, or a network/proxy path problem. Resending the identical payload again is unlikely to help; wait for the provider to recover, or switch model or account.`,\n `Command Code API 已停止重试:同一请求连续 ${count} 次在 ${timeoutMs} 毫秒内都没有收到任何响应头,这不是网络抖动,而是服务商排队、Go 套餐容量限制或网络/代理链路问题。继续原样重发同一个请求通常无济于事——可以等服务商恢复,或换模型/换账号。`,\n )\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 failures\n * (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`, plan\n * rejections) are absent from the whitelist and surface immediately instead\n * of looping. Waits the pool/adapter attach as `providerRetryAfterMs` are\n * honored verbatim at or below the 15-minute cap and never attached above it\n * (in normal mode a longer attached wait makes the executor abandon the\n * 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. One price per occurrence, in order, is a hard\n * 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 { status, record } = await this.fetchJson(\n `${apiBase}/provider/v1/models`,\n { accept: 'application/json', ...IDENTITY_ENCODING_HEADER, ...attributionHeaders() },\n MODELS_TIMEOUT_MS,\n signal,\n )\n if (status < 200 || status >= 300) throw new Error(`models endpoint returned ${status}`)\n this.catalog = parseCatalogResponse(record)\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, and it hid models the user's OTHER accounts\n // could run. The union is the honest question for a pool, and it only works\n // together with the entitlement rotation in the connect loop.\n const accesses = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess()\n // Visible-model allowlist, then the terminal settings page's per-model\n // boolean overrides (its schema seam can only give each model its own\n // flag, which cannot express \"this id is in the list\"). Both are defined\n // on {@link CommandCodeConnectionOptions}.\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 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 /**\n * The per-model allowance bracket this account POOL falls into, or undefined\n * when there is nothing honest to show.\n *\n * The pricing page publishes a per-model monthly allowance for GOAT and Pro\n * only — its own words are \"the boost is a per-model allowance, so it lives on\n * the plans that have them\" — so a pool whose highest plan is Go, Provider,\n * Max or Ultra gets undefined rather than a neighbouring tier's figure. Taking\n * the HIGHEST tier matches the question the picker already answers for a pool\n * (see `modelVisibleForAnyAccount`): what the user can reach, not what the one\n * account serving this request happens to be. The fail-open shape is the same\n * too — an unreachable billing endpoint yields undefined, which hides the\n * allowance instead of inventing one.\n */\n async allowanceTier(): Promise<'goat' | 'pro' | undefined> {\n const accesses = await this.loadPoolBillingAccess()\n if (accesses === undefined) return undefined\n let highest: number | undefined\n for (const access of accesses) {\n const weight = access?.tierWeight\n if (weight === undefined) continue\n if (highest === undefined || weight > highest) highest = weight\n }\n // `allowanceTierForWeight` owns the weight → bracket mapping (and the\n // decision that Go, Provider, Max and Ultra have no bracket at all), so this\n // method only has to answer \"what is the highest plan in the pool?\".\n return allowanceTierForWeight(highest)\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 // Every account endpoint runs the chat path's own `assertUsableApiKey`\n // 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 JSON GET and return its HTTP status with a parsed record. The\n * catalog, billing probe, and usage report each apply their own failure\n * policy. Non-2xx and invalid JSON bodies come back without a record; only\n * a fetch failure propagates to the caller.\n *\n * `timeoutMs` is the caller's budget, unless it provides its own signal.\n * The usage report passes the connection's request budget rather than the\n * catalog/picker's shorter default.\n */\n private async fetchJson(\n url: string,\n headers: Record<string, string>,\n timeoutMs: number = MODELS_TIMEOUT_MS,\n signal?: AbortSignal,\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: 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 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.fetchJson(`${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`, which is\n * keyed by API key alone: remembering it would pin the whole ACCOUNT to the\n * CLI transport and drag every other model 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: a\n * 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 I/O,\n * for every endpoint at once, so this path runs `assertUsableApiKey` too and\n * answers `blocked: 'invalid-key'`; and the four endpoints get the SAME\n * per-request budget as a chat call (`connection.requestTimeoutMs`, default\n * 60 s), not the catalog's 10 s probe budget, because on a slow link a 10 s\n * cap made every account query time out while chat kept working.\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.fetchJson(\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 (issue #51's follow-up: \"切到一个不可用账号\").\n * `exceeded` is therefore true when ANY published window is exceeded, and\n * `resetAt` is the LATEST reset among the exceeded ones — the binding\n * constraint, because a clear five-hour window buys nothing while the weekly\n * 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 credit balances are deliberately NOT part of this answer: they\n * carry no reset 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 { record: parsed } = await this.fetchJson(\n `${connection.apiBase}/alpha/billing/credits`,\n await this.accountHeaders(apiKey),\n )\n if (parsed === undefined) 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 request-image 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: ReadRequestImage | 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 modelEntry = this.catalog.find((m) => m.id === options.model)\n const modelMax = modelEntry?.maxTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n const requestedMaxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n let maxTokens = requestedMaxTokens\n let contextBudget: RequestContextBudget = { maxTokens, sizePressure: false }\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 // (`resolveProtocol()` also forces the CLI transport for Claude).\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. Rung 0 is the standing budget; a 413 below steps down\n // the ladder. The session surface owns the offload set, so this throws\n // `IMAGE_OFFLOAD_REQUIRED` when more images must go; the retry then\n // arrives with the surface already updated.\n let requestOptions = withSurfaceOffload(\n options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!,\n connection.offloadSeenImagesForCache === true && protocol === 'cli' ? options.model : undefined,\n )\n const buildBody = async (target: CommandCodeProtocol): Promise<Record<string, unknown>> => {\n const facts = { maxTokens: requestedMaxTokens, reasoningEffort, systemText, readImage }\n const built = target === 'cli'\n ? await buildCliBody(requestOptions, connection, facts)\n : await buildOpenAIBody(requestOptions, facts)\n contextBudget = requestContextBudget(\n target, built, requestOptions.messages, options.model, modelEntry?.contextWindow, requestedMaxTokens,\n )\n maxTokens = contextBudget.maxTokens\n if (target === 'cli') recordOrEmpty(built.params).max_tokens = maxTokens\n else built.max_tokens = maxTokens\n return built\n }\n let body: Record<string, unknown> = await buildBody(protocol)\n\n // The opt-in trace now starts before the first connect attempt so a cache\n // miss can be correlated with the exact request shape that produced it.\n // The record contains hashes and counts only; see requestFingerprint().\n const trace = openStreamTrace(`${options.provider}/${options.model}`)\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 let attemptNumber = 0\n let responseMetadata: ResponseMetadata = { protocol, headers: {} }\n const connectDeps: GenerateConnectDeps = {\n options, connection, fetchImpl: this.fetchImpl,\n onResponse: (response) => {\n // Any answer from the gateway ends a header-timeout streak, whatever\n // its status: the silence being measured is over.\n this.headerTimeoutStreak = undefined\n responseMetadata = { protocol, headers: responseIdentifiers(response.headers) }\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 attempt: attemptNumber,\n accountsTried: tried.size,\n maxTokens,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n headers: responseMetadata.headers,\n })\n },\n }\n let connected: { response: Response; cleanup: () => void } | undefined\n try {\n for (;;) {\n tried.add(apiKey)\n attemptNumber++\n responseMetadata = { protocol, headers: {} }\n if (trace.enabled) trace.record('request', {\n attempt: attemptNumber,\n sessionId: options.sessionId,\n ...requestFingerprint(protocol, body),\n })\n const attempt = await connectGenerate(connectDeps, apiKey, protocol, body)\n if ('response' in attempt) {\n connected = attempt\n break\n }\n const providerError = parseProviderError(attempt.errText)\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, providerError)\n ) {\n protocol = 'cli'\n this.rememberProtocol(apiKey, true)\n requestOptions = withSurfaceOffload(\n options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!,\n connection.offloadSeenImagesForCache === true ? options.model : undefined,\n )\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, as a durable\n // surface mutation rather than a local edit, so the extra omissions\n // survive the retry. Zero missing means the images are already gone and\n // the body is simply too big: fall through to the 413 diagnosis instead\n // of asking for an offload that cannot happen, which is also what keeps\n // the branch 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, providerError)\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, and `PROVIDER_HTTP_ERROR` sits\n // outside dsh-llm-retry's whitelist — so without this the turn dies on\n // the spot even though the provider said exactly when the same request\n // 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 // A status that already maps to RATE_LIMIT (a plain 429) keeps that\n // mapping — `generateHttpError` owns the `Retry-After` header's cap and\n // finiteness rules there — unless the body named its own reset.\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 bilingual(\n 'RATE_LIMIT',\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 wait > 0 ? { providerRetryAfterMs: wait } : undefined,\n )\n }\n throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs, providerError, contextBudget.sizePressure)\n }\n } catch (error) {\n trace.record('connect-error', { message: boundTraceText(errorChain(error)), responseMetadata })\n trace.close()\n if (options.signal?.aborted) throw error\n throw failureWithRequestId(\n this.gradeHeaderTimeout(error, protocol, body, connection.requestTimeoutMs),\n responseMetadata,\n )\n }\n if (connected === undefined) {\n // Unreachable: the loop only exits via `break` or `throw`. The guard\n // 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 trace.record('end', { outcome: 'empty', code: 'PROVIDER_PROTOCOL_ERROR' })\n trace.close()\n throw failureWithRequestId(new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR'), responseMetadata)\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 // The request fingerprint was recorded before connect; this is the\n // response half of the same opt-in trace. See ./stream-trace.ts for why\n // the raw response stream remains the artifact that separates a provider\n // cut from a parser miss.\n const streamStartedAt = Date.now()\n let chunkCount = 0\n let totalBytes = 0\n let lastChunkAt = streamStartedAt\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 can legitimately stay silent for minutes while\n // thinking, and the official CLI sets no idle cap at all. reader.cancel()\n // unblocks a pending read(), which the loop then turns into a TIMEOUT\n // 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 captureResponseIdentifiers(responseMetadata, event)\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 bilingual(\n 'TRANSPORT',\n `Command Code API stream from ${connection.apiBase} failed while reading: ${errorChain(error)}`,\n 'Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\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 bilingual(\n 'TIMEOUT',\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 )\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 responseMetadata,\n })\n endRecorded = true\n if (failure !== undefined) throw failure\n yield hasResponseIdentifiers(responseMetadata)\n ? { ...finish, replayState: { response: responseMetadata } }\n : 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 response\n // was closed mid-generation: the gateway, an intermediary proxy, or the\n // network. Synthesizing a clean `stop` is what turned a truncated answer\n // into a turn that just ended, with nothing saying why\n // (`dsh-llm-deepseek`'s `translate()` raises this same code for this\n // same condition).\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 responseMetadata,\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 bilingual('EMPTY_RESPONSE', 'Command Code returned an empty response', 'Command Code 返回了空响应,重试通常可恢复')\n }\n throw bilingual(\n 'STREAM_CLOSED',\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 )\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 responseMetadata,\n })\n }\n throw options.signal?.aborted ? error : failureWithRequestId(error, responseMetadata)\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 `providerRetryAfterMs` so\n * dsh-llm-retry can wait exactly that long instead of guessing at the backoff\n * cadence — capped at RETRY_MAX_DELAY_MS, because in normal mode a longer\n * attached wait makes the executor abandon the retry outright.\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`, because that failure has a recovery the harness\n * performs and a generic provider error does not. Every message built here is\n * bilingual — the harness renders it verbatim in its retry chrome.\n */\ninterface ParsedProviderError {\n root?: Record<string, unknown>\n nested?: Record<string, unknown> | undefined\n code?: string | undefined\n type?: string | undefined\n message?: string | undefined\n rateLimit?: Record<string, unknown> | undefined\n}\n\n/** Parse a rejected body once, retaining the nested/root distinction. */\nfunction parseProviderError(errText: string): ParsedProviderError {\n try {\n const parsed: unknown = JSON.parse(errText)\n if (!isRecord(parsed)) return {}\n const nested = isRecord(parsed.error) ? parsed.error : undefined\n const body = nested ?? parsed\n return {\n root: parsed,\n nested,\n code: stringValue(body.code),\n type: stringValue(body.type),\n message: stringValue(body.message),\n rateLimit: isRecord(body.rateLimit) ? body.rateLimit : undefined,\n }\n } catch {\n return {}\n }\n}\n\nfunction generateHttpError(\n status: number,\n errText: string,\n retryAfterMs?: number,\n parsed: ParsedProviderError = parseProviderError(errText),\n sizePressure = false,\n): LlmError {\n // Historically this diagnosis reads only a nested `error` envelope; root\n // fields still feed account rotation and the Go-plan fallback below.\n const providerCode = parsed.nested === undefined ? undefined : parsed.code\n const providerDetail = parsed.nested === undefined ? '' : [parsed.code, parsed.type, parsed.message]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\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 const overflowDetail = providerDetail !== '' ? providerDetail : errText.slice(0, 500)\n if (status < 500 && isContextOverflowDetail(overflowDetail)) {\n return bilingual(\n CONTEXT_WINDOW_EXCEEDED_CODE,\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 { status },\n )\n }\n // The gateway can wrap an over-reserved request in a generic provider_error\n // 400 with no context wording. That phrase alone also covers unrelated\n // upstream failures, so use the known model window and THIS request's size\n // pressure before asking the harness to compact. Do not turn an ordinary\n // empty stream, timeout, or small provider_error into a false overflow.\n if (status === 400 && sizePressure && AMBIGUOUS_SIZE_REJECTION.test(providerDetail)\n && /\\bprovider_error\\b/i.test(providerDetail)) {\n return bilingual(\n CONTEXT_WINDOW_EXCEEDED_CODE,\n 'Command Code API error 400: the provider could not complete a request near the model context limit'\n + ' — compacting the session and retrying',\n 'Command Code API 返回 400:请求接近模型上下文上限,服务商无法完成——正在压缩上下文后重试',\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. The code is matched shape-insensitively because the provider\n // spells it both ways (`cmd_zdr_no_providers` in the JSON error body,\n // `CMD_ZDR_NO_PROVIDERS` in plain-text ones, exactly as the official CLI's\n // classifier reads it), and the CLI's own user guidance is to unset CMD_ZDR.\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\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 { status: 422 },\n )\n }\n if (status === 401) {\n // An invalid or missing credential is a config problem, not a transport\n // failure: retrying it identically cannot succeed.\n return bilingual(\n 'INVALID_CREDENTIAL',\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 { 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.\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\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 { 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 \"temporarily unavailable\" class (Cloudflare's\n * 520-527 included) and the only sane answer to it is the byte-identical\n * resend the retry policy exists to make; 408 is the same story for the\n * request itself. Everything else stays permanent: a 400/403/404/409/422\n * 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` member\n // of an SSE chunk rather than as an event type of its own; ignoring it let\n // the stream end with no finish event, so a context-window or quota rejection\n // surfaced only as a generic EMPTY_RESPONSE (which the retry policy repeats)\n // and the real cause was lost.\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 a `reasoning_details` array, GLM/Qwen/Kimi with the\n // DeepSeek-native `reasoning_content`, and the OpenAI family with the scalar\n // `reasoning` PLUS a `reasoning_details` array whose entry is\n // `{ type: 'reasoning.summary', summary }` (measured live 2026-09-18 on\n // gpt-5.6-luna, 6/6 rounds: the scalar and the array's `summary` carried the\n // identical text every time). All three spellings are read here, in that\n // order, so no family's thinking is dropped; the scalar wins over the array,\n // which is a forward guard rather than the live path for any family (every\n // family that sends the array also sends a scalar alongside it). See\n // {@link reasoningDetailsText} for the array's two vocabularies.\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 bilingual(\n 'OUTPUT_TOKEN_LIMIT',\n `Command Code reached the output token limit without producing answer text or a tool call (${detail})`,\n 'Command Code 已达到输出 token 上限,但没有生成正文或工具调用;请调整思考强度,或在模型和接口上限内增加输出预算',\n )\n }\n if (reason === 'content_filter' || reason === 'content-filter') {\n return bilingual('CONTENT_FILTER', `Command Code filtered the response (${detail})`, 'Command Code 拦截了响应,未生成正文或工具调用')\n }\n return bilingual(\n 'EMPTY_RESPONSE',\n `Command Code finished without producing answer text or a tool call (${detail})`,\n 'Command Code 返回了空响应(可能只有思考内容),重试通常可恢复',\n )\n}\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 * It must recognize the whole account-scoped class, not just 429/401: when it\n * did not, an account that could not pay, or could not run the model, stayed\n * \"usable\" in the pool and was handed out again on the next request (issue\n * #51's follow-up). The four reasons are defined on\n * {@link AccountRotationReason}; what this function owes them is the evidence\n * split:\n *\n * - `rate-limit` / `throttled`: the code `RATE_LIMITED` is the authoritative\n * signal — the CLI accepts the code OR a 429 status — and only a body that\n * NAMES a window (`error.rateLimit.window`, see {@link readWindowLimitEvidence})\n * may be called a spent one. A bare 429 is a burst/model/spend limiter the\n * billing endpoint cannot see, so it stays `throttled` and the host claims\n * no window (issue #54).\n * - `unavailable`: no credits, or a model outside this account's plan, so it\n * rotates but must NOT mark the key — the fact is about the model or the\n * balance, and either can change without the key changing.\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 carrying one of these must rotate\n * past the account instead of being retried as a transient provider failure,\n * because the same request against the same account cannot succeed. Only the\n * prose scan below is confined to 4xx.\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(\n status: number,\n errText: string,\n parsed: ParsedProviderError = parseProviderError(errText),\n): { reason: AccountRotationReason; resetAtMs?: number } | undefined {\n const code = (parsed.code ?? parsed.type)?.toUpperCase()\n if (status === 429 || code === 'RATE_LIMITED') {\n const evidence = readWindowLimitEvidence(errText, parsed)\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.\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.\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/**\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 \"usage limit\n * for your plan\" wording (read as `weekly` when it says so, else `fiveHour`).\n * That is the CLI's own bar for calling a rejection a WINDOW limit, and it is\n * what keeps a bare 429 — a burst limiter, a model-level limit, a spend cap\n * `windowLimits` cannot show — from being reported as an exhausted window\n * (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(\n errText: string,\n parsed: ParsedProviderError,\n): { window?: 'fiveHour' | 'weekly' | 'daily'; resetAtMs?: number } {\n const named = stringValue(parsed.rateLimit?.window)\n const message = parsed.message ?? stringValue(parsed.root?.message) ?? ''\n const seconds = numberValue(parsed.rateLimit?.reset)\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\n/**\n * True when a pre-stream rejection is Command Code's Go-plan gate\n * (`upgrade_required`) — the only plan without Provider API access. Only this\n * class of rejection should fall back to the CLI `/alpha/generate` transport;\n * other 4xx/5xx must surface as ordinary errors so real account/model\n * problems are not masked.\n */\nfunction isUpgradeRequiredError(\n status: number,\n errText: string,\n parsed: ParsedProviderError = parseProviderError(errText),\n): 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 if ((parsed.code ?? parsed.type)?.toLowerCase() === 'upgrade_required') return true\n if (parsed.message?.toLowerCase().includes('go plan') && parsed.message.toLowerCase().includes('api access')) return true\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 * zh/en copy for the Host-side `/commandcode` usage command, as plain\n * constants: the command runs on the Host and has no access to the client's\n * `ctx.locale`, so the active locale is resolved by `pickCommandLocale()` and\n * the dictionaries are read by direct lookup. Distinct from\n * `./client/locales.ts` (the settings-page `settings.commandcode` namespace).\n *\n * zh is the source of truth for the key set; `en` must carry exactly the same\n * keys, which the `Record` type makes a compile error.\n */\n\n/** Active locale id for the `/commandcode` command. */\nexport type LocaleId = 'zh' | 'en'\n\n/** Dictionary keys used by the `/commandcode` command. */\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 | '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 | 'activeBadge'\n | 'invalidCredentialBadge'\n | 'cooldownBadge'\n | 'rateLimitBadge'\n | 'planLine'\n | 'planPeriodSuffix'\n | 'usageHeader'\n | 'requestsLine'\n | 'costLine'\n | 'tokensLine'\n | 'creditsHeader'\n | 'monthlyLine'\n | 'barLine'\n | 'windowsHeader'\n | 'fiveHourLine'\n | 'weeklyLine'\n | 'windowBarLine'\n | 'exceededWarning'\n | 'partialFailures'\n | 'noData'\n | 'errorText'\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 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 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: explicit `override`\n * (from `Config.lang`) → `LC_ALL` → `LANG` → the `'zh'` fallback that keeps\n * unconfigured deployments on their current output.\n *\n * Matched on the leading tag only — `zh_CN.UTF-8`, `zh-Hans` and `zh` all\n * map to `'zh'`, anything starting with `en` maps to `'en'`, everything else\n * falls back to `'zh'` rather than 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","/** Shared, dependency-free formatting for Host commands and browser surfaces. */\n\nexport function formatMoney(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\nexport function formatMoneyExact(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\nexport function formatTokensCompact(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/** The input is already in percent units; callers add the percent sign. */\nexport function formatSuccessRate(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** One window's fill ratio in [0, 1]; zero when uncapped. */\nexport function windowRatio(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.max(0, Math.min(1, used / cap))\n}\n\n/** Local date-time, with the empty state chosen by the caller. */\nexport function formatResetAt(ms: number): string {\n return ms <= 0 ? '' : new Date(ms).toLocaleString()\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()`. The command is Host-side\n * and has no access to the client's `ctx.locale`, so the active locale\n * arrives through `deps.getLocale()` and every string comes from\n * `./command-locales.ts` (a missing key falls back to the `en` copy).\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'\nimport { formatMoney, formatMoneyExact, formatSuccessRate, formatTokensCompact, formatResetAt, windowRatio } from './display-format.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 it\n * from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent (notably in\n * tests), the command renders with the default locale `'zh'`.\n */\n getLocale?: () => LocaleId\n}\n\n// ---------------------------------------------------------------------------\n// Number / time formatting (locale-independent; the locale only changes\n// the surrounding labels)\n// ---------------------------------------------------------------------------\n\nconst money = formatMoneyExact\nconst moneyShort = formatMoney\nconst tokensCompact = formatTokensCompact\nconst successRateText = formatSuccessRate\n\n/** A local date, or `n/a` when the provider published no reset time. */\nfunction resetLabel(ms: number): string {\n return formatResetAt(ms) || 'n/a'\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 = windowRatio(used, cap)\n const filled = Math.round(ratio * 10)\n return '█'.repeat(filled) + '░'.repeat(10 - filled)\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/prices`, `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`). This module is dependency-free so\n * the client bundle can inline it, and it holds the schema helpers and\n * descriptor boilerplate the wire files 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 endpoint\n * in the rejection message (e.g. `commandcode/report result:`), so each wire\n * file keeps its own diagnostic phrasing while sharing the helper 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). Callers that need the\n * narrowing in an `if` must therefore assign inside the positive branch.\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: `mode: 'strict'` carries the LAZY schema factory\n * (`create()`) the registry requires and the Gateway validates with\n * (`codec.create().parse`). There is NO `schema` member — issue #49.\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 result\n * — only the endpoint, method, result type symbol, and schema differ.\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 contracts for the Command Code Remotes the browser half mounts: the\n * account-usage report (`commandcode/report`), the model catalog\n * (`commandcode/models`) and the price table (`commandcode/prices`).\n *\n * The browser never holds the API key, so every one of these is produced\n * Host-side: the Host half registers a strict invocation descriptor against a\n * Cordis service (`src/usage-remote.ts`) and the browser half mounts the\n * matching contribution on `ctx.remote` (`src/client/index.ts`). This module\n * is the single source both halves share — the hand-rolled result validators\n * and the exact descriptor objects, so neither half can drift. It is\n * dependency-free because the client bundle inlines it.\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/**\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 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: an explicit `false` means the endpoint omitted the\n // balance, which cannot be told from a real zero — the panel keeps the\n // figure off the dashboard rather than drawing a consumed quota. An absent\n // flag (an older Host) stays unset and reads as \"assume reported\", so a\n // real balance is not lost cross-version. A PRESENT value must still be a\n // boolean, so a malformed frame is rejected 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 parsers return\n // undefined for an absent block, and an optional member is only set when\n // 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 * Per-model MONTHLY allowance in USD: how much of the plan's monthly credit\n * pool this one model may draw, already resolved by the Host against the\n * account pool's highest plan (the pricing page publishes an allowance for\n * GOAT and Pro only). Undefined when that plan has no published allowance\n * (Go, Provider, Max, Ultra) or when billing could not be read — the browser\n * shows nothing rather than guessing a neighbouring tier's figure.\n *\n * Deliberately a plain number and not the `{ goat, pro }` pair: the bracket is\n * a Host decision that already depends on facts the browser does not hold, and\n * shipping both figures would invite a second, divergent rule here. Note this\n * is dollars per MONTH, unlike every rate in `CommandCodePriceTable`.\n */\n allowance?: number\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 numberField: catalogNumber,\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 // Same rule for the allowance: an older Host simply omits it, but a Host that\n // sends a non-number has broken the contract.\n if (source.allowance !== undefined) {\n model.allowance = catalogNumber(source, 'allowance', 'model.allowance')\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: a present non-number is a contract violation rather\n // than a silent zero (only a minority of models publish a cache-write rate).\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 instead of pasting an API key. The loopback server must live\n * in the Host half — it binds a local port and receives the key — so the page\n * drives it through the 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 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 Command Code Remotes (`commandcode/report`,\n * `commandcode/models`, `commandcode/prices`, `commandcode/login*`).\n *\n * The settings page needs facts the browser cannot fetch for itself — it never\n * holds the API key — so this module exposes them through the Typert Gateway:\n * a `TypertRemoteService` provides the receiver the Gateway resolves, and the\n * shared strict descriptors (`src/usage-wire.ts`, `src/login-wire.ts`) are\n * registered on the `typert` registry so the Gateway claims the endpoints.\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_HOST_CONTRIBUTION } 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 and `begin`\n * rejects with a plain message, so the page's manual paste path stays the\n * 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. Absent, the\n * `models` endpoint answers an empty list — the page's editors degrade to\n * 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 /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */\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. The\n * contribution is the combined one built below, so the type is structural\n * rather than tied to any one endpoint's 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 * Degrades per endpoint like the `/commandcode` command (failures land in\n * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which\n * the Gateway folds into 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 browser\n * never calls the Command Code API directly — the Host serves the catalog\n * (already fetched/cached by the adapter) so models can be picked from the\n * 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, served Host-side so the browser bundle never carries\n * a copy that could drift from the snapshot, and so a price update reaches an\n * 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).\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_HOST_CONTRIBUTION.invocations],\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), mirroring\n * what the official `command-code login` CLI command performs.\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 * The server contract is CLI-mirrored: POST-only `/callback`, a 10 KB body\n * cap, JSON responses (`{success:true}` / `{success:false,error}`), and\n * state-token equality as the anti-forgery check. Three deliberate hardenings\n * over the CLI build: the CORS origin is echoed only when allowlisted (the\n * CLI falls back to the first origin), `Connection: close`, and the denial\n * branch checks the state token before it ends the attempt.\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.\n */\n private attemptSeq = 0\n /**\n * The start currently binding a port, if any. Every `begin()` arriving before\n * it settles joins it: two independent starts would each bind a loopback\n * server, and only the LAST one is reachable by `teardown()` — the orphan\n * keeps answering `/callback` for the process's lifetime, and ten of them\n * exhaust 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 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 — 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()` or a `dispose()` can arrive before any `waiting` status is\n // visible. Publishing one now would hand the user a live authUrl they\n // already asked to drop, so the freshly bound server is closed here.\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 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 * Command Code web-search provider over `ctx.web`.\n *\n * The official CLI's built-in `web_search` tool POSTs\n * `{ query, numResults, allowedDomains?, blockedDomains? }` to\n * `{apiBase}/alpha/web-search` and reads `{ results: [{ title, url, snippet }] }`\n * back, authenticating with the SAME `Authorization: Bearer <key>` and\n * `x-command-code-version` headers the model adapter uses. This provider\n * therefore reuses the plugin's existing credential chain and `apiBase`, so\n * the model-facing `web_search` tool needs no separate configuration.\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`). A documented\n * reference only: disabling this plugin's `webSearch` toggle restores the\n * PREVIOUSLY selected backend, never this default (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 * dsh offers no public API to change the selected search provider at runtime,\n * so this seam mutates the instance field directly — 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\n * boot-time `searchProvider: commandcode` cordis patch is the durable\n * 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. `displaced`\n * is the backend it took over — restored on disable or unload — and\n * `undefined` means \"nothing was configured, leave auto-select\" and must\n * round-trip untouched.\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) OR \"the field already read `commandcode`\" (touch\n * nothing). Collapsing the two is what turned a user's own\n * `searchProvider: commandcode` pin into an auto-select, and then into\n * `WEB_PROVIDER_AMBIGUOUS` on every search.\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, the original `displaced` is kept —\n * the field currently holds our own id, which must never be mistaken for the\n * user's backend.\n * - Disabling hands the selection back to the remembered backend only when\n * this plugin actually took it over. A fresh boot straight into\n * `webSearch: false`, or a `preexisting` field, leaves it ALONE: writing the\n * empty memory back would clear the user's own `searchProvider: commandcode`\n * pin and hand the selection to dsh-web's auto-select, where a second usable\n * provider makes every later search throw `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).\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 — see the\n // `preexisting` note on {@link CommandCodeSearchSelection}.\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, reusing\n * the plugin's credential chain and `apiBase` so the model-facing `web_search`\n * tool needs no separate configuration. Selection between multiple search\n * providers is the web seam's job (pin `searchProvider: commandcode` if\n * 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). A MISSING credential maps to WEB_PROVIDER_CREDENTIAL_MISSING;\n // real rejections (INVALID_CREDENTIAL / RATE_LIMIT) keep their message\n // 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 * dsh-TUI owns its settings screen and asks plugins only to DECLARE what is\n * editable. Without 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 `/provider` wizard manages its `llm-pi-ai` routes\n * exclusively (issue #28). The seam is third-party, so this module carries\n * LOCAL structural types and reads the service defensively; registration rides\n * the plugin entry's `ctx.inject(['tuiSettingsSections'], …)`, so a profile\n * without dsh-TUI never activates the fiber.\n *\n * The API-key field is a **secret** field: the literal goes to the credentials\n * seam, never into a settings document. Its reference must stay out of the\n * host-reserved namespace (`DEEPSEEK_*`/`DSH_*`) — dsh-TUI silently DROPS a\n * field with a reserved ref, which would leave a page with no key input.\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. The\n * seam has no multi-select kind (`text | number | boolean | select`) and no\n * array element path a checkbox could own, so each model is its own `boolean`\n * field at `modelVisibility.<id>` whose `parse` writes the whole array. The\n * `parse` reads the allowlist LIVE (the screen stages several toggles into one\n * save, so a captured base would let two quick toggles resurrect each other's\n * stale list), and an empty allowlist means \"show every model\" to the adapter,\n * so the checkboxes render the EFFECTIVE set.\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'\nimport { PLAN_LABELS, PLAN_TIER_ORDER } from './plan-tiers.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 readonly value: string\n /** Display label (English; also the fallback). */\n readonly label: string\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 readonly descriptions?: TuiLocalizedText\n /** Optional one-line help rendered under the field. */\n readonly hint?: string\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 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 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/** Tiers in picker order; a model outside this set joins the \"Other\" group. */\nconst TIER_ORDER: readonly string[] = PLAN_TIER_ORDER\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. A model added\n * upstream after this build still reaches the user: an empty allowlist shows\n * everything, and a model named in the allowlist but absent here is rendered\n * 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 * The two option-bearing fields (`activeAccount`, `lang`) are `text` +\n * `options` rather than `select`, because a `select` cannot express \"unset\" —\n * cycling only ever lands on a declared option, so it would strand the user on\n * a pinned value with no way back to automatic. The `auto` sentinel plus a\n * `parse` that clears the path keeps unset reachable. `filterModelsByPlan`\n * formats its EFFECTIVE default (unset means true at the adapter) so a fresh\n * install reads true instead of 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 const stored = storedIds(deps.visibleModels())\n const overrides = deps.modelVisibility?.() ?? {}\n // Models this build's catalog cannot place (retired, 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: `${PLAN_LABELS[tier] ?? tier} models`,\n descriptions: { zh: `${PLAN_LABELS[tier] ?? tier} 模型` },\n }))\n // A tier this snapshot cannot place shares the \"Other\" group above.\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. An override equal to what the array already\n * says is written as a CLEAR, so toggling a model back to its inherited\n * state leaves no residue.\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 // Live, not captured at registration: the host stages a toggle and\n // saves it later.\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: ['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: ['offloadSeenImagesForCache'],\n group: 'advanced',\n kind: 'boolean',\n label: 'Stop replaying images already seen',\n descriptions: { zh: '已看过的图片不再重复发送' },\n hint: 'CLI transport only. After this model has answered, durably replace older images with text to keep later prompt text cacheable. Old pixels need a fresh file read or attachment to inspect again. Off by default.',\n hintDescriptions: { zh: '仅 CLI 传输。模型看过图片并回复后,永久用文字替代旧图,以保留后续文本缓存;重看旧图需要重新读取文件或附加。默认关闭。' },\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.\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 * @returns a refresh function that re-registers the section when a fact it\n * renders changed — the plugin entry calls it from its\n * `loader/volatile-update` listener — or `undefined` when the seam is\n * unusable. The returned function is 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 rejecting host (a shadow-mode capability policy, a future contract\n // change) must not take the plugin down: the terminal simply keeps no\n // Command Code page, and the web settings 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 policy (`providerRetryPolicy` in `./adapter.ts`) is near-unbounded\n * on purpose — 1000 attempts doubling to a 15-minute cap — for failures the\n * provider ASKS to have retried. A connection that cannot be established is\n * not that: a blip the first few attempts absorb, or an outage no in-request\n * waiting fixes (attempt 11 alone already waits 512 s). So transport failures\n * get their own budget, cleared at each new STEP (one step = one model\n * request). `agent/status` → `idle` is NOT the reset (one `running` phase spans\n * a turn's steps), and neither is `assistant/attempt` (appended for the FAILED\n * attempt itself, which would clear the budget on every failure).\n *\n * Not counted here: the adapter's in-`stream()` pre-stream recovery (account\n * rotation, the 413 step-down, the Provider-API → CLI switch) — invisible to\n * the caller and bounded on its own.\n *\n * @module\n */\n\n/** Failure code this budget covers. */\nexport const TRANSPORT_FAILURE_CODE = 'TRANSPORT'\n\n/** Transport failures to absorb before the failure surfaces (default 5: ~15 s of blip cover on the route cadence). */\nexport const DEFAULT_TRANSPORT_MAX_RETRIES = 5\n\n/** Ceiling for the setting above (plausibility bound, not a recommendation; mirrored in `Config`'s schema and pinned by tests). */\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 * Pure and exported on purpose: the choice of event is the part of this design\n * that is easy to get plausibly wrong (see the module comment), so it is stated\n * once, where a test can pin it.\n *\n * @param type - the appended session event's type.\n * @returns `'reset'` for a new step, `'forget'` when the turn ended (the\n * session → agent mapping is no longer needed), otherwise `'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 too; it names the retry budget and the checks that actually help instead\n * of the bare \"fetch failed\" 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 * Volatile-config helpers for dsh 0.1.7's schema-derived profile Config.\n *\n * 0.1.7's `settings.describe()` projects each entry's schema through\n * `volatileForm()`, so a form contains ONLY nodes carrying `meta.volatile`\n * and a form edit is refused unless its path lies beneath a marked node. The\n * loader then resolves each marked field into a frozen `{ get() }` reference\n * that is written IN PLACE (no remount) and announced with\n * `loader/volatile-update`. Two helpers keep the rest of the plugin reading a\n * PLAIN `Config`: `markVolatile()` applies the mark, and\n * `unwrapVolatileConfig()` reads every top-level field through its reference\n * when one is present — FRESH per call, because a reference's identity is\n * stable while its value changes.\n *\n * Only TOP-LEVEL fields are marked (a form write names a top-level path such\n * as `accounts` or `modelVisibility.<id>`), so one unwrap level is complete.\n * The literal `apiKey` secret stays unmarked on purpose: no settings surface\n * writes it — page and TUI both write keys through the credentials seam — so a\n * config-file edit to it reloading the fiber is correct 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: it is a schemastery 3.18.3 feature and the\n * only supported engine (`dsh 0.2.0-rc.1`) pins `~3.18.4`, so the method is\n * always present. It is reached through a structural member so the caller's\n * declared field type survives — the mark changes what the schema PARSES to (a\n * live reference), not the plugin-facing `Config` shape.\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 */\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, MIT).\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 and the model picker lists the live catalog. Connection\n * facts are resolved per request from the live profile Config (volatile\n * fields, unwrapped per read) and the credential seam, so a changed key,\n * endpoint or cache path reaches the 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 { 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'\nimport { modelAllowanceFor } from './model-prices.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 * Opt-in cache mitigation for the CLI route: after this model has answered,\n * durably offload its earlier images before later turns. Old pixels then\n * require a fresh read/attachment if the model needs to inspect them again.\n * Defaults to false to preserve full image history.\n */\n offloadSeenImagesForCache?: boolean\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\n * (1000 attempts, waits doubling to 15 minutes) because that shape is for\n * the failures a provider asks to have retried; a transport failure is not\n * one of those, and after ~15.5 s of grace the wait is pure stall, so it is\n * capped here (issue #39). 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\"; applied 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.\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, and an entry with\n * neither `apiKey` nor `apiKeyEnv` is ignored. A pre-stream 429/401 marks\n * the key and the next account's key is retried transparently.\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`). It serves\n * whenever usable; an unknown id or an exhausted one falls back to rotation\n * order. Unset means \"first usable account\".\n */\n activeAccount?: string\n /**\n * Model → account routing rules, each listing catalog model ids for an\n * account slot id. A matching rule's account serves before {@link\n * activeAccount} and the passive rotation order; an unusable routed account\n * falls back, so the router is a hint, never a hard gate. First match wins.\n */\n modelAccountRules?: CommandCodeModelAccountRule[]\n /**\n * Whether to use Command Code as the backend for dsh's model-facing\n * `web_search` tool. Enabled registers a `commandcode` search provider on\n * `ctx.web` AND selects it over the shipped `deepseek-official` (or a\n * sibling plugin's pin), reusing the SAME key and apiBase as chat. Disabling\n * hands the selection back to whichever backend was there before, so a\n * sibling search plugin (e.g. modsearch) keeps working (issue #26). The\n * write rides dsh's internal `searchProviderId`, read per search call, so a\n * setting change lands on the next search without a restart. Defaults true.\n */\n webSearch?: boolean\n /**\n * Whether the Web sidebar shows the plans & quota card\n * (`sidebar.footer.action`). Defaults to false, so an unset document mounts\n * no sidebar quota surface and no background usage poll for it; the\n * dashboard cell behind it stays registered. Read by the browser client; the\n * adapter ignores it.\n */\n showSidebarQuota?: boolean\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, and a model\n * with no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` rather\n * than losing the guarantee. ZDR capacity is priced pass-through and usually\n * costs more; the price readout keeps quoting the ordinary catalog rates\n * (the real per-request price shows in Command Code's Studio).\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 the\n * explicit knob: `'zh'` or `'en'`, defaulting to `'zh'`. The web settings\n * page is unaffected — it follows the browser's language preference on its\n * own. The declared type is `string` (the schemastery `pattern` cannot\n * narrow literal types); `pickCommandLocale` treats an unknown value as\n * \"unset\" and then reads `LC_ALL`/`LANG`, which is only reachable when\n * `lang` is absent from a programmatically built config.\n */\n lang?: string\n}\n\n/**\n * The Config schema: every field volatile except the composition-only `apiKey`\n * secret. 0.1.7's settings forms are projected from the schema's\n * `meta.volatile` nodes, so an unmarked field would be invisible to AND\n * unwritable from the settings page. The loader also hands `apply()` a live\n * reference per marked field, so writes commit in place without remounting\n * this fiber — the `loader/volatile-update` listener at the bottom of `apply`\n * re-derives the two facts that are not re-read per request.\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.\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 offloadSeenImagesForCache: z.boolean().default(false),\n transportMaxRetries: z.number().min(0).max(MAX_TRANSPORT_MAX_RETRIES),\n filterModelsByPlan: z.boolean(),\n visibleModels: z.array(z.string()),\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 // 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 * every settings-backed read.\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 offloadSeenImagesForCache: config.offloadSeenImagesForCache === true,\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.\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: a non-object or a\n * non-boolean entry is dropped rather than reaching the picker filter, and an\n * all-empty map reads as no map. Returns a fresh id → boolean map, or\n * 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 a\n // settings-page accounts change reaches the very next request.\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, re-read per resolution like every other\n // 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, and the marks are re-checked\n // against the live window limits only once every account is marked, so the\n // 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 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 unusable the pool's own RATE_LIMIT / INVALID_CREDENTIAL\n // error is what the caller sees, not the raw provider rejection.\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 — a `:free` model is still served by a\n // credits-empty account. `rate-limit` and `throttled` both mark but with\n // different causes, so the pool's own diagnosis never reports a plain\n // throttle as an exhausted usage window (issue #54).\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.\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.\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. An empty `settingsPath` means the whole\n // `llm-commandcode` section configures this provider.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n // Bounded retry for TRANSPORT failures (issue #39). The route policy is\n // near-unbounded on purpose (see `providerRetryPolicy`) because an exhausted\n // rate-limit window or a gateway 520 is a failure that ASKS to be retried —\n // a connection that cannot be established is not, and the unbounded cadence\n // turned a 10-second connect timeout into an ~8-minute stall, so the first\n // 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, and the\n // diagnostic also goes to the log, which 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 per invocation from `Config.lang`\n // (explicit override) and the environment's `LC_ALL`/`LANG` (inferred\n // default), so a settings change reaches the next 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`), plus the browser-login flow the\n // same service carries (the Host binds a loopback callback server and stores\n // the delivered key through the credentials seam). Rides the optional\n // `typert` registry service, so profiles without the web stack never\n // activate it.\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: served\n // Host-side from the adapter's cached/fetched catalog, so the browser never\n // calls the Command Code API directly. Unfiltered, so an editor never loses\n // its own options — a rule can route a GOAT-only model the picker hides.\n // Each 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 // Per-model monthly allowance (how far this one model stretches the plan's\n // credit pool). The page publishes one for GOAT and Pro only, so the POOL's\n // bracket decides whether a figure exists at all — a Go/Max/Provider account\n // gets none rather than a neighbouring tier's number. `listModels` above\n // already consulted the same cached billing facts, so this costs one lookup.\n const bracket = await adapter.allowanceTier()\n return {\n models: models.map((model) => {\n const tier = KNOWN_PLANS[model.id]\n const allowance = bracket === undefined ? undefined : modelAllowanceFor(model.id)?.[bracket]\n return {\n id: model.id,\n name: model.name.replace(/\\s*\\(CC\\)$/, ''),\n ...(tier === undefined ? {} : { tier }),\n ...(allowance === undefined ? {} : { allowance }),\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. It reuses\n // the SAME credential chain and apiBase as the model adapter, so DSH's\n // model-facing web_search tool needs no separate key or endpoint config.\n //\n // Whether `commandcode` WINS over the shipped `deepseek-official` (or a\n // sibling search plugin's pin, e.g. modsearch) is `Config.webSearch`. The\n // seam has no public runtime selector, so the plugin writes its private\n // `searchProviderId` field (read per call) via\n // `applyCommandCodeSearchSelection`; see src/web-search.ts for why that\n // write is safe. The tracked selection remembers whichever backend was\n // displaced, so turning the toggle off — and disposing the fiber — hands the\n // selection back to it (issue #26) instead of forcing the factory default.\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 dsh-TUI settings page: without it a TUI-only user has no way to enter\n // the API key (issue #28). The seam is optional, exactly like `commands` and\n // `web`, so a profile without dsh-TUI never activates this fiber.\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 section is re-registered when this list changes (the refresh call\n // below), since the host renders a fixed option list per declaration.\n accountSlots: () => slots().map((slot) => ({ id: slot.id, label: slot.label })),\n // Read live, so a checkbox judges its inherited state against the\n // current document, and an id this build's catalog does not place still\n // 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. A profile without a settings service simply keeps\n // 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`) — never rename one without the other, or a mismatch\n // strands existing users' non-secret settings in `settings.yaml.imported`.\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","counts","record","stringField","reject","createNetServer","createHttpServer"],"sources":["../src/cost-facts.ts","../src/plan-tiers.ts","../src/capabilities.ts","../src/model-prices.ts","../src/wire-guards.ts","../src/cost-projection.ts","../src/response-encoding.ts","../src/timeout-limits.ts","../src/model-visibility.ts","../src/transient-retry.ts","../src/accounts.ts","../src/image-request.ts","../src/image-tokens.ts","../src/stream-trace.ts","../src/request-timing.ts","../src/adapter.ts","../src/command-locales.ts","../src/display-format.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/config-volatile.ts","../src/index.ts"],"sourcesContent":["/** 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\n * 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 and no row carries both\n * today, so the combination becoming real is visible before it reaches a user.\n * This ordering is a latent choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // ORDER IS LOAD-BEARING: 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.\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 // The table is mutable, so an identity-keyed index can keep stale model\n // mappings after its rows are changed in place. The projection already\n // indexes its usage groups once per settlement; scan the small price table\n // here so every call observes the current rows.\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","/** Shared plan-tier presentation facts; safe to inline into the browser bundle. */\n\nexport const PLAN_TIER_ORDER = ['go', 'goat', 'pro', 'provider', 'max'] as const\n\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\nexport const PLAN_ORDER: Readonly<Record<string, number>> = Object.fromEntries(\n PLAN_TIER_ORDER.map((tier, index) => [tier, index]),\n)\n","/**\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 here is synced from official sources — the command-code CLI\n * bundle's model table (`dist/cli.mjs`, re-verified at command-code@1.73.0) and\n * the official plan/pricing/model docs; see the dsh-commandcode-upstream skill\n * for the extraction procedures. Keeping the snapshot in its own module\n * confines those frequent sync diffs here: src/adapter.ts holds only the stable\n * wire/runtime logic. The read helpers live here too, for the same reason.\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\nimport { peakHour } from './cost-facts.ts'\nimport { PLAN_LABELS, PLAN_ORDER } from './plan-tiers.ts'\nexport { PLAN_LABELS, PLAN_ORDER } from './plan-tiers.ts'\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n // Re-verified against the authoritative command-code@1.73.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 '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; same effort 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 // command-code@1.68.0; the five-level set shared with the rest of the Sonnet /\n // Opus family. It takes the \"recommended\" slot from `claude-sonnet-5`.\n 'claude-sonnet-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.39.1 dropped `medium`; the 1.39.2 table ships these three.\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0.\n 'deepseek/deepseek-v4.1-flash': ['low', 'high', 'max'],\n // command-code@1.67.0; the same three-level set as its `deepseek-v4.1-flash`\n // sibling, whose throughput-focused variant this is.\n 'deepseek/deepseek-v4.1-flash-fast': ['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 // command-code@1.39.3; it previously reasoned automatically with no levels.\n 'moonshotai/Kimi-K3': ['low', 'high', 'max'],\n // command-code@1.43.0.\n 'google/gemini-3.8-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n // command-code@1.60.0; same three-level set as its Step 3.x Flash siblings,\n // which still reason automatically with no levels and 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; same four-level set as Grok 4.6. 1.61.0 put it on a\n // 40% off launch deal (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; same effort set as its `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: selectable levels in command-code@1.45.0, `max` added to\n // 1.3 in 1.48.0 (1.3-contributor keeps the four-level set).\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 '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; the full five-level set.\n 'gpt-6-astra': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.64.0: Claude Opus 5.5 and the GPT-6 Sol / Luna pair, the only\n // registry additions in the 1.62.0 -> 1.64.0 train; all three reason with the\n // same five-level set as `gpt-6-astra`.\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; it previously reasoned automatically with no levels\n // and lived in KNOWN_THINKING_MODELS. The hidden\n // `minimax/minimax-m3-free` sibling gained the same set in the bundle.\n 'MiniMaxAI/MiniMax-M3': ['low', 'medium', 'high'],\n // command-code@1.65.0. Free during the stealth preview (see KNOWN_DEALS) and\n // NOT routed under ZDR (see KNOWN_NON_ZDR_MODELS).\n 'stealth/space-bunny-alpha': ['low', 'medium', 'high'],\n // command-code@1.66.0. A three-level set offering `xhigh` INSTEAD of `high` —\n // the GLM 5.3 / 5.2 family's shape, unlike Space Bunny Alpha's. Free during\n // the stealth preview and NOT routed under ZDR (see the tables above).\n 'stealth/pixel-canary': ['low', 'medium', 'xhigh'],\n // command-code@1.71.0. Max-and-above availability (see KNOWN_PLANS), Vision\n // per the official registry and inputModalities:[\"text\",\"image\"], and the\n // same five-level set as its `gpt-6-astra` / `gpt-6-sol` predecessors.\n 'gpt-6.1-sol': ['low', 'medium', 'high', 'xhigh', 'max'],\n // command-code@1.70.0. Free during \"while it lasts\" (see KNOWN_DEALS) but,\n // unlike the free stealth previews and its own `ling-3.0-flash-sante:free`\n // predecessor, it still carries selectable efforts — so it belongs here and\n // NOT in KNOWN_THINKING_MODELS.\n 'inclusionai/ling-3.1-flash:free': ['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; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'Qwen/Qwen3.8-Max-0902',\n // command-code@1.56.0; Vision per the official registry and inputModalities.\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; Vision per the official registry and inputModalities.\n 'claude-opus-5-5',\n 'claude-opus-5',\n 'claude-sonnet-4-6',\n 'claude-sonnet-5',\n // command-code@1.68.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'claude-sonnet-5-5',\n 'deepseek/deepseek-v4-flash-vision-exp',\n // command-code@1.53.0; Vision per the official registry and inputModalities.\n 'deepseek/deepseek-v4.1-flash',\n // command-code@1.67.0; Vision per the official registry and inputModalities.\n 'deepseek/deepseek-v4.1-flash-fast',\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; Vision per the official registry and inputModalities.\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; Vision per the official registry and inputModalities.\n 'gpt-6-astra',\n // command-code@1.64.0 added the GPT-6 Sol / Luna pair; Vision per the\n // official registry and inputModalities.\n 'gpt-6-luna',\n 'gpt-6-sol',\n // command-code@1.71.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"] — unlike the text-only Ling free models.\n 'gpt-6.1-sol',\n // command-code@1.44.0 added Muse Spark 1.3 and its Contributor sibling; both\n // are Vision per the official registry and inputModalities.\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.66.0; Vision per the official registry (the docs models page\n // lists it in the Stealth group) and the CLI's inputModalities.\n 'stealth/pixel-canary',\n // command-code@1.65.0; Vision per the official registry and inputModalities.\n 'stealth/space-bunny-alpha',\n 'stepfun/Step-3.7-Flash',\n // command-code@1.60.0; Vision per the official registry and inputModalities.\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 (text-only in 1.46.0).\n 'xai/grok-4.6',\n // command-code@1.59.0; Vision per the official registry and inputModalities.\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. None carries a reasoning flag in any\n // source, so no effort or 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; Vision per the official registry and inputModalities.\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.73.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 of both\n * is this set. Reading only the sibling route table would drop `meituan/\n * LongCat-2.0`, which appears in `modelSupportsZdr` alone (re-read from the\n * 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: the two stealth-preview\n * rows sit in BOTH sets, so LongCat is the only divergence). The official docs (commandcode.ai/docs/resources/\n * zdr) put it in prose — \"99% of our models have ZDR-capable upstreams … only\n * a small handful of models are affected\" — so the CLI's exclusion list is\n * the only per-model evidence there is; a ZDR request naming one of these\n * fails with HTTP 422 `cmd_zdr_no_providers` instead of routing through a\n * 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. It is a rare change:\n * 20 members held across 1.62.0 → 1.64.0, 1.65.0 and 1.66.0 each added exactly\n * one (the two stealth-preview models below), 1.67.0 added one\n * (`deepseek/deepseek-v4.1-flash-fast`), and 1.68.0 changed nothing — 23\n * members as of 2026-09-29.\n */\nexport const KNOWN_NON_ZDR_MODELS: ReadonlySet<string> = new Set([\n 'MiniMaxAI/MiniMax-M3',\n 'Qwen/Qwen3.8-Max-0902',\n // command-code@1.67.0. The 1.67.0 artifact lists it in BOTH anchor sets, so\n // the CLI's own ZDR predicate excludes it. Unlike the stealth previews below,\n // the pricing page carries no ZDR note for this row — the artifact is the\n // evidence, and the sibling `deepseek-v4.1-flash` stays ZDR-covered.\n 'deepseek/deepseek-v4.1-flash-fast',\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, in BOTH anchors. The pricing page's own tip agrees:\n // \"Free while the preview lasts. Not routed under ZDR.\"\n 'stealth/space-bunny-alpha',\n // command-code@1.66.0 added `stealth/pixel-canary` — the second stealth-preview\n // free model, and like its sibling it is not routed under ZDR. Re-read from\n // the 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: it is listed in BOTH\n // anchor sets in all three, so an earlier note here claiming it entered\n // through `modelSupportsZdr` alone was wrong. The pricing page's own tip says\n // it either way: \"Free while the preview lasts. Not routed under ZDR.\"\n 'stealth/pixel-canary',\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 marks `reasoning:!0` but defines no\n * selectable `reasoning_effort` levels — they think automatically, with\n * Command Code driving the depth. `KNOWN_EFFORTS` (which mirrors the CLI's\n * effort map exactly) stays the sole source for selectable effort levels, and\n * this snapshot is not surfaced in the picker's compact description — it exists\n * for programmatic consumers.\n *\n * Source: the bundled model table (dist/cli.mjs), cross-checked with\n * https://commandcode.ai/docs/reference/cli/models. Keep in sync via the\n * dsh-commandcode-upstream skill; a model that GAINS selectable efforts leaves\n * this set for `KNOWN_EFFORTS` (Tencent Hy4 Preview, Kimi K3, the Muse Spark\n * family and MiniMax M3 all took that path).\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`.\n *\n * Measured 2026-09-16 (command-code@1.54.0, 69 models posted to\n * `/provider/v1/chat/completions`): exactly the then-entire Claude family\n * refused with HTTP 400 `Model \"<id>\" must be called via\n * /provider/v1/messages (Anthropic Messages shape)`, and every one of them is\n * routed normally by `/alpha/generate`.\n *\n * Re-measured 2026-09-29 against the 84-model catalog: the same ten\n * `claude-*` ids are the only ones carrying `supported_endpoints:\n * [\"/messages\"]`, and posting a non-Claude model to the endpoint answers 400\n * `Model \"<id>\" is not supported on this endpoint. Use\n * /provider/v1/chat/completions for OpenAI and OSS models.` The adapter routes\n * on that field when the catalog supplies it, so this set is the FALLBACK for\n * a cached or hand-built catalog, not the primary source — see\n * `requiresMessagesEndpoint()`.\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 * `requiresMessagesEndpoint()` additionally treats any `claude-*` id as\n * Messages-only, so a Claude model added upstream is still routed correctly\n * by an un-updated plugin instead of hard-failing with the 400 above. The\n * worst case of that rule going stale the other way (upstream teaching\n * `/provider/v1/chat/completions` to serve Claude) is one model riding a\n * transport it already works on.\n *\n * Keep in sync when models ship (see the dsh-commandcode-upstream skill).\n */\nexport const MESSAGES_ONLY_MODELS: ReadonlySet<string> = new Set([\n 'claude-sonnet-5-5',\n 'claude-sonnet-5',\n 'claude-sonnet-4-6',\n 'claude-fable-5-1',\n 'claude-fable-5',\n 'claude-opus-5-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 * Per-model output ceilings, which `/provider/v1/models` does NOT publish (it\n * carries `context_length` and `supported_endpoints` only) while every endpoint\n * refuses a larger `max_tokens` per model. Sending the context window as the\n * output budget is what produced issue #71: `claude-sonnet-5-5` has a\n * 1 000 000-token window and a 128 000-token ceiling, the adapter derived\n * 131072, and the endpoint refused every request of a fresh process.\n *\n * **Generated — do not hand-edit.** `scripts/sync-output-limits.mjs` rewrites\n * this literal from models.dev; run it after a catalog sync, and use its\n * `--check` in CI. Command Code resells these models through their VENDOR's own\n * API, so the vendor's published ceiling is the value recorded: 76 of the 86\n * catalog ids as of 2026-09-30. Each row carries a comment naming the entry it\n * came from.\n *\n * Two of those 76 rest on more than a vendor lookup. `gpt-6.1-sol` (128000) comes\n * from OpenAI's own row and is corroborated by every other provider carrying it.\n * `inclusionai/ling-3.1-flash:free` (32768) is hand-recorded in the script's\n * `MANUAL_CEILINGS`: models.dev has no `ling-3.1` entry yet, so it takes the Ling\n * family's uniform ceiling. Both are still correctable — a stricter gateway costs\n * one refused request, and `streamRequest()` remembers what the endpoint said.\n *\n * The 10 unlisted models are ones no vendor publishes and the aggregators\n * disagree about. They are NOT a gap: a refusal states the ceiling in full, and\n * `streamRequest()` reads it off, retries once and remembers it for the model\n * (issue #71). A vendor figure the gateway turns out to be stricter than costs\n * one round trip; a conservative guess costs half of every answer, forever —\n * which is why the unlisted path defers to the endpoint rather than to a\n * fallback here.\n *\n * An unlisted Messages-route model still falls back to\n * {@link DEFAULT_MESSAGES_MAX_TOKENS} before any request is made, so a ceiling\n * is never absent when the body is built.\n */\nexport const MODEL_OUTPUT_TOKEN_LIMITS: ReadonlyMap<string, number> = new Map([\n // anthropic\n ['claude-fable-5', 128000],\n // anthropic\n ['claude-fable-5-1', 128000],\n // anthropic\n ['claude-haiku-4-5-20251001', 64000],\n // anthropic\n ['claude-opus-4-7', 128000],\n // anthropic\n ['claude-opus-4-8', 128000],\n // anthropic\n ['claude-opus-5', 128000],\n // anthropic\n ['claude-opus-5-5', 128000],\n // anthropic\n ['claude-sonnet-4-6', 128000],\n // anthropic\n ['claude-sonnet-5', 128000],\n // anthropic\n ['claude-sonnet-5-5', 128000],\n // deepseek\n ['deepseek/deepseek-v4-flash', 393216],\n // deepseek\n ['deepseek/deepseek-v4-flash-vision-exp', 393216],\n // deepseek\n ['deepseek/deepseek-v4-pro', 393216],\n // google\n ['google/gemini-3.1-flash-lite', 65536],\n // google\n ['google/gemini-3.5-flash', 65536],\n // google\n ['google/gemini-3.5-flash-lite', 65536],\n // google\n ['google/gemini-3.6-flash', 65536],\n // google\n ['google/gemini-3.7-flash', 65536],\n // google\n ['google/gemini-3.8-flash', 65536],\n // openai\n ['gpt-5.3-codex', 128000],\n // openai\n ['gpt-5.4', 128000],\n // openai\n ['gpt-5.4-mini', 128000],\n // openai\n ['gpt-5.5', 128000],\n // openai\n ['gpt-5.6-luna', 128000],\n // openai\n ['gpt-5.6-sol', 128000],\n // openai\n ['gpt-5.6-terra', 128000],\n // openai\n ['gpt-6-astra', 128000],\n // openai\n ['gpt-6-luna', 128000],\n // openai\n ['gpt-6-sol', 128000],\n // openai\n ['gpt-6.1-sol', 128000],\n // 2 provider(s), unanimous\n ['inclusionai/ling-3.0-flash-sante:free', 32768],\n // manual: no models.dev row; Ling family ceiling 32768, see MANUAL_CEILINGS\n ['inclusionai/ling-3.1-flash:free', 32768],\n // 1 provider(s), unanimous\n ['meituan/LongCat-2.0', 131072],\n // meta\n ['meta/muse-spark-1.1', 131072],\n // meta\n ['meta/muse-spark-1.2', 131072],\n // meta\n ['meta/muse-spark-1.2-contributor', 131072],\n // meta\n ['meta/muse-spark-1.3', 131072],\n // meta\n ['meta/muse-spark-1.3-contributor', 131072],\n // minimax\n ['MiniMaxAI/MiniMax-M2.5', 131072],\n // minimax\n ['MiniMaxAI/MiniMax-M2.7', 131072],\n // minimax\n ['MiniMaxAI/MiniMax-M3', 512000],\n // moonshotai\n ['moonshotai/Kimi-K2.6', 262144],\n // moonshotai\n ['moonshotai/Kimi-K2.7-Code', 262144],\n // moonshotai\n ['moonshotai/Kimi-K2.7-Code-Highspeed', 262144],\n // moonshotai\n ['moonshotai/Kimi-K3', 1048576],\n // nvidia\n ['nvidia/nemotron-3-ultra-550b-a55b', 65536],\n // poolside\n ['poolside/laguna-s-2.1-free', 32768],\n // alibaba\n ['Qwen/Qwen3.6-Max-Preview', 65536],\n // alibaba\n ['Qwen/Qwen3.6-Plus', 65536],\n // alibaba\n ['Qwen/Qwen3.7-Flash', 131072],\n // alibaba\n ['Qwen/Qwen3.7-Max', 131072],\n // alibaba\n ['Qwen/Qwen3.7-Plus', 131072],\n // alibaba\n ['Qwen/Qwen3.8-Flash', 131072],\n // alibaba\n ['Qwen/Qwen3.8-Max', 131072],\n // alibaba\n ['Qwen/Qwen3.8-Omni-Flash', 131072],\n // sakana\n ['sakana/fugu-ultra', 1000000],\n // 1 provider(s), unanimous\n ['stealth/pixel-canary', 131072],\n // 3 provider(s), unanimous\n ['stealth/space-bunny-alpha', 524288],\n // stepfun\n ['stepfun/Step-3.5-Flash', 256000],\n // stepfun\n ['stepfun/Step-3.7-Flash', 256000],\n // stepfun\n ['stepfun/Step-5-Preview', 65536],\n // thinkingmachines\n ['thinkingmachines/inkling', 65536],\n // xai\n ['xai/grok-4.5', 500000],\n // xai\n ['xai/grok-4.6', 500000],\n // xai\n ['xai/grok-4.7', 500000],\n // xiaomi\n ['xiaomi/mimo-v2.5', 131072],\n // xiaomi\n ['xiaomi/mimo-v2.5-pro', 131072],\n // xiaomi\n ['xiaomi/mimo-v2.6-flash', 131072],\n // xiaomi\n ['xiaomi/mimo-v2.6-pro', 131072],\n // xiaomi\n ['xiaomi/mimo-v2.6-pro-ultraspeed', 131072],\n // zai\n ['z-ai/glm-5.3-flash', 131072],\n // zai\n ['z-ai/glm-5.3-flashx', 131072],\n // zai\n ['zai-org/GLM-5', 131072],\n // zai\n ['zai-org/GLM-5.1', 131072],\n // zai\n ['zai-org/GLM-5.2', 131072],\n // zai\n ['zai-org/GLM-5.3', 131072],\n])\n\n/**\n * Output ceiling for a Messages-route model that {@link MODEL_OUTPUT_TOKEN_LIMITS}\n * does not carry — today only models no vendor publishes yet. Deliberately\n * conservative: a 400 on `max_tokens` is a wasted round trip on every request,\n * whereas a lower ceiling only shortens an answer, and the endpoint states the\n * real one the first time it refuses, at which point the runtime overrides this\n * anyway (issue #71).\n *\n * 64 000 is not arbitrary: it is `claude-haiku-4-5-20251001`'s actual ceiling,\n * the lowest in the Claude family. A Claude model added to the catalog before\n * its row exists here therefore answers at a size the family really supports,\n * and is corrected upward on its first rejection rather than clamped here\n * forever.\n */\nexport const DEFAULT_MESSAGES_MAX_TOKENS = 64_000\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`,\n * `/docs/plans/max` and `/docs/resources/pricing-limits`). Each plan's model\n * list is a superset of the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.\n * Models absent from every plan list (Claude Opus/Fable, Fugu Ultra) are\n * Provider-tier. Re-verified at command-code@1.73.0 (2026-10-01): 86 catalog\n * ids at 53/62/76/84 cumulative, a strict superset chain — every release since\n * 1.49.0 has been additive with no tier move, and per-entry tags below name the\n * release that added each row.\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 (54) ---\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; listed on the Go plan page.\n 'Qwen/Qwen3.8-Max-0902': 'go',\n // command-code@1.56.0; the pricing page's embedded availability grants every\n // tier (individual-go through teams-pro) — the \"all\":true shape shared by the\n // Qwen 3.8 family and the stealth-preview models below.\n 'Qwen/Qwen3.8-Omni-Flash': 'go',\n // command-code@1.39.0; Go-tier like the rest of the DeepSeek V4 family.\n 'deepseek/deepseek-v4-flash-fast': 'go',\n // command-code@1.53.0; every plan including Go.\n 'deepseek/deepseek-v4.1-flash': 'go',\n // command-code@1.67.0; individual-go true, so Go-tier like the rest of the\n // DeepSeek V4 family.\n 'deepseek/deepseek-v4.1-flash-fast': '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', // command-code@1.64.0; the opensource-category GPT-6, on every plan including\n // Go, unlike its premium-category siblings Sol (Pro) and Astra (Provider/Max).\n 'gpt-6-luna': 'go',\n // command-code@1.42.0 added the free LongCat 2.0 on every plan; that promo\n // ended 2026-09-19 and the catalog renamed the id to the paid\n // `meituan/LongCat-2.0` ($0.30/$1.20/$0.006), which keeps this slot. The CLI\n // followed in command-code@1.58.0, marking the retired `:free` sibling\n // `hidden`, so its registry now agrees with the catalog this map is keyed by.\n 'meituan/LongCat-2.0': 'go',\n // command-code@1.52.0; free on every plan (\"up to 100 requests a day\"),\n // successor to the retired `inclusionai/ling-3.0-flash-free` promo.\n 'inclusionai/ling-3.0-flash-sante:free': 'go',\n // command-code@1.70.0; free on every plan including Go — the embedded\n // availability is the \"all\":true shape (individual-go through teams-pro),\n // same as its `ling-3.0-flash-sante:free` predecessor and unlike the\n // Max-only `gpt-6.1-sol` below.\n 'inclusionai/ling-3.1-flash:free': 'go',\n // command-code@1.44.0; on every plan including Go, like its 1.2 Contributor\n // 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; every tier, and listed by the Go/GOAT/Pro/Max plan\n // pages alike — the superset chain this map encodes.\n 'stepfun/Step-5-Preview': 'go',\n // command-code@1.66.0; all-tiers availability, so a Go model every higher\n // plan also serves. Free during the stealth preview (see KNOWN_DEALS).\n 'stealth/pixel-canary': 'go',\n // command-code@1.65.0; all-tiers availability. Free during the stealth\n // 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 the MiMo V2.6 family; these two are on every tier\n // (the Go plan page lists both), while the Pro UltraSpeed sibling is GOAT —\n // individual-go is what separates them.\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; the \"all\":true shape shared with its\n // `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 (9 more) ---\n // command-code@1.68.0; individual-go false, individual-goat true — \"Available\n // on GOAT and above\", one tier ABOVE its `claude-sonnet-5` predecessor, which\n // sits in the Pro block below.\n 'claude-sonnet-5-5': 'goat',\n 'google/gemini-3.7-flash': 'goat',\n // command-code@1.43.0; \"Available on GOAT and above\", like the rest of the\n // 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; \"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; \"Available on GOAT and above\" (individual-go false).\n 'xai/grok-4.7': 'goat',\n // command-code@1.62.0; GOAT and above, the same split as its Grok 4.7\n // sibling. Its two cheaper V2.6 siblings are Go, 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; Pro and above (individual-go/goat false).\n 'gpt-6-sol': 'pro',\n 'meta/muse-spark-1.1': 'pro',\n // --- Provider (8) ---\n // command-code@1.40.0; Provider/Max exactly like its `claude-fable-5`\n // predecessor — individual-provider/max/ultra and teams-pro only.\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; Provider API only (go/goat/pro/pro-v1 all false), and\n // the catalog serves it with supported_endpoints ['/messages'] — the Claude\n // route, which the adapter's `claude-*` prefix rule already sends down the\n // CLI transport.\n 'claude-opus-5-5': 'provider',\n 'claude-opus-5': 'provider',\n // command-code@1.49.0; on Max.\n 'gpt-6-astra': 'provider',\n 'sakana/fugu-ultra': 'provider',\n // --- Max (1) ---\n // command-code@1.71.0; the FIRST Max-only model in this catalog and the only\n // one whose minimum plan is `max`: the embedded availability sets every lower\n // tier false (individual-go / go-v1 / goat / pro / pro-v1 / provider all\n // false) and only individual-max, individual-ultra and teams-pro true.\n // `PLAN_ORDER` already carries `max` above `provider`, so the picker sorts it\n // last without a change there (plan-tiers.ts).\n 'gpt-6.1-sol': 'max',\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 `dist/cli.mjs`, re-verified unchanged\n * through command-code@1.73.0): subscription `planId` prefix → display name and\n * the plan's monthly credit total. This is the account's own subscription\n * (from `/alpha/billing/subscriptions`) — distinct from {@link KNOWN_PLANS},\n * 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 // command-code@1.69.0 (\"Go plan moves to per-model credits\") added this second\n // Go row to the CLI's plan maps. Same display name and monthly total, so\n // `tierWeight` stays 0 alongside `individual-go` — exactly how the pre-existing\n // `individual-pro-v1` sits at Pro's weight 2. Resolution is longest-prefix\n // match (see below), so the explicit `-v1` suffix still wins over the base.\n 'individual-go-v1': { 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, shown as a `FREE`\n * badge; it degrades to a plain discount once the deal lapses.\n *\n * A deal whose promo ENDS is removed here rather than left to lapse on\n * `expiresAt`: the pricing page drops the entry, so a lapsed row would badge a\n * model the catalog now serves at full price (Grok 4.7 reverts to $2.00 in /\n * $6.00 out after its 2026-09-27 window).\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 'MiniMaxAI/MiniMax-M3': { label: '50% off' },\n 'xiaomi/mimo-v2.5-pro': { label: '99% off' },\n 'xiaomi/mimo-v2.5': { label: '98% off' },\n 'poolside/laguna-s-2.1-free': { label: 'FREE', free: true },\n // command-code@1.52.0; free \"up to 100 requests a day\" with no published end\n // date, so a permanent-style deal like the stealth previews below.\n 'inclusionai/ling-3.0-flash-sante:free': { label: 'FREE', free: true },\n // command-code@1.70.0; 100% off \"Free while it lasts\" with the same\n // 100-requests-a-day cap as its `ling-3.0-flash-sante:free` predecessor and\n // likewise no fixed end date, so no `expiresAt`. The pricing page publishes it\n // at a literal zero, which `modelPriceTable()` serves from this deal, so it\n // gets no row in the vendored price table either.\n 'inclusionai/ling-3.1-flash: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, no\n // published end date), and command-code@1.66.0 added Pixel Canary on\n // identical terms. Neither is routed under ZDR (see\n // KNOWN_NON_ZDR_MODELS), and the pricing page publishes both at a literal\n // zero, which `modelPriceTable()` serves from these deals — so neither gets a\n // row in the vendored price table.\n 'stealth/space-bunny-alpha': { label: 'FREE', free: true },\n 'stealth/pixel-canary': { 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 * Exactly five models carry the page's `timeOfDay` block (the five rows below).\n * The picker shows the *current* state as a compact label (`Peak`/`Half`)\n * matching the English noun style of the other markers (`Image`, `FREE`), so a\n * developer can tell at a glance whether calling the model right now is cheap\n * or expensive.\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. A rate that is\n * internally consistent can still be the wrong row (the V4 Flash Vision (exp)\n * variant is priced from the page's own `timeOfDay` block, not from 2× its own\n * off-peak figures), which is why the vendored price table\n * (`./model-prices.ts`) is synced from the page and not hand-kept.\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; the same `timeOfDay` block as the other three\n // (off-peak $0.15/$0.60, peak $0.30/$1.20, 01–04 & 06–10 UTC Mon–Fri).\n 'deepseek/deepseek-v4.1-flash',\n // command-code@1.67.0; the same 01–04 & 06–10 UTC Mon–Fri windows and the same\n // 2026-08-16T16:00Z effective date, at its own rates (off-peak\n // $0.16/$0.58/$0.016, peak $0.32/$1.16/$0.032) — note these are NOT 2× the\n // sibling's, so this row must come from its own `timeOfDay` block.\n 'deepseek/deepseek-v4.1-flash-fast',\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 return peakHour(now, PEAK_HOUR_RANGES)\n}\n\n/**\n * As {@link isPeakPricingHour}, plus the {@link KNOWN_PEAK_PRICING} membership\n * test; `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 * 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 pricing\n * page publishes, which is what lets the composer price a session in dollars.\n * Every figure is USD per 1,000,000 tokens.\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.\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 * Discounted rows carry both price sets. The page publishes a deal's\n * PROMOTIONAL rates as the row's ordinary figures and its pre-discount\n * `listRates` alongside, so the generator copies both and the table picks\n * between them with `dealLabel()`'s clock. That keeps a lapsed discount from\n * pricing a session below what the provider now charges — the same \"a stale\n * snapshot never shows a lapsed discount\" rule the picker badge follows, applied\n * to dollars rather than to a label. The page's own `discountPercent` is NOT\n * used for this: it is a marketing figure that does not divide out (MiMo V2.5's\n * \"98% off\" prices three buckets at 5.7×, 14.3× and 57× of list).\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 only the rows.\n * `--check` reports drift without writing (exit 1 on drift, exit 2 when the\n * page could not be read, so a network failure never reads as \"up to date\").\n * Everything else in this file — this doc, the types, the slug rules, the\n * 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, dealLabel, isFreeModel } from './capabilities.ts'\nimport { PLAN_ORDER } from './plan-tiers.ts'\n\n/** One pricing-page context band: the rates charged inside `maxContext` tokens. */\ninterface ModelPriceContextTier {\n readonly maxContext?: number\n readonly rates: readonly number[]\n /**\n * The band's pre-discount rates, present only for a row carrying a deal. See\n * {@link ModelPriceRow.listRates}.\n */\n readonly listRates?: readonly number[]\n}\n\n/**\n * A model's per-model monthly allowance, in USD, per plan tier.\n *\n * This is the page's `planAllowanceUsd`: how much of the plan's monthly credit\n * pool this ONE model may draw. It is not extra money — every allowance draws\n * on the same pool. Go、GOAT、Pro 按官网各自的数字展示;旧来源缺少 Go\n * 时保留缺失状态,零额度也不等于接口权限。\n * Max/Provider 不借用相邻套餐的额度。Deals are baked in:\n * `MiniMaxAI/MiniMax-M3` carries `$47 / $57` precisely because its 2× promotion\n * is already folded into the allowance.\n */\nexport interface ModelAllowance {\n readonly go?: number\n readonly goat: number\n readonly pro: number\n}\n\n/**\n * The plan tiers a per-model allowance exists for, cheapest first. Ordering\n * matters: {@link allowanceTierForWeight} matches a tier weight against these\n * rather than against hard-coded numbers, so this table and the subscription\n * table cannot drift apart silently.\n */\nconst ALLOWANCE_TIERS = ['go', 'goat', 'pro'] as const\n\n/**\n * Which allowance bracket a plan-tier weight belongs to, or undefined when that\n * plan has no per-model allowance.\n *\n * Weights come from `KNOWN_SUBSCRIPTION_PLANS` (go 0 · goat 1 · pro 2 ·\n * provider 3 · max/ultra 4) and {@link PLAN_ORDER} is the same scale, which is\n * what makes the lookup exact: Provider、Max、Ultra\n * 没有本地额度;缺项时不能用相邻套餐的数字代替。\n */\nexport function allowanceTierForWeight(\n tierWeight: number | undefined,\n): keyof ModelAllowance | undefined {\n if (tierWeight === undefined) return undefined\n return ALLOWANCE_TIERS.find((tier) => PLAN_ORDER[tier] === tierWeight)\n}\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 *\n * `listRates` appears only on rows whose page record carries a `deal`: those\n * `rates` are the PROMOTIONAL figures, and `listRates` is what the row reverts\n * to when the deal lapses. {@link modelPriceTable} picks between the two with\n * the same clock {@link dealLabel} uses, so a discount that has expired stops\n * pricing a session at the promotional rate even before the next sync — the\n * badge and the dollars always agree. A permanent deal (no `expiresAt`) never\n * lapses, and a row with no `listRates` has nothing to fall back to.\n *\n * `allowance` is a different KIND of number from everything else here: dollars\n * per month, not dollars per million tokens. It never enters the price table —\n * {@link modelAllowanceFor} serves it to the settings page instead.\n */\ninterface ModelPriceRow {\n readonly id: string\n readonly rates: readonly number[]\n readonly listRates?: readonly number[]\n readonly peak?: readonly number[]\n readonly allowance?: ModelAllowance\n readonly contextTiers?: readonly ModelPriceContextTier[]\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], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-fable-5-1', rates: [10, 50, 0.25, 12.5], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-haiku-4-5', rates: [1, 5, 0.1, 1.25], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-opus-4-6', rates: [5, 25, 0.5, 6.25], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-opus-4-7', rates: [5, 25, 0.5, 6.25], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-opus-4-8', rates: [5, 25, 0.5, 6.25], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-opus-5', rates: [5, 25, 0.5, 6.25], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-opus-5-5', rates: [4, 20, 0.2, 5], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-sonnet-4-6', rates: [3, 15, 0.3, 3.75], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-sonnet-5', rates: [2, 10, 0.2, 2.5], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'claude-sonnet-5-5', rates: [2, 10, 0.2, 2.5], allowance: { go: 6, goat: 10, pro: 20 } },\n { id: 'deepseek-v4-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { go: 6, goat: 60, pro: 70 } },\n { id: 'deepseek-v4-flash-fast', rates: [0.28, 0.56, 0.07], allowance: { go: 8, goat: 20, pro: 30 } },\n { id: 'deepseek-v4-flash-vision-exp', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'deepseek-v4-pro', rates: [0.66, 1.98, 0.022], peak: [1.32, 3.96, 0.044], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'deepseek-v4.1-flash', rates: [0.15, 0.6, 0.003], peak: [0.3, 1.2, 0.006], allowance: { go: 10, goat: 60, pro: 70 } },\n { id: 'deepseek-v4.1-flash-fast', rates: [0.16, 0.58, 0.016], peak: [0.32, 1.16, 0.032], allowance: { go: 6, goat: 60, pro: 70 } },\n { id: 'fugu-ultra', rates: [5, 30, 0.5], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gemini-3.1-flash-lite', rates: [0.25, 1.5, 0.03], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gemini-3.5-flash', rates: [1.5, 9, 0.15], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gemini-3.5-flash-lite', rates: [0.3, 2.5, 0.03], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gemini-3.6-flash', rates: [1.5, 7.5, 0.15], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gemini-3.7-flash', rates: [1.5, 7.5, 0.15, 0.08334], allowance: { go: 6, goat: 40, pro: 50 } },\n { id: 'gemini-3.8-flash', rates: [1.5, 7.5, 0.15], allowance: { go: 6, goat: 40, pro: 50 } },\n { id: 'glm-5', rates: [1, 3.2, 0.2], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'glm-5.1', rates: [1.4, 4.4, 0.26], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'glm-5.2', rates: [1.4, 4.4, 0.26], allowance: { go: 10, goat: 70, pro: 80 } },\n { id: 'glm-5.2-fast', rates: [3, 10.25, 0.5], allowance: { go: 9, goat: 20, pro: 30 } },\n { id: 'glm-5.3', rates: [1.4, 4.4, 0.26], allowance: { go: 10, goat: 20, pro: 30 } },\n { id: 'glm-5.3-flash', rates: [0.15, 0.5, 0.03], allowance: { go: 10, goat: 40, pro: 50 } },\n { id: 'glm-5.3-flashx', rates: [0.37, 1.25, 0.075], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'gpt-5.3-codex', rates: [2, 8, 0.5, 0], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gpt-5.4', rates: [2.5, 15, 0.25, 0], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gpt-5.4-mini', rates: [0.75, 4.5, 0.075, 0], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gpt-5.5', rates: [5, 30, 0.5, 0], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'gpt-5.6-luna', rates: [0.2, 1.2, 0.02, 0.25], allowance: { go: 6, goat: 20, pro: 30 }, 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], allowance: { go: 6, goat: 70, pro: 80 }, 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], allowance: { go: 6, goat: 20, pro: 20 }, 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], allowance: { go: 6, goat: 20, pro: 20 }, 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], allowance: { go: 6, goat: 20, pro: 30 }, 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], allowance: { go: 6, goat: 20, pro: 20 }, contextTiers: [{\"maxContext\":272000,\"rates\":[2,10,0.2,2.5]},{\"rates\":[4,15,0.4,5]}] },\n { id: 'gpt-6.1-sol', rates: [2, 10, 0.1, 2.5], allowance: { go: 6, goat: 20, pro: 20 }, contextTiers: [{\"maxContext\":272000,\"rates\":[2,10,0.1,2.5]},{\"rates\":[4,15,0.2,5]}] },\n { id: 'grok-4.5', rates: [2, 6, 0.5], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'grok-4.6', rates: [2, 6, 0.5], allowance: { go: 6, goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":200000,\"rates\":[2,6,0.5]},{\"rates\":[4,12,1]}] },\n { id: 'grok-4.7', rates: [2, 6, 0.5], allowance: { go: 6, goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":200000,\"rates\":[2,6,0.5]},{\"rates\":[4,12,1]}] },\n { id: 'inkling', rates: [1, 4.05, 0.17], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'inkling-small', rates: [0.5, 1.2, 0.1], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'kimi-k2.5', rates: [0.6, 3, 0.1], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'kimi-k2.6', rates: [0.95, 4, 0.16], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'kimi-k2.7-code', rates: [0.95, 4, 0.19], allowance: { go: 9, goat: 60, pro: 70 } },\n { id: 'kimi-k2.7-code-highspeed', rates: [1.9, 8, 0.38], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'kimi-k3', rates: [3, 15, 0.3], allowance: { go: 8, goat: 20, pro: 30 } },\n { id: 'longcat-2.0', rates: [0.3, 1.2, 0.006], allowance: { go: 10, goat: 50, pro: 60 } },\n { id: 'mimo-v2.5', rates: [0.14, 0.28, 0.0028], listRates: [0.8, 4, 0.16], allowance: { go: 6, goat: 30, pro: 40 } },\n { id: 'mimo-v2.5-pro', rates: [0.435, 0.87, 0.0036], listRates: [2, 6, 0.4], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-flash', rates: [0.14, 0.28, 0.0028], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-pro', rates: [0.435, 0.87, 0.0036], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'mimo-v2.6-pro-ultraspeed', rates: [4.35, 8.7, 0.036], allowance: { go: 6, goat: 10, pro: 20 } },\n { id: 'minimax-m2.5', rates: [0.3, 1.2, 0.03], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'minimax-m2.7', rates: [0.3, 1.2, 0.06], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'minimax-m3', rates: [0.3, 1.2, 0.06], listRates: [0.6, 2.4, 0.12], allowance: { go: 8, goat: 47, pro: 57 } },\n { id: 'muse-spark-1.1', rates: [1.25, 4.25, 0.15], allowance: { go: 6, goat: 20, pro: 20 } },\n { id: 'muse-spark-1.2', rates: [1.25, 4.25, 0.15], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'muse-spark-1.2-contributor', rates: [0.1, 0.2, 0.002], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'muse-spark-1.3', rates: [1.25, 4.25, 0.15], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'muse-spark-1.3-contributor', rates: [0.1, 0.2, 0.002], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'nemotron-3-ultra', rates: [0.6, 2.4, 0.12], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'qwen-3.6-max', rates: [1.3, 7.8, 0.26, 1.63], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'qwen-3.6-plus', rates: [0.5, 3, 0.1], allowance: { go: 10, goat: 33, pro: 43 }, 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], allowance: { go: 6, goat: 20, pro: 30 }, 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], allowance: { go: 10, goat: 33, pro: 43 } },\n { id: 'qwen-3.7-plus', rates: [0.4, 1.6, 0.08, 0.5], allowance: { go: 10, goat: 33, pro: 43 }, 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], allowance: { go: 10, goat: 70, pro: 80 } },\n { id: 'qwen-3.8-flash', rates: [0.16, 0.47, 0.016], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'qwen-3.8-max', rates: [2, 6, 0.25, 2.5], allowance: { go: 7, goat: 20, pro: 30 } },\n { id: 'qwen-3.8-max-0902', rates: [2, 6, 0.25], allowance: { go: 7, goat: 20, pro: 30 } },\n { id: 'qwen-3.8-omni-flash', rates: [0.15, 0.47, 0.016], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'step-3.5-flash', rates: [0.09, 0.3, 0.02], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'step-3.7-flash', rates: [0.2, 1.15, 0.04], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'step-5-preview', rates: [1, 2.7, 0.05], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'tencent/hy3-paid', rates: [0.14, 0.58, 0.035], allowance: { go: 10, goat: 70, pro: 80 } },\n { id: 'tencent/hy4-preview', rates: [0.834, 2.501, 0.042], allowance: { go: 6, goat: 20, pro: 30 } },\n { id: 'typesafe/jev', rates: [0.042, 0, 0], allowance: { go: 6, goat: 20, pro: 30 } },\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 map\n * of eighty 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 only ever\n // emits rows with the three published rates, so a short row is a broken table\n // 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/**\n * Build the full price row the browser prices a session with.\n *\n * Every figure switches together: once the deal stops being live, the base\n * rates AND each context band come from the pre-discount set, so a session\n * priced after a promotion ends can never mix the two.\n */\nfunction wireRow(id: string, slug: string, row: ModelPriceRow, now: number): CommandCodeModelPrice {\n // `dealLabel()` answers undefined both for \"no deal\" and for \"deal expired\";\n // `listRates` exist only on discounted rows, so the pair settles which set\n // applies. A row with one and not the other falls back to its current rates.\n const promotional = dealLabel(id, now) !== undefined\n const price: CommandCodeModelPrice = {\n id,\n slug,\n ...ratesOf(promotional ? row.rates : (row.listRates ?? row.rates)),\n }\n if (row.peak !== undefined) price.peak = ratesOf(row.peak)\n if (row.contextTiers !== undefined) {\n price.contextTiers = row.contextTiers.map((tier) => ({\n ...ratesOf(promotional ? tier.rates : (tier.listRates ?? tier.rates)),\n ...(tier.maxContext === undefined ? {} : { maxContext: tier.maxContext }),\n }))\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. Free models are served\n * explicitly at zero so the composer can say so instead of showing nothing; the\n * peak windows travel with the table so the browser applies the very schedule\n * this snapshot knows instead of restating it.\n *\n * `now` (defaults to `Date.now()`) resolves lapsed promotions: a discounted row\n * whose `expiresAt` has passed is served at its pre-discount `listRates`, the\n * same instant {@link dealLabel} stops showing its badge. The table is rebuilt\n * per request, so that switch needs no redeploy.\n */\nexport function modelPriceTable(now: number = Date.now()): 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, now))\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, now))\n }\n\n return {\n models,\n peakHours: PEAK_HOUR_RANGES.map(([start, end]) => [start, end] as [number, number]),\n }\n}\n\n/** Slug-keyed view of the rows, built once: neither table nor allowance mutates. */\nconst ROWS_BY_SLUG: ReadonlyMap<string, ModelPriceRow> = new Map(\n MODEL_PRICE_ROWS.map((row) => [row.id, row]),\n)\nconst KNOWN_SLUGS: ReadonlySet<string> = new Set(ROWS_BY_SLUG.keys())\n\n/**\n * The per-model monthly allowance for a CATALOG model id, or undefined when the\n * page carries none (a model without a price row, or the free stealth previews\n * the estimator array omits).\n *\n * Resolution rides the same slug rules as the price table, so\n * `MiniMaxAI/MiniMax-M3` finds the row the page files under `minimax-m3` — the\n * settings page must not grow a second mapping that can drift from this one.\n * The settings page asks for a model only while rendering a list it already\n * has, so this stays a pure lookup with no clock: an allowance is not\n * time-dependent (a plan's figure does not lapse the way a promotional rate\n * does; when the page re-prices it, the next sync carries it).\n */\nexport function modelAllowanceFor(modelId: string): ModelAllowance | undefined {\n const slug = priceSlugFor(modelId, KNOWN_SLUGS)\n if (slug === undefined) return undefined\n return ROWS_BY_SLUG.get(slug)?.allowance\n}\n","/** Non-throwing value guards for untrusted provider payloads. */\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport function stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nexport function numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nexport function booleanValue(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\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'\nimport { isRecord } from './wire-guards.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 => isRecord(v) ? v : 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 // One pass over the groups replaces the two linear `find` scans; the\n // first index wins, matching `find` on duplicate keys.\n const byKey = new Map<string, number>()\n groups.forEach((g, i) => { const key = costGroupKey(g, table); if (!byKey.has(key)) byKey.set(key, i) })\n const groupKey = costGroupKey(group, table)\n if (previous) {\n const old = byKey.get(costGroupKey(previous, table))\n if (old !== undefined) for (const k of COST_TOKEN_KEYS) groups[old]!.tokens[k] -= previous.tokens[k]\n }\n const targetIdx = byKey.get(groupKey)\n let target = targetIdx === undefined ? undefined : groups[targetIdx]\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","/** 两端共用可编辑超时范围,存储仍是整数毫秒;提示不能借用重试退避上限。 */\nexport const MIN_TIMEOUT_SECONDS = 0.001\nexport const MAX_TIMEOUT_SECONDS = 3600\n","/** 网页、终端与模型目录共用的选择规则;显式开关优先于白名单。 */\nexport function modelIsVisible(id: string, allowlist: readonly string[], overrides: unknown): boolean {\n const flag = overrides !== null && typeof overrides === 'object' && !Array.isArray(overrides)\n ? (overrides as Record<string, unknown>)[id] : undefined\n return typeof flag === 'boolean' ? flag : allowlist.length === 0 || allowlist.includes(id)\n}\n\n/** 只接收布尔事实,手工配置中的其他值不能成为可见性开关。 */\nexport function readVisibility(raw: unknown): Record<string, boolean> {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return {}\n return Object.fromEntries(Object.entries(raw).filter(([id, value]) => id !== '' && typeof value === 'boolean'))\n}\n","/** 普通临时故障与额度窗口分开计数;预算按智能体的一次模型请求重置。 */\nexport const TRANSIENT_MAX_RETRIES = 3\nexport const THROTTLED_CODE = 'THROTTLED'\nconst boundedCodes = new Set(['EMPTY_RESPONSE', 'SERVER', 'TIMEOUT', THROTTLED_CODE])\nconst counts = new WeakMap<object, number>()\n\nexport function absorbTransientFailure(agent: object, code: string): 'ignored' | 'retry' | 'exhausted' {\n if (!boundedCodes.has(code)) return 'ignored'\n const used = counts.get(agent) ?? 0\n if (used >= TRANSIENT_MAX_RETRIES) return 'exhausted'\n counts.set(agent, used + 1)\n return 'retry'\n}\n\nexport function resetTransientFailures(agent: object): void {\n counts.delete(agent)\n}\n\nexport function transientBudgetMessage(code: string, message: string): string {\n return `Command Code 请求在 ${TRANSIENT_MAX_RETRIES} 次自动重试后仍失败,已停止重试(${code})。`\n + '请稍后重新发送;若反复出现,请检查服务状态或请求耗时诊断。'\n + ` 原因:${message}`\n}\n","/**\n * Multi-account pool for the Command Code provider (host side).\n *\n * One subscription's 5-hour window is metered, and a user with several wants a\n * request that hits one account's limit to continue on the next without a\n * visible failure. Rotation is passive: a key is marked only on a real\n * pre-stream rejection, and when nothing can serve, marked keys are revived by\n * probing their real usage windows.\n *\n * The non-obvious rules — which rejection may be REPORTED as a spent window, why\n * a fallback is never permanent, what an explicitly selected account's probe\n * costs — are stated at the members below, and recorded in full in AGENTS.md.\n *\n * Cordis-free like the adapter: every host fact arrives through injected thunks,\n * so node tests can drive the pool directly.\n *\n * @module dsh-commandcode-provider/accounts\n */\n\nimport { LlmError } from '@deepseek-ai/dsh-llm'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport type { CredentialRef } from '@deepseek-ai/dsh-credentials'\n\n/**\n * Upper bound on the retry wait attached to the all-exhausted `RATE_LIMIT`.\n * Must equal the adapter's `backoff.maxDelayMs`: dsh-llm-retry honors a\n * provider wait verbatim only at or below that cap — a longer one abandons the\n * retry instead of falling back to local backoff, turning \"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. Without this, a single 429 on the user's pinned\n * account demotes it until the process restarts (issue #51); probing at most\n * once per interval per key bounds a probe endpoint that keeps failing.\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, split by EVIDENCE — what the pool may\n * claim about it — rather than by what it does.\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 plain\n * 429: the key leaves rotation for now, but the provider said nothing about a\n * window, so the pool must not describe one as exhausted. Collapsing the two is\n * issue #54: a bare 429 was reported as a spent window while the account card\n * showed both windows barely used.\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 that\n * no account can serve. `window`: the provider named a usage window, or a\n * `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429 that\n * said nothing about a window (a burst limiter, or a model-/spend-level limit\n * 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 /** Probe one key's usage windows (BOTH windows the endpoint publishes); undefined when it failed. */\n probeWindow(apiKey: string): Promise<AccountWindowProbe | undefined>\n /**\n * The manually selected account slot id, re-read per resolution. It serves\n * whenever it is usable; an unknown id or an exhausted preferred account falls\n * back to the first usable slot — and an exhausted one is re-probed on the way\n * (see {@link CommandCodeAccountPool.resolveKey}), so the fallback lasts only\n * 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. A matching, usable routed account serves before the\n * preferred/rotation selection; an unusable one falls back to the normal\n * 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, so the \"the interval\n * elapsed\" half of {@link CommandCodeAccountPool.canProbeExplicit} is testable\n * without 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 extra\n * account's credential reference). 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 is\n * usable, otherwise the first usable account in rotation order; undefined when\n * no account is usable. Shared by the pool (request path) and the plugin entry\n * (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 usable, else\n * the manually preferred account when usable, else the first usable account\n * in rotation order. Returns `undefined` when no account resolves any key,\n * or when an account this request already used is still UNMARKED — the\n * caller's own rejection is the honest answer then. Throws `RATE_LIMIT` /\n * `INVALID_CREDENTIAL` when every account is marked.\n *\n * `options.tried` lists the keys this request already used; they are removed\n * from the resolution entirely, which is what lets one request walk a\n * four-account pool. An explicit selection (pin or model rule) that a\n * rate-limit mark would demote is probed first, so a fallback never becomes\n * permanent (issue #51). Rules re-read per resolution, so settings apply live.\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: an UNMARKED account\n // leaves the caller's own rejection as the honest answer; when every\n // account is marked instead, the pool owes its own diagnosis — built from\n // the marks as they stand, WITHOUT probing (a probe here answers a\n // question this request cannot act on).\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 const revived = await this.reviveExplicit(available, options?.model ?? '', preferred, chosen)\n return this.pick(revived ?? chosen)\n }\n\n // Every account still in play is marked: probe the real windows before\n // giving up.\n await this.probeAllMarked(available)\n\n // Re-resolve once: the probe pass above may have revived keys, and both the\n // revival check and the error classification read the same post-probe\n // snapshot. (Each resolvedAccounts() re-runs the async seams, so two calls\n // is the minimum here.) The tried keys stay filtered out: a probe that\n // cleared one must not re-offer a key this request already burned.\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 used\n // may be UNMARKED, because an `unavailable` rejection (no credits, a model\n // outside this account's plan) deliberately marks nothing, and that\n // rejection is the honest answer: returning undefined is how the caller\n // surfaces it. The pool's own diagnosis would name the wrong cause, count\n // only the tried subset, and hand dsh-llm-retry a wait that turns a\n // PERMANENT failure into a ~15-minute stall. The all-tried branch above\n // applies exactly this rule.\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 * Which account is serving right now, for display (the settings page's\n * account card, the sidebar usage stats) — without consuming a request's\n * `tried` budget and without throwing when nothing can serve.\n *\n * Reads and self-heals exactly like {@link resolveKey} would: an `unknown`\n * mark on the pinned account is re-probed (throttled the same way, sharing\n * the same per-key timestamp), and a pool where nothing currently resolves\n * gets one batch probe pass too. Without this, the badge read a possibly\n * stale mark forever — nothing but an actual generate request ever cleared\n * an `unknown` mark, so a page left open with no chat activity kept\n * showing \"switched to the fallback account\" long after a real request\n * would have quietly recovered (issue #51's follow-up report: the account\n * card and the sidebar stats both stuck on the wrong account).\n *\n * No `model` parameter: the badge describes the pool as a whole, not one\n * request, so model-routing rules are deliberately not consulted here —\n * matching what the direct `selectActiveAccount` call this replaces did.\n */\n async activeAccount(): Promise<ResolvedAccount | undefined> {\n const accounts = await this.resolvedAccounts()\n if (accounts.length === 0) return undefined\n const preferred = this.deps.preferredId?.()\n const chosen = selectActiveAccount(accounts, preferred)\n if (chosen !== undefined) {\n const revived = await this.reviveExplicit(accounts, '', preferred, chosen)\n return revived ?? chosen\n }\n await this.probeAllMarked(accounts)\n return selectActiveAccount(await this.resolvedAccounts(), preferred)\n }\n\n /**\n * Record a rejection against one key. A `throttled` rejection (the plain 429\n * that named no window) marks the key with the `throttle` cause, leaving\n * rotation exactly like a window mark but keeping the pool's own diagnosis at\n * \"rate limited\" rather than inventing an exhausted window. `rate-limit`\n * marks a `cooldown` until `resetAtMs` when the body named the provider's own\n * reset, otherwise an `unknown` mark whose window is probed lazily.\n * `invalid-credential` (401) disables the key until the stored credential\n * changes.\n *\n * `resetAtMs` is seconds-to-millis converted by the adapter from\n * `error.rateLimit.reset`; it applies to a window mark only. A plain throttle\n * keeps its 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 the `unknown` mark is what keeps the key eligible for\n // the window probe that can still find a real one.\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\n * `assertUsableApiKey()`, which trims it, and reports that trimmed form back\n * to {@link markRejected}: returning the raw value would file every 429/401\n * mark under a key no later lookup can find — rotation would re-offer the same\n * account, the account card would show no mark, and the usage endpoints would\n * 401 while chat kept working.\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 the\n * request to when that id exists among the resolved slots, else the manually\n * pinned slot. Consulted only on the fallback path, so — unlike\n * {@link selectAccountForModel} — it does NOT require the account to be usable,\n * 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` carries its reset and expires by itself, and a\n * `disabled` (401) key stays out until the stored credential changes. The\n * 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 as\n * 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. The\n // stamp costs nothing when the revival was right: a serving account is\n // never probed at all.\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` — see `stampWindowMark`.\n this.stampWindowMark(account, probe)\n return undefined\n }\n\n /**\n * Stamp a probe-read window onto one key. A known reset becomes a cooldown\n * that expires by itself; without one the mark stays `unknown`, so a later\n * probe can still learn it — and a mark that already carries a cooldown\n * keeps it, never trading a known reset for an unknown one. The cause is\n * `window` either way: a probe that read a window as exceeded IS window\n * evidence, whatever the key was marked for. An `until: 0` cooldown would\n * read as \"never usable again\" to {@link accountUsable}, so `unknown` it is.\n */\n private stampWindowMark(account: ResolvedAccount, probe: AccountWindowProbe): void {\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 /**\n * The explicit-account fallback re-check: when `chosen` (what rotation\n * would currently serve) is not the account the user actually asked for,\n * re-probe that explicit account's mark before accepting the fallback —\n * so a rate-limit mark never demotes the user's own selection for good\n * (issue #51). Returns the revived account, or `undefined` when there is\n * nothing to revive (explicit account already serving, not due for a\n * probe, or the probe found it still exceeded). Shared by {@link resolveKey}\n * (the request path) and {@link activeAccount} (the display path), so both\n * agree on what \"currently usable\" means instead of drifting apart.\n */\n private async reviveExplicit(\n accounts: readonly ResolvedAccount[],\n model: string,\n preferred: string | undefined,\n chosen: ResolvedAccount,\n ): Promise<ResolvedAccount | undefined> {\n const explicit = this.explicitAccount(accounts, model, preferred)\n if (explicit === undefined || explicit.key === chosen.key || !this.canProbeExplicit(explicit)) {\n return undefined\n }\n return this.probeExplicit(explicit)\n }\n\n /**\n * Probe every marked account's real usage window when nothing currently\n * resolves. Disabled (401) keys are not probed — an invalid key stays\n * invalid. A throwing probe counts as \"unknown\" (like a failed one): it\n * must not turn the all-exhausted path into a raw rejection instead of\n * RATE_LIMIT. Shared by {@link resolveKey} and {@link activeAccount}.\n */\n private async probeAllMarked(accounts: readonly ResolvedAccount[]): Promise<void> {\n await Promise.all(accounts.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 this.stampWindowMark(account, probe)\n }))\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.\n * Claiming \"all accounts have exhausted their usage window\" here is issue\n * #54: a bare 429 was reported that way while the account card showed both\n * windows barely used.\n *\n * The attached `providerRetryAfterMs` is the exact wait until the earliest known\n * window reset, so dsh-llm-retry sleeps through the window instead of polling at\n * its backoff cadence. It is capped at {@link RETRY_MAX_DELAY_MS} — see there for\n * why a longer attached wait is worse than a capped one; longer resets simply\n * ride the capped local backoff and the probe revival. A throttle diagnosis\n * attaches none: its marks carry no reset.\n *\n * Shared by the all-marked tail of {@link CommandCodeAccountPool.resolveKey} and\n * by its already-tried diagnosis, so the two can never drift apart.\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 metered\n // window is spent — and because it carries no reset (`unknown`, so the next\n // pass may probe), this answer has no time to name one. dsh-llm-retry's own\n // 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 THROTTLED_CODE,\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 (`{ width, height, maxBytes }`, passed straight to its\n * encoder).\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 * @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.\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. This local guard is the ONLY\n * reason the function is not imported; do not replace it with the upstream one.\n * `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 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, so the estimate is per\n * FAMILY, using each vendor's published rule, and the families are recognised\n * by the catalog id (which names the vendor). Every formula is stated here\n * rather than imported: the only in-tree implementations live inside the\n * official adapters, and this plugin deliberately does not depend on those\n * protocols. These are ESTIMATES for context accounting, not invoices — the\n * provider's own usage remains authoritative for a completed request.\n *\n * @module dsh-commandcode-provider/image-tokens\n */\n\nimport { longEdgeDimensions, REQUEST_IMAGE_MAX_LONG_EDGE } 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 to the request long edge (never\n * 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, REQUEST_IMAGE_MAX_LONG_EDGE)\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, a proxy or the network closes the socket mid-generation,\n * so the adapter's read loop sees `done` without the transport's terminal event.\n * A provider cut, a proxy timeout and a dropped socket are indistinguishable\n * from inside the adapter; only the raw wire separates them — which events\n * arrived, when the last one landed, how long the socket then sat silent.\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 read as \"off\" rather than as a file name.\n *\n * Every model request appends one JSONL record per raw chunk plus lifecycle\n * records (`request`, `response`, `eof`, `idle-timeout`, `read-error`, `end`,\n * `stream-close`), each stamped with `streamId` and `at` — milliseconds since\n * the trace opened, before connecting. `stream-open.startedAt` is Unix time in\n * milliseconds, so interleaved calls and session logs can be correlated.\n *\n * PRIVACY: the chunk records carry the provider's own payload verbatim, because\n * a truncated answer is exactly what is being diagnosed — treat the file as\n * conversation content, not as a log safe to share. The request-side record\n * records structural counts and SHA-256 fingerprints only; it never carries the\n * raw request body, an API key, or any request header. Keep it that way.\n *\n * Trade-offs: OFF costs one `process.env` read per request; ON appends\n * synchronously, one file open per chunk, because the trace must survive a host\n * killed mid-diagnosis. A trace that cannot be written turns itself off rather\n * than failing the request it observes — a diagnostic must never become the\n * outage.\n *\n * @module\n */\n\nimport { appendFileSync, mkdirSync } from 'node:fs'\nimport { randomUUID } from 'node:crypto'\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 and 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 only: one\n * bounded `end` and `stream-close` can still follow, so a long reasoning phase\n * 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` 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 const streamId = randomUUID()\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, streamId, ...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, streamId, 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', startedAt })\n return {\n get enabled() { return !stopped && !capped },\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","/** 请求耗时只记录阶段、计数和状态;不记录消息、凭据、请求头或错误正文。 */\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport const REQUEST_TIMING_ENV = 'DSH_COMMANDCODE_TIMING'\ntype Phase = 'credentials' | 'images' | 'body' | 'serialization' | 'headers'\ntype Outcome = 'finished' | 'error' | 'aborted' | 'cancelled'\n\nexport interface RequestTimingSummary {\n version: 1\n startedAt: number\n model: string\n outcome: Outcome\n errorCode?: string\n totalMs: number\n phasesMs: Record<Phase, number>\n firstByteMs?: number\n firstContentMs?: number\n attempts: Array<{ protocol: string; bodyBytes: number; headersMs: number; status?: number }>\n}\n\nexport type RequestTimingSink = (summary: RequestTimingSummary) => void | Promise<void>\n\n/** 每次生成独立计时;可注入时钟验证顺序,不依赖真实等待。 */\nexport class RequestTiming {\n private readonly started: number\n private readonly summary: RequestTimingSummary\n\n constructor(model: string, private readonly sink?: RequestTimingSink, private readonly now = () => performance.now()) {\n this.started = now()\n this.summary = {\n version: 1, startedAt: Date.now(), model, outcome: 'cancelled', totalMs: 0,\n phasesMs: { credentials: 0, images: 0, body: 0, serialization: 0, headers: 0 }, attempts: [],\n }\n }\n\n /** 返回结束函数,确保成功和异常都计入同一阶段。阶段可嵌套,不能直接相加。 */\n phase(name: Phase): () => void {\n if (!this.sink) return () => {}\n const start = this.now()\n return () => { this.summary.phasesMs[name] += this.now() - start }\n }\n\n attempt(protocol: string, bodyBytes: number): (status?: number) => void {\n if (!this.sink) return () => {}\n const start = this.now()\n const attempt = { protocol, bodyBytes, headersMs: 0 }\n this.summary.attempts.push(attempt)\n return (status) => {\n Object.assign(attempt, { headersMs: this.now() - start, ...(status === undefined ? {} : { status }) })\n this.summary.phasesMs.headers += attempt.headersMs\n }\n }\n\n first(kind: 'firstByteMs' | 'firstContentMs'): void {\n if (this.sink && this.summary[kind] === undefined) this.summary[kind] = this.now() - this.started\n }\n\n async close(outcome: Outcome, errorCode?: string): Promise<void> {\n if (!this.sink) return\n this.summary.outcome = outcome\n this.summary.totalMs = this.now() - this.started\n if (errorCode !== undefined) this.summary.errorCode = errorCode\n // 观测失败不能改变生成结果;每次请求只异步写一条,避免逐块同步磁盘写入。\n try { await this.sink(this.summary) } catch { /* 诊断降级不影响请求。 */ }\n }\n}\n\n/** 与原始流诊断独立开关,便于仅收集数值耗时。 */\nexport function openRequestTiming(model: string, sink?: RequestTimingSink): RequestTiming {\n if (sink) return new RequestTiming(model, sink)\n const raw = process.env[REQUEST_TIMING_ENV]?.trim()\n if (!raw || ['0', 'false', 'no', 'off'].includes(raw.toLowerCase())) return new RequestTiming(model)\n const path = ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase())\n ? join(tmpdir(), 'dsh-commandcode-timing.jsonl') : raw\n return new RequestTiming(model, async (summary) => {\n await mkdir(dirname(path), { recursive: true })\n await appendFile(path, `${JSON.stringify(summary)}\\n`, { mode: 0o600 })\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 * Owns the three chat transports (`/alpha/generate`, `/provider/v1/chat/completions`,\n * `/provider/v1/messages`),\n * message conversion, SSE/JSONL parsing, the catalog + its on-disk cache, and\n * the pre-stream account rotation loop. The wire protocol is\n * reverse-engineered (command-code@1.28.4, re-verified through 1.73.0);\n * docs/agent-reference/adapter-protocol.md holds the full protocol record.\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 { createHash, randomUUID } from 'node:crypto'\nimport { IDENTITY_ENCODING_HEADER } from './response-encoding.ts'\nimport { MAX_TIMEOUT_SECONDS } from './timeout-limits.ts'\nimport { modelIsVisible } from './model-visibility.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef, RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n CONTEXT_WINDOW_EXCEEDED_CODE,\n isContextWindowExceededError,\n LlmAdapter,\n LlmError,\n ProviderRequestId,\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 { allowanceTierForWeight } from './model-prices.ts'\nimport { boundTraceText, openStreamTrace, STREAM_TRACE_ENV } from './stream-trace.ts'\nimport { openRequestTiming, type RequestTiming, type RequestTimingSink } from './request-timing.ts'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport { booleanValue, isRecord, numberValue, stringValue } from './wire-guards.ts'\n\nimport {\n DEFAULT_MESSAGES_MAX_TOKENS,\n KNOWN_EFFORTS,\n KNOWN_IMAGE_MODELS,\n MODEL_OUTPUT_TOKEN_LIMITS,\n capabilityDescription,\n compareByPlan,\n modelVisibleForAnyAccount,\n requiresMessagesEndpoint,\n subscriptionPlanInfo,\n type CommandCodeBillingAccess,\n} from './capabilities.ts'\n\n/**\n * Output ceilings the endpoint has named in a live rejection, per model.\n *\n * The snapshot in ./capabilities.ts carries the vendor-published ceiling for\n * 74 of the 84 catalog models (see scripts/sync-output-limits.mjs). The other\n * 10 are models no vendor publishes yet, and a gateway is free to sit below\n * the vendor figure even where one exists — so this map is the correction\n * channel, not a fallback of last resort: the endpoint states the model's own\n * ceiling in its rejection, so one wasted round trip is enough to know it for\n * the rest of the process.\n *\n * Shared by adapters for the same gateway, but not across apiBase values: a\n * proxy can enforce a smaller ceiling for the same model id. Only ever tightens\n * within that gateway, so a stale catalog row cannot undo a live refusal.\n */\nconst learnedOutputLimits = new Map<string, Map<string, number>>()\n\n/**\n * Output ceilings the CATALOG published, per model.\n *\n * `/provider/v1/models` carries `max_output_tokens` in its schema and the\n * official pi provider already prefers it, but the endpoint does not send it\n * yet — so this is empty today and fills in on its own the day it does. It sits\n * above the models.dev snapshot and below what a live rejection proved, because\n * that ordering is also the order of trust: the gateway knows its own ceiling,\n * a rejection proves it, and models.dev is a third party describing the same\n * model. Restored from the on-disk catalog cache so a published ceiling\n * survives a restart without waiting for the next catalog fetch.\n */\nconst publishedOutputLimits = new Map<string, Map<string, number>>()\n\n/** Keep model facts from one gateway from constraining another gateway. */\nfunction outputLimitsFor(store: Map<string, Map<string, number>>, apiBase: string): Map<string, number> {\n let limits = store.get(apiBase)\n if (limits === undefined) {\n limits = new Map()\n store.set(apiBase, limits)\n }\n return limits\n}\n\n/**\n * The output ceiling this gateway route sends for `modelId`.\n *\n * `/provider/v1/models` publishes `context_length` and `supported_endpoints`\n * but no output cap today, while each endpoint refuses a larger `max_tokens` per\n * model — the Messages endpoint names its own in the rejection (`max_tokens:\n * 200000 > 128000, which is the maximum allowed number of output tokens for\n * claude-sonnet-5-5`). What the endpoint has already named wins, then the\n * catalog's own figure once it publishes one, then the snapshot, then — for\n * the Messages-route models only — the conservative value, because the ceilings\n * actually observed are below the global default and assuming otherwise would\n * fail every request.\n */\nfunction modelOutputTokenLimit(apiBase: string, modelId: string): number {\n const learned = outputLimitsFor(learnedOutputLimits, apiBase).get(modelId)\n const known = outputLimitsFor(publishedOutputLimits, apiBase).get(modelId) ?? MODEL_OUTPUT_TOKEN_LIMITS.get(modelId)\n if (learned !== undefined && (known === undefined || learned < known)) return learned\n if (known !== undefined) return known\n return requiresMessagesEndpoint(modelId) ? DEFAULT_MESSAGES_MAX_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS\n}\n\n/**\n * Record a ceiling the endpoint just stated, if it is one this route can act\n * on: a real number, and one below what the next request would otherwise send.\n * A ceiling at or above the current budget describes a request that was not\n * refused for being too large, and acting on it would be a guess.\n */\nfunction noteOutputCeiling(apiBase: string, modelId: string, ceiling: number): boolean {\n if (!Number.isSafeInteger(ceiling) || ceiling <= 0) return false\n if (ceiling >= modelOutputTokenLimit(apiBase, modelId)) return false\n outputLimitsFor(learnedOutputLimits, apiBase).set(modelId, ceiling)\n return true\n}\n\n/**\n * The ceiling to retry this turn with, when `error` is a request-side output\n * refusal the route can act on — else undefined, meaning surface it.\n *\n * Read from the message, so it covers both shapes the same refusal arrives in:\n * an HTTP 400 (`PROVIDER_HTTP_ERROR`) and an in-stream error frame\n * (`PROVIDER_STREAM_ERROR`). Both carry the endpoint's wording, and both are\n * already classified as output refusals rather than context overflows by the\n * time they reach here.\n *\n * Recording is what makes the retry pay off: the ceiling is kept for this\n * gateway and model, so a refused turn leaves its next request correct.\n */\nfunction outputCeilingRefusal(apiBase: string, modelId: string, error: unknown): number | undefined {\n if (!(error instanceof LlmError)) return undefined\n const detail = error.message\n if (!OUTPUT_LIMIT_REJECTION.test(detail)) return undefined\n const stated = parseOutputCeiling(detail)\n if (stated === undefined) return undefined\n return noteOutputCeiling(apiBase, modelId, stated) ? stated : undefined\n}\n\n/** Keep the two user-facing languages and error metadata together. */\nfunction bilingual(code: string, en: string, zh: string, options?: LlmErrorOptions): LlmError {\n return new LlmError(`${en};${zh}`, code, options)\n}\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.73.0'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\n\n/**\n * The output budget this bundle asks for, and the ceiling it will never exceed.\n *\n * 131 072, chosen against a measured provider limit rather than a round guess.\n * Probing `/alpha/generate` directly on 2026-09-28: 64 000 → 200, 131 072 → 200,\n * 196 608 → 200, **200 000 → 200, 200 704 → 400**, 1 000 000 → 400. The server\n * therefore caps `max_tokens` at 200 000, and it does so identically for a\n * 262 144-window model (`stealth/pixel-canary`) and a 1 000 000-window one\n * (`stealth/space-bunny-alpha`) — the cap is global, not per model. 131 072\n * keeps a 35 % margin under it while covering the real output ceiling of the\n * models that have one (Claude 64 K, Gemini 64 K, several at 128 K).\n *\n * The old 64 000 was never a provider requirement: it cost nothing in latency\n * (a 64 000 request answered headers in 1.28 s against 1.57 s for 131 072) but\n * it did cap what a model could ever say in one turn.\n *\n * No client-side clamp is applied on top of this: an earlier version pre-shrank\n * `max_tokens` from an estimate of the prompt already sent (`requestContextBudget()`,\n * issue #67), but that estimate over-corrected on ordinary long conversations —\n * exactly the \"output gets cut short as the conversation grows\" symptom issue #74\n * reported — while a live A/B probe (2026-09-30, `stealth/space-bunny-alpha`,\n * ~19.6% over its 1,000,000-token window with no client-side shrink) showed the\n * endpoint answers a genuine overflow with an unambiguous `400 … exceeds the\n * model's context window`, which `isContextOverflowDetail()` below already\n * classifies as `CONTEXT_WINDOW_EXCEEDED` independently of this constant. See\n * [决策记录](../docs/决策记录.md).\n */\nexport const DEFAULT_GENERATE_MAX_TOKENS = 131_072\n\n/**\n * The fallback when the catalog carries no output ceiling for a model.\n *\n * `/provider/v1/models` publishes only `context_length` — no output limit — so\n * the catalog cannot learn one per model and derives a stand-in from the\n * window instead. Kept equal to {@link DEFAULT_GENERATE_MAX_TOKENS} on purpose:\n * a lower value here would silently re-cap every request through\n * `Math.min(contextLength, this)` before the ceiling above is ever consulted.\n */\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 131_072\nexport const MODELS_TIMEOUT_MS = 10_000\n/** 目录短期复用;刷新失败只短暂退避,避免反复阻塞模型选择器。 */\nexport const MODEL_CATALOG_TTL_MS = 5 * 60_000\nconst MODEL_CATALOG_RETRY_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/**\n * Endpoint protocol selected for one generate call.\n *\n * `messages` is the Anthropic Messages surface at\n * `{apiBase}/provider/v1/messages`, the only Provider API route the Claude\n * family answers (posted to `/chat/completions` they refuse with `400 Model\n * \"<id>\" must be called via /provider/v1/messages`). `openai` is the\n * documented Chat Completions surface; `cli` is Command Code's private\n * `/alpha/generate` transport, kept for Go-plan keys (the one plan without\n * Provider API access) and as the `upgrade_required` fallback.\n */\ntype CommandCodeProtocol = 'cli' | 'openai' | 'messages'\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/**\n * Head-of-request timeout: how long to wait for the first response byte.\n *\n * 300 s, and that number is the official CLI's, not a round choice. Decompiled\n * from `command-code@1.66.0`: its `createNodeTransport` fetch passes only the\n * caller's `signal` and sets no timeout at all, so the model request inherits\n * Node/undici's own default — measured at 301.0 s against a local server that\n * accepts the connection and never sends headers. The previous 60 s default was\n * five times stricter than the CLI it emulates, and being stricter only ever\n * costs legitimate requests: a slow upstream first token on the Provider API\n * route can outlast 60 s, and the official CLI simply waits it out. Measured\n * headers (2026-09-28, 26 250-token prompt, `max_tokens: 16` to separate the\n * header from the generation): `/alpha/generate` 2.12 / 2.56 / 2.75 s,\n * `/provider/v1/chat/completions` 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap\n * with the Provider API route varying over a 2.5 s span against the CLI route's\n * 0.6 s. A gateway that is genuinely dead now takes longer to name itself,\n * which is what the consecutive-timeout streak exists to bound (three\n * attempts, then a diagnosis instead of another re-send).\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 300_000\n/** Stream idle timeout: a generation that stalls this long is a dead connection. */\nexport const DEFAULT_STREAM_IDLE_TIMEOUT_MS = 300_000\n/** Version 3 binds cached catalog facts to their gateway; older files lack a safe source. */\nconst MODEL_CACHE_VERSION = 3\n\n// ---------------------------------------------------------------------------\n// Small helpers\n// ---------------------------------------------------------------------------\n\n/** A size-and-hash summary safe to put in an opt-in diagnostic trace. */\ninterface ValueFingerprint {\n bytes: number\n sha256: string\n}\n\n/**\n * A lone UTF-16 surrogate half: a high surrogate not followed by a low one, or\n * a low surrogate not preceded by a high one. Such a half is not a character —\n * it only arises from a truncated slice, a lossy decode, or a lone `\\uD83D`\n * escape — and it survives `JSON.stringify` as an escape (`\"\\ud83d\"`) rather\n * than failing locally, so the request leaves the process carrying a string no\n * UTF-8 consumer can round-trip. Providers running strict decoders reject it.\n *\n * This is the same expression `@earendil-works/pi-ai` applies to every outgoing\n * string on this endpoint. Valid astral characters (emoji and anything else\n * outside the BMP) are PAIRED surrogates and pass through untouched.\n */\nconst LONE_SURROGATE_PATTERN = /[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g\n\n/**\n * A cheap pre-test for \"this string contains any surrogate code unit at all\",\n * paired or not. The exact pattern above needs lookaround, which V8 cannot\n * optimize into a fast scan; this one is a plain range test. Real prompts are\n * overwhelmingly ASCII-plus-CJK with no surrogates, so the common case pays one\n * linear scan instead of the lookaround pass. Measured on a 412 KB request\n * body: 1.40 ms with the exact pattern alone against 0.77 ms with this gate,\n * where a bare `JSON.stringify` is 0.59 ms.\n */\nconst ANY_SURROGATE_PATTERN = /[\\uD800-\\uDFFF]/\n\n/**\n * Drop lone surrogate halves from one outgoing string.\n *\n * Applied at the single point a request body is serialized, so every field of\n * every transport is covered — system text, message content, tool schemas and\n * tool results alike — instead of enumerating the fields that can carry text\n * and missing one. The value is returned unchanged whenever it holds no\n * surrogate at all, which is the ordinary case.\n *\n * The `test()` call deliberately uses the flagless {@link ANY_SURROGATE_PATTERN}:\n * a global regex is stateful, so testing with one would advance `lastIndex` and\n * make consecutive calls on the same string alternate between true and false.\n * `replace()` resets `lastIndex` itself, so the global pattern is safe there.\n */\nfunction sanitizeSurrogates<T>(value: T): T {\n if (typeof value !== 'string') return value\n return ANY_SURROGATE_PATTERN.test(value)\n ? (value.replace(LONE_SURROGATE_PATTERN, '') as T)\n : value\n}\n\n/** Hash one request value without retaining or logging its contents. */\nfunction fingerprintValue(value: unknown): ValueFingerprint {\n let serialized: string\n try {\n serialized = JSON.stringify(value) ?? String(value)\n } catch {\n serialized = String(value)\n }\n return {\n bytes: Buffer.byteLength(serialized),\n sha256: createHash('sha256').update(serialized).digest('hex'),\n }\n}\n\n/**\n * Structural request facts for issue #64's cache diagnosis.\n *\n * This deliberately records hashes and counts, never the prompt, tool\n * descriptions, image bytes, headers, or credentials. `body` catches changes\n * in any wire field; the named sections make a changed system/tools/messages\n * prefix visible without making the trace a copy of the conversation.\n */\nfunction requestFingerprint(protocol: CommandCodeProtocol, body: Record<string, unknown>): Record<string, unknown> {\n const params = protocol === 'cli' ? recordOrEmpty(body.params) : body\n const messages = Array.isArray(params.messages) ? params.messages : []\n const tools = Array.isArray(params.tools) ? params.tools : []\n return {\n protocol,\n model: typeof params.model === 'string' ? params.model : undefined,\n threadId: typeof body.threadId === 'string' ? body.threadId : undefined,\n body: fingerprintValue(body),\n config: fingerprintValue(body.config),\n system: fingerprintValue(protocol === 'cli' ? params.system : messages.filter((m) => isRecord(m) && m.role === 'system')),\n tools: {\n count: tools.length,\n ...fingerprintValue(tools),\n },\n messages: {\n count: messages.length,\n roles: messages.map((message) => isRecord(message) && typeof message.role === 'string' ? message.role : 'unknown'),\n ...fingerprintValue(messages),\n // Whole-history hashes change on every append. Per-message hashes let\n // adjacent requests identify the first changed byte-bearing message.\n items: messages.map((message) => fingerprintValue(message)),\n },\n }\n}\n\n/** Only provider correlation headers, never a wholesale response-header dump. */\nconst RESPONSE_ID_HEADERS = ['x-request-id', 'request-id', 'x-trace-id', 'x-generation-id', 'traceparent'] as const\n\nfunction responseIdentifiers(headers: Headers): Record<string, string> {\n const result: Record<string, string> = {}\n for (const name of RESPONSE_ID_HEADERS) {\n const value = diagnosticId(headers.get(name))\n if (value !== undefined) result[name] = value\n }\n return result\n}\n\nfunction diagnosticId(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 && value.length <= 512 ? value : undefined\n}\n\n/** Small, JSON-only response facts that DSH can retain on the assistant source. */\ninterface ResponseMetadata {\n protocol: CommandCodeProtocol\n headers: Record<string, string>\n responseId?: string\n generationId?: string\n providerRequestId?: string\n traceId?: string\n}\n\nfunction captureResponseIdentifiers(metadata: ResponseMetadata, event: unknown): void {\n if (!isRecord(event)) return\n // An OpenAI completion id or an AI SDK response-metadata id names the\n // response. A tool-call id does not, so never collect generic CLI event ids.\n if ((metadata.protocol === 'openai' && Array.isArray(event.choices)) || event.type === 'response-metadata') {\n const id = diagnosticId(event.id)\n if (id !== undefined) metadata.responseId = id\n }\n for (const name of ['generationId', 'providerRequestId', 'traceId'] as const) {\n const id = diagnosticId(event[name])\n if (id !== undefined) metadata[name] = id\n }\n}\n\nfunction hasResponseIdentifiers(metadata: ResponseMetadata): boolean {\n return Object.keys(metadata.headers).length > 0 || metadata.responseId !== undefined\n || metadata.generationId !== undefined || metadata.providerRequestId !== undefined || metadata.traceId !== undefined\n}\n\n/** Keep the provider's request id on DSH's durable failure, when it supplied one. */\nfunction failureWithRequestId(error: unknown, metadata: ResponseMetadata): unknown {\n const id = metadata.providerRequestId ?? metadata.headers['x-request-id'] ?? metadata.headers['request-id']\n if (!(error instanceof LlmError) || error.failure.requestId !== undefined || id === undefined) return error\n return new LlmError(error.message, error.code, {\n ...error.failure,\n requestId: ProviderRequestId(id),\n ...(error.cause === undefined ? {} : { cause: error.cause }),\n })\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 }` — the same summary text the\n * scalar `delta.reasoning` carries. A `type` filter would drop one family, and\n * losing thinking is the failure this exists to prevent. `text` wins per entry,\n * but an EMPTY `text` must not shadow a populated `summary` (the Responses wire\n * emits `text: ''` placeholders), so the fallback tests for non-empty rather\n * than merely present. Encrypted-blob entries carry neither member and\n * contribute nothing; no entry carries both, so nothing is 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: ''`), and `??` alone cannot express that.\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 * A request-side `max_tokens` refusal, told apart from a context overflow that\n * mentions the same field. Kept narrow on purpose: the overflow pattern also\n * matches a bare `max_tokens`, so this must name the specific shapes the\n * endpoint uses — a ceiling comparison, its prose about output tokens, or a\n * request-validation error on the field.\n */\nconst OUTPUT_LIMIT_REJECTION = new RegExp([\n 'max_tokens:\\\\s*\\\\d+\\\\s*>\\\\s*\\\\d+',\n 'maximum allowed number of output tokens',\n 'invalid input[^\\\\n]*max_tokens',\n 'expected number[^\\\\n]*at max_tokens',\n].join('|'), 'i')\n\n/**\n * The output ceiling the endpoint states in a `max_tokens` refusal, read off\n * its own comparison: `max_tokens: 131072 > 128000` yields 128000.\n *\n * Only the comparison form is parsed. The other shapes\n * {@link OUTPUT_LIMIT_REJECTION} matches — a bare validation error, or the\n * prose without the numbers — name no ceiling, and guessing one would be worse\n * than failing: a fabricated value is indistinguishable from a real one at the\n * point where it decides the next request's budget.\n */\nfunction parseOutputCeiling(detail: string): number | undefined {\n const stated = /max_tokens:\\s*\\d+\\s*>\\s*(\\d+)/i.exec(detail)?.[1]\n if (stated === undefined) return undefined\n const ceiling = Number(stated)\n return Number.isSafeInteger(ceiling) && ceiling > 0 ? ceiling : undefined\n}\n\n/**\n * The advice floor for a Provider-API timeout: doubling a 60 s budget is still\n * short for a slow upstream first token, so the suggestion never goes below 5\n * minutes. 提示上限与页面可编辑范围相同,重试退避上限不约束单次请求。\n */\nconst MIN_SUGGESTED_TIMEOUT_MS = 300_000\n\n/**\n * Why one attempt saw no response headers, and what the user can do about it.\n *\n * The TRANSPORT is the reliable signal; the request size is not — and the\n * mechanism is read straight out of the official CLI rather than inferred from\n * a timing. `createNodeTransport` passes only the caller's `signal` and sets no\n * timeout, so the two routes differ in WHO answers the headers:\n * `/alpha/generate` has the gateway answer them before the model starts, while\n * `/provider/v1/chat/completions` cannot answer until its upstream emits a\n * first token, so whatever that upstream is doing is charged to the header\n * wait. Measured 2026-09-28 (26 250-token prompt, `max_tokens: 16`):\n * `/alpha/generate` 2.12 / 2.56 / 2.75 s, `/provider/v1/chat/completions`\n * 5.52 / 2.98 / 3.70 s — a ~1.1 s median gap, with the Provider API route\n * swinging across 2.5 s where the CLI route moved 0.6 s. A larger prompt moves\n * neither, which is why an earlier draft that branched on a 1 MiB body\n * threshold was wrong: size is not the variable here. Only the route decides.\n *\n * @param protocol - the transport the attempt used.\n * @param timeoutMs - the header budget that just expired.\n */\nexport function headersTimeoutAdvice(\n protocol: CommandCodeProtocol,\n timeoutMs: number,\n): { cause: 'gateway' | 'upstream-first-token'; suggestionMs?: number } {\n if (protocol === 'openai') {\n const suggestionMs = Math.min(MAX_TIMEOUT_SECONDS * 1000, Math.max(timeoutMs * 2, MIN_SUGGESTED_TIMEOUT_MS))\n return {\n cause: 'upstream-first-token',\n // That route charges the upstream's time-to-first-token to this wait, so\n // a larger budget is the one thing that can help when it expires.\n ...(suggestionMs > timeoutMs ? { suggestionMs } : {}),\n }\n }\n return { cause: 'gateway' }\n}\n\n/**\n * How many consecutive header timeouts on ONE unchanged payload stop being a\n * blip. The retry policy whitelists `TIMEOUT` with `maxRetries: 1000` and a\n * 500 ms → 15 min backoff, which is right for a provider that says when to\n * come back but wrong for a gateway that simply never answers: the reporter\n * saw the identical multi-megabyte body re-sent for hours (issue #67) instead\n * of a diagnosis. Three is where a 60 s budget has already spent three\n * minutes waiting, so the cost of being wrong is bounded and the user gets an\n * answer either way.\n */\nconst MAX_CONSECUTIVE_HEADER_TIMEOUTS = 3\n\n/** Streak key for a session-less call, so those keep the old single-slot semantics instead of never escalating. */\nconst GLOBAL_HEADER_TIMEOUT_KEY = '\\u0000global'\n\n/** UTF-8 byte length, computed only on the timeout path so a large body is encoded once, not per attempt. */\nfunction utf8ByteLength(text: string): number {\n return new TextEncoder().encode(text).length\n}\n\n/**\n * The thrown headers timeout, worded for the cause it actually has.\n *\n * Every earlier version of this message said \"通常是网络或代理问题\" for both\n * transports, which is actively wrong for a large `/provider/v1/chat/completions`\n * prompt: there the model simply needs longer than any budget, and a user sent\n * to check their proxy never finds anything. The code stays `TIMEOUT` (still\n * retryable) in both branches — only the diagnosis and the advice change.\n */\nfunction headersTimeoutError(input: {\n protocol: CommandCodeProtocol\n endpoint: string\n body: string\n timeoutMs: number\n cause: unknown\n}): LlmError {\n const { protocol, endpoint, timeoutMs, cause } = input\n const bytes = utf8ByteLength(input.body)\n const megabytes = `${(bytes / 1_048_576).toFixed(1)} MB`\n const advice = headersTimeoutAdvice(protocol, timeoutMs)\n if (advice.cause === 'upstream-first-token') {\n const suggestion = advice.suggestionMs ?? timeoutMs\n return bilingual(\n 'TIMEOUT',\n `Command Code API request to ${endpoint} did not respond within ${timeoutMs}ms: this route withholds response headers until the upstream model emits its first token, and it did not start within the budget. Raise \"Request timeout\" in the plugin's advanced settings to ${suggestion}ms, or compact the session or start a new one. The request body was ${megabytes}, but size is not the cause here — a slow upstream is. ${errorChain(cause)}`,\n `Command Code API 请求在 ${timeoutMs} 毫秒内未收到响应:该路由要等上游模型吐出第一个 token 才返回响应头,而上游在预算内没有开始作答。可在插件「高级」设置里把「请求超时」调到 ${suggestion} 毫秒,或压缩上下文 / 新开会话。本次请求体约 ${megabytes},但体积不是原因——慢的是上游。(${errorChain(cause)})`,\n { cause },\n )\n }\n return bilingual(\n 'TIMEOUT',\n `Command Code API request to ${endpoint} did not respond within ${timeoutMs}ms: the gateway returned no response headers at all — it answers headers itself before the model replies. This is usually provider queueing, a Go-plan capacity limit, or a network/proxy path problem; a longer timeout will not help, but retrying usually recovers. The request body was ${megabytes}, and size is not the cause on this route. ${errorChain(cause)}`,\n `Command Code API 请求在 ${timeoutMs} 毫秒内未收到响应:网关完全没有返回响应头——它会在模型开始回答前先返回响应头。这通常是服务商排队、Go 套餐容量限制,或网络/代理链路问题;调大超时不会有帮助,重试通常可恢复。本次请求体约 ${megabytes},而在该路由上体积不是原因。(${errorChain(cause)})`,\n { cause },\n )\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, the Provider API transport as a top-level `error` member of\n * 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). Order is 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. Reported as retryable `SERVER` instead, the adapter resent\n * the byte-identical oversized request up to `maxRetries` times and the\n * session could never recover (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.\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 (OUTPUT_LIMIT_REJECTION.test(detail)) {\n // Checked BEFORE the overflow test, and that ordering is the whole point:\n // `isContextOverflowDetail` matches a bare `max_tokens`, so this refusal\n // used to be reported as an oversized session. The harness then compacted a\n // context that was within budget and resent the identical request, which the\n // endpoint refused identically (issue #71) — a turn that could not recover,\n // described to the user as one that could. A stream-side refusal has no\n // status to report, so the wording names the field only.\n const stated = /max_tokens:\\s*\\d+\\s*>\\s*\\d+/i.exec(detail)?.[0]\n return bilingual(\n 'PROVIDER_STREAM_ERROR',\n `Command Code refused the request's max_tokens for this model`\n + (stated !== undefined ? ` (${stated})` : '')\n + ' — the session is not oversized, so compacting it will not help;'\n + ' lower \"Max output tokens\" or pick a model with a larger output ceiling',\n `Command Code 拒绝了本次请求的 max_tokens(该模型的输出上限更低)`\n + (stated !== undefined ? `(${stated})` : '')\n + '——会话内容并未超长,压缩上下文无效;请调低「最大输出 token」或改用输出上限更大的模型',\n statusOption,\n )\n }\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 bilingual(\n CONTEXT_WINDOW_EXCEEDED_CODE,\n `Command Code stream error: ${message}`,\n 'Command Code API 拒绝了这次请求:内容超出模型上下文窗口。正在压缩上下文后重试;如仍失败,请新建会话或减少上下文',\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` and unnecessarily retried by the route policy.\n // An explicit `isRetryable: true` still 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 const rejection = classifyAccountRejection(statusCode ?? 0, JSON.stringify(value) ?? message)\n if (rejection?.reason === 'rate-limit' || rejection?.reason === 'throttled') {\n const wait = rejection.resetAtMs === undefined ? 0 : Math.min(RETRY_MAX_DELAY_MS, Math.max(1000, rejection.resetAtMs - Date.now()))\n return bilingual(\n rejection.reason === 'rate-limit' ? 'RATE_LIMIT' : THROTTLED_CODE,\n `Command Code stream error: ${message}`,\n rejection.reason === 'rate-limit' ? 'Command Code 用量窗口已限流,等待恢复' : 'Command Code 请求暂时被限流,正在重试',\n { ...statusOption, ...(wait > 0 ? { providerRetryAfterMs: wait } : {}) },\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). The gateway validates every function\n// schema's ROOT as an object schema and rejects the whole request otherwise.\n// Tool schemas do not always come from the harness's own typed builder: 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.\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 * Only the root is touched and every path returns a copy: the harness may\n * deep-freeze the caller's schema.\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, the last\n// fallback in the plugin entry's resolution order. 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\n// ---------------------------------------------------------------------------\n\ninterface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n /**\n * The output ceiling the catalog PUBLISHED for this model, as distinct from\n * the one {@link maxTokens} was resolved to. The gateway has this field in\n * its schema and the official pi provider already reads it, but it does not\n * send it yet — the endpoint currently stops after `supported_endpoints`\n * (see the pi provider's `CommandCodeModelListItem`). Carried separately so\n * that a value cached before this field existed cannot outlive it: the\n * snapshot in ./capabilities.ts and the runtime's learned limits are both\n * re-derivable, while a published number is the one thing only the gateway\n * can say.\n */\n publishedMaxTokens?: number\n /**\n * The catalog's own per-model route list, e.g. `['/chat/completions',\n * '/responses']` or `['/messages']`. New as of command-code@1.55.0 and the\n * authoritative routing source: a model listed only under `/messages`\n * answers `400 Model \"<id>\" must be called via /provider/v1/messages` on\n * every other route. Absent from older cache files, in which case\n * `resolveProtocol()` falls back to {@link requiresMessagesEndpoint}.\n */\n supportedEndpoints: readonly string[]\n}\n\nfunction parseCatalogResponse(value: unknown, apiBase: string): 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 // A refreshed catalog may remove a previously published field; do not let\n // its older value silently outlive the response from this same gateway.\n publishedOutputLimits.set(apiBase, new Map())\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 const endpoints = Array.isArray(entry.supported_endpoints)\n ? entry.supported_endpoints.filter((item): item is string => typeof item === 'string')\n : []\n // The gateway's own ceiling, when it publishes one. Today it sends nothing\n // after `supported_endpoints`, so this is normally absent and the snapshot\n // answers instead; recording it here is what lets the published figure take\n // over the moment it appears, with no change here.\n const published = numberValue(entry.max_output_tokens)\n if (published !== undefined && published > 0) outputLimitsFor(publishedOutputLimits, apiBase).set(id, published)\n models.push({\n id,\n name,\n contextWindow: contextLength,\n // The catalog publishes no output ceiling yet, but each endpoint refuses a\n // larger `max_tokens` per model (the Messages endpoint names its own in\n // the rejection), so the ceiling comes from the capability snapshot.\n maxTokens: Math.min(contextLength, modelOutputTokenLimit(apiBase, id)),\n ...(published !== undefined && published > 0 ? { publishedMaxTokens: published } : {}),\n supportedEndpoints: endpoints,\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, apiBase: string, restorePublished = true): Promise<CommandCodeModel[]> {\n const parsed: unknown = JSON.parse(await readFile(cachePath, 'utf-8'))\n // Earlier cache files did not identify their gateway. Even the default path\n // may have been written by a custom apiBase, so an unscoped file is unsafe.\n if (!isRecord(parsed) || parsed.version !== MODEL_CACHE_VERSION\n || parsed.apiBase !== apiBase || !Array.isArray(parsed.models)) {\n throw new Error(`Invalid model cache at ${cachePath}`)\n }\n if (restorePublished) publishedOutputLimits.set(apiBase, new Map())\n // Normalize rather than trust the file: a hand-edited or fixture cache may\n // omit `supported_endpoints`, and an absent list must degrade to the\n // `claude-*` prefix rule instead of routing Claude to the wrong transport.\n return parsed.models.map((entry) => {\n const model = isRecord(entry) ? entry : {}\n const endpoints = Array.isArray(model.supportedEndpoints)\n ? model.supportedEndpoints.filter((item): item is string => typeof item === 'string')\n : []\n // A published ceiling is the gateway's own, so it is restored — but\n // `maxTokens` is NOT taken from the file. It is a DERIVED value: the\n // snapshot, the fallback and the gateway's published figure can all move\n // between two runs, and a cache written before any of them moved would\n // otherwise pin the old answer for as long as the file survives. The\n // catalog cache exists to spare a network fetch, not to freeze a\n // conclusion (issue #71).\n const id = stringValue(model.id)\n const published = numberValue(model.publishedMaxTokens)\n if (restorePublished && id !== undefined && published !== undefined && published > 0) {\n outputLimitsFor(publishedOutputLimits, apiBase).set(id, published)\n }\n const contextWindow = numberValue(model.contextWindow)\n return {\n ...model,\n supportedEndpoints: endpoints,\n maxTokens: id === undefined || contextWindow === undefined\n ? numberValue(model.maxTokens) ?? DEFAULT_MAX_OUTPUT_TOKENS\n : Math.min(contextWindow, modelOutputTokenLimit(apiBase, id), published !== undefined && published > 0 ? published : Infinity),\n } as unknown as CommandCodeModel\n })\n}\n\nasync function writeModelsCache(\n cachePath: string,\n apiBase: string,\n models: CommandCodeModel[],\n mayCommit: () => boolean,\n): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true })\n // Separate refreshes can overlap while settings change; one refresh must\n // never rename or delete another refresh's temporary file.\n const tmp = `${cachePath}.${process.pid}.${randomUUID()}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, apiBase, models }, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600,\n })\n if (mayCommit()) 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 — as a `reasoning` block on\n// `/alpha/generate` (the official CLI's `toWireMessages` shape) and as\n// `reasoning_content` on `/provider/v1/chat/completions` — because DeepSeek's\n// thinking-mode contract requires the previous chain of thought to be passed\n// back whenever tool calls are in play (issue #34). Only tool calls with a\n// paired tool result are 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 (`MessageRoleMap.tool` is\n * the only role a tool result can arrive on). Pairing and emission MUST agree\n * on this same view, or a dropped result either drops its call too (making the\n * model forget completed work) or leaves an 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, and the harness log keeps the\n * 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: a turn's carriers are\n * emitted as a group after the whole tool group (issue #33), so position\n * cannot carry the association — and every `read_image` result renders the\n * same envelope text, so two parallel calls would produce two identical\n * notes. The id is the WIRE id, the one the model saw on the `tool-call` and\n * on the tool message just above, so an overlong cross-provider id is named\n * by the alias that replaced it. Count and pixel dimensions are appended\n * when the tool's own text does not already state them.\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 offload set is a DURABLE surface fact, not a local edit: the adapter\n// renders the surface's `offloaded` marks with `projectOffloadedImages`, and a\n// history that still exceeds the budget 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. The budget is accounted in the\n// encoded form, because it is the base64 the wire actually carries that has to\n// 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 count is the\n * ONE thing the harness needs: `dsh-compaction-image-offload` records it as an\n * `image/offload` event, marks that many oldest retained occurrences, and\n * 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, reason: 'budget' | 'cache' = 'budget'): LlmError {\n const options: LlmErrorOptions & { offloadImages: number } = { offloadImages: missing }\n return new LlmError(\n reason === 'cache'\n ? `commandcode cache-aware image history: ${missing} already-seen oldest image occurrence(s) must be offloaded before replay.`\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 cacheOffloadModel?: string,\n): GenerateOptions {\n const marked = policy.projectOffloadedImages(options.messages, (ref) => offloadedImageText(ref))\n const messages = marked === options.messages ? options.messages : [...marked]\n const budgetMissing = policy.requiredImageOffload(messages, coreBudget(budget), imageVersionBytes)\n const cacheMissing = cacheOffloadModel === undefined ? 0 : seenImageOffloadCount(messages, cacheOffloadModel)\n const missing = Math.max(budgetMissing, cacheMissing)\n if (missing > 0) throw imageOffloadRequired(missing, cacheMissing > budgetMissing ? 'cache' : 'budget')\n return messages === options.messages ? options : { ...options, messages }\n}\n\n/**\n * Count retained images already followed by an answer from this same model.\n * The current tool result's image has not yet been seen by the model and must\n * stay on the wire. The engine can only offload durable user/tool input nodes;\n * assistant output and request-only input have no selectable surface event.\n */\nfunction seenImageOffloadCount(messages: readonly RequestMessage[], model: string): number {\n let lastAnswer = -1\n for (let index = 0; index < messages.length; index++) {\n const message = messages[index]!\n if (message.role === 'assistant'\n && message.source.kind === 'model'\n && message.source.provider === 'commandcode'\n && message.source.model === model) lastAnswer = index\n }\n if (lastAnswer < 0) return 0\n let count = 0\n for (let index = 0; index < lastAnswer; index++) {\n const message = messages[index]!\n if ((message.role !== 'user' && message.role !== 'tool') || message.id === undefined) continue\n for (const block of message.content) {\n if (block.type === 'image') count++\n }\n }\n return count\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<RequestImageAttachment> {\n return attachments.readImageRequest(ref, requestImageTarget(ref))\n}\n\ntype ReadRequestImage = ((ref: ImageAttachmentRef) => Promise<RequestImageAttachment>) & {\n prepare?: (refs: readonly ImageAttachmentRef[]) => Promise<void>\n}\n\n/** 同一次生成及其协议切换共享图片读取,最多同时准备四张,避免内存峰值失控。 */\nfunction requestImages(attachments: AttachmentStore, signal: AbortSignal | undefined, timing: RequestTiming): ReadRequestImage {\n const cache = new Map<string, Promise<RequestImageAttachment>>()\n const read: ReadRequestImage = (ref) => {\n signal?.throwIfAborted()\n const key = JSON.stringify([ref.attachmentId, requestImageTarget(ref)])\n let pending = cache.get(key)\n if (!pending) {\n pending = readRequestImage(attachments, ref)\n cache.set(key, pending)\n }\n return pending\n }\n read.prepare = async (refs) => {\n if (refs.length === 0) return\n const finishImages = timing.phase('images')\n let cursor = 0\n try {\n const workers = Array.from({ length: Math.min(4, refs.length) }, async () => {\n while (cursor < refs.length) {\n signal?.throwIfAborted()\n await read(refs[cursor++]!)\n }\n })\n // 等所有已开始的读取结束再抛错,避免失败请求留下未处理拒绝或后台工作。\n const results = await Promise.allSettled(workers)\n const failure = results.find((result) => result.status === 'rejected')\n if (failure?.status === 'rejected') throw failure.reason\n } finally { finishImages() }\n }\n return read\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 (which\n * is what stops the meter counting an evicted image as context): a model that\n * 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 final `/alpha/generate` wire format.\n * The official CLI accepts a base64 source internally, then toWireMessages()\n * sends a data URL plus mimeType. Use the request version's media type because\n * readImageRequest() can transcode the stored image to JPEG or WebP.\n */\nasync function imageToCommandCode(\n ref: ImageAttachmentRef,\n readImage: ReadRequestImage,\n): Promise<{ type: 'image'; image: string; mimeType: string }> {\n const version = await readImage(ref)\n return {\n type: 'image',\n image: `data:${version.mediaType};base64,${Buffer.from(version.data).toString('base64')}`,\n mimeType: version.mediaType,\n }\n}\n\ninterface MessageCodec {\n encodeImage: (ref: ImageAttachmentRef, readImage: ReadRequestImage) => Promise<unknown>\n encodeUser: (parts: unknown[]) => unknown\n encodeAssistant: (\n message: Extract<RequestMessage, { role: 'assistant' }>,\n paired: ReadonlySet<string>,\n wireIds: ReadonlyMap<string, string>,\n ) => unknown | undefined\n encodeTool: (\n result: ToolResultView,\n media: ToolResultMedia,\n wireId: string,\n toolName: string,\n readImage: ReadRequestImage | undefined,\n ) => unknown | Promise<unknown>\n /**\n * True when the transport can carry images inside a tool result, so\n * `convertMessages` must not split them into a following user message.\n * Only the Messages surface can: its `tool_result.content` accepts image\n * blocks, while the CLI's `tool-result.output` is text-only and Chat\n * Completions forbids non-text `role: 'tool'` content (issue #30).\n */\n carriesToolResultMedia: boolean\n}\n\n/**\n * One emitted block's replay metadata, stored in the terminal chunk's\n * `replayState.blocks` and handed back on the next request through the\n * assistant message's `source.replayState`.\n *\n * The Messages endpoint rejects a replayed `thinking` block without its\n * `signature` (`thinking.signature: Field required`), and a thinking block\n * with empty text is accepted, so the signature is the part that must\n * survive the round trip.\n */\ninterface MessagesReplayBlock {\n type: 'text' | 'reasoning' | 'tool-call'\n signature?: string\n}\n\n/**\n * The signature recorded for the reasoning block at `position` of a\n * historical assistant message, or undefined when the message was produced\n * by another route or an older plugin version.\n */\nfunction messagesSignatureAt(\n message: Extract<RequestMessage, { role: 'assistant' }>,\n position: number,\n): string | undefined {\n const replay = message.source?.replayState\n if (!isRecord(replay) || !Array.isArray(replay.blocks)) return undefined\n const entry = replay.blocks[position]\n return isRecord(entry) ? stringValue(entry.signature) : undefined\n}\n\n/**\n * The common pairing and image-carrier ordering for both transports. Each\n * codec owns its wire shape: CLI content blocks and Chat Completions\n * reasoning/tool calls differ beyond the image envelope.\n */\nasync function convertMessages(\n messages: readonly RequestMessage[],\n readImage: ReadRequestImage | undefined,\n codec: MessageCodec,\n): Promise<unknown[]> {\n const out: unknown[] = []\n const { ids: paired, names: toolNames } = pairedToolCalls(messages)\n if (readImage?.prepare) {\n const refs: ImageAttachmentRef[] = []\n // 只预读投影后实际发送的图片;孤立工具结果和已卸载图片不触碰附件服务。\n for (const message of messages) {\n const result = toolResultOf(message)\n if (message.role === 'user' && !result) {\n for (const block of message.content) if (block.type === 'image') refs.push(block.attachment)\n } else if (result && paired.has(result.toolCallId)) refs.push(...toolResultMedia(result).images)\n }\n await readImage.prepare(refs)\n }\n const wireIds = wireToolCallIds(paired)\n // Consecutive tool results must precede user image carriers, including when\n // an assistant turn has several parallel calls.\n const pendingImages: unknown[] = []\n const flushPendingImages = () => {\n for (const message of pendingImages) out.push(message)\n pendingImages.length = 0\n }\n const encodeImage = (ref: ImageAttachmentRef): Promise<unknown> => {\n if (!readImage) {\n throw new LlmError('Image input requires the durable attachment service', 'UNSUPPORTED_CONTENT')\n }\n return codec.encodeImage(ref, readImage)\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') parts.push(await encodeImage(block.attachment))\n }\n if (parts.length > 0) out.push(codec.encodeUser(parts))\n continue\n }\n\n if (message.role === 'assistant') {\n flushPendingImages()\n const assistant = codec.encodeAssistant(message, paired, wireIds)\n if (assistant !== undefined) out.push(assistant)\n continue\n }\n\n if (!result || !paired.has(result.toolCallId)) continue\n const media = toolResultMedia(result)\n const wireId = wireIds.get(result.toolCallId) ?? result.toolCallId\n out.push(await codec.encodeTool(result, media, wireId, toolNames.get(result.toolCallId) || 'unknown', readImage))\n if (!codec.carriesToolResultMedia && media.images.length > 0) {\n const carried: unknown[] = [{ type: 'text', text: toolResultImageNote(media, wireId) }]\n for (const attachment of media.images) carried.push(await encodeImage(attachment))\n pendingImages.push(codec.encodeUser(carried))\n }\n }\n flushPendingImages()\n return out\n}\n\nconst ccMessageCodec: MessageCodec = {\n carriesToolResultMedia: false,\n encodeImage: imageToCommandCode,\n encodeUser: (parts) => ({ role: 'user', content: parts }),\n encodeAssistant: (message, paired, wireIds) => {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n else if (block.type === 'reasoning') 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 return parts.length > 0 ? { role: 'assistant', content: parts } : undefined\n },\n encodeTool: (result, media, wireId, toolName) => ({\n role: 'tool',\n content: [{\n type: 'tool-result',\n toolCallId: wireId,\n toolName,\n output: result.isError\n ? { type: 'error-text', value: toolResultTextForWire(media) }\n : { type: 'text', value: toolResultTextForWire(media) },\n }],\n }),\n}\n\nasync function messagesToCC(\n messages: readonly RequestMessage[],\n readImage?: ReadRequestImage,\n): Promise<unknown[]> {\n return convertMessages(messages, readImage, ccMessageCodec)\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: ReadRequestImage,\n): Promise<{ type: 'image_url'; image_url: { url: string } }> {\n const version = await readImage(ref)\n return {\n type: 'image_url',\n image_url: {\n url: `data:${version.mediaType};base64,${Buffer.from(version.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 */\nconst openAiMessageCodec: MessageCodec = {\n carriesToolResultMedia: false,\n encodeImage: imageToOpenAI,\n encodeUser: (parts) => {\n const hasImage = parts.some((part) => (part as { type?: string }).type === 'image_url')\n return !hasImage && parts.length === 1\n ? { role: 'user', content: (parts[0] as { text: string }).text }\n : { role: 'user', content: parts }\n },\n encodeAssistant: (message, paired, wireIds) => {\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: { name: block.name, arguments: block.arguments },\n }))\n if (text === '' && reasoning === '' && toolCalls.length === 0) return undefined\n const assistant: Record<string, unknown> = { role: 'assistant', content: text === '' ? null : text }\n if (reasoning !== '') assistant.reasoning_content = reasoning\n if (toolCalls.length > 0) assistant.tool_calls = toolCalls\n return assistant\n },\n encodeTool: (_result, media, wireId) => ({\n role: 'tool',\n tool_call_id: wireId,\n content: toolResultTextForWire(media),\n }),\n}\n\nasync function messagesToOpenAI(\n messages: readonly RequestMessage[],\n readImage?: ReadRequestImage,\n): Promise<unknown[]> {\n return convertMessages(messages, readImage, openAiMessageCodec)\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic Messages transport (`/provider/v1/messages`)\n// ---------------------------------------------------------------------------\n\n/**\n * Convert one image reference to the Messages wire shape. Unlike the other two\n * transports this one keeps the native media type rather than a data URL, and\n * it may be used INSIDE a tool result — `tool_result.content` accepts image\n * blocks, which is why this codec sets `carriesToolResultMedia`.\n */\nasync function imageToMessages(\n ref: ImageAttachmentRef,\n readImage: ReadRequestImage,\n): Promise<{ type: 'image'; source: { type: 'base64'; media_type: string; data: string } }> {\n const version = await readImage(ref)\n return {\n type: 'image',\n source: { type: 'base64', media_type: version.mediaType, data: Buffer.from(version.data).toString('base64') },\n }\n}\n\n/** A tool call's `arguments` is a raw JSON string in the harness, an object here. */\nfunction parseToolArguments(raw: string): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(raw)\n return isRecord(parsed) ? parsed : {}\n } catch {\n return {}\n }\n}\n\n/**\n * Convert harness messages to the Anthropic Messages request shape.\n *\n * Differences from the other two transports, all measured against the live\n * endpoint on 2026-09-29:\n *\n * - Content is always a block array; there is no string shorthand, so a\n * single-text user turn is still `{ role: 'user', content: [{type:'text'…}] }`.\n * - Tool results live in a `user` turn as `tool_result` blocks (not a\n * `role: 'tool'` message) and may carry images natively, so no image is\n * split into a separate user message here.\n * - A replayed `thinking` block is only valid WITH its `signature`: the\n * endpoint answers `thinking.signature: Field required` without it, and\n * `each thinking block must contain thinking` when the text is empty and\n * the signature is blank. A reasoning block with no recorded signature is\n * therefore dropped rather than sent — replaying it would fail the request,\n * while omitting it is accepted (verified 200 both ways).\n * - The conversation must end with a user turn; the endpoint refuses an\n * assistant prefill (`This model does not support assistant message\n * prefill`), which `convertMessages` already guarantees for a tool loop.\n */\nconst messagesMessageCodec: MessageCodec = {\n carriesToolResultMedia: true,\n encodeImage: imageToMessages,\n encodeUser: (parts) => ({ role: 'user', content: parts }),\n encodeAssistant: (message, paired, wireIds) => {\n const parts: unknown[] = []\n let position = 0\n for (const block of message.content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n position++\n continue\n }\n if (block.type === 'reasoning') {\n const signature = messagesSignatureAt(message, position)\n if (signature !== undefined) {\n parts.push({ type: 'thinking', thinking: block.text, signature })\n }\n position++\n continue\n }\n if (block.type === 'tool-call' && paired.has(block.id)) {\n parts.push({\n type: 'tool_use',\n id: wireIds.get(block.id) ?? block.id,\n name: block.name,\n input: parseToolArguments(block.arguments),\n })\n position++\n }\n }\n return parts.length > 0 ? { role: 'assistant', content: parts } : undefined\n },\n encodeTool: async (result, media, wireId, _toolName, readImage) => {\n const content: unknown[] = []\n // Only this transport can carry the bytes here, so the resolver must exist\n // whenever the session holds a tool-result image; `convertMessages` has\n // already refused a request that carries one without it.\n if (readImage) {\n for (const attachment of media.images) content.push(await imageToMessages(attachment, readImage))\n }\n content.push({ type: 'text', text: toolResultTextForWire(media) })\n const toolResult: Record<string, unknown> = { type: 'tool_result', tool_use_id: wireId, content }\n if (result.isError) toolResult.is_error = true\n return { role: 'user', content: [toolResult] }\n },\n}\n\nasync function messagesToMessages(\n messages: readonly RequestMessage[],\n readImage?: ReadRequestImage,\n): Promise<unknown[]> {\n return convertMessages(messages, readImage, messagesMessageCodec)\n}\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\n * 300s, the official CLI's own budget — see\n * {@link DEFAULT_REQUEST_TIMEOUT_MS}).\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 * Opt-in CLI cache mitigation: after this same model has answered with an\n * image in its history, ask dsh's durable image-offload surface to replace\n * that image before the next replay. This protects the growing text prefix\n * when Command Code's multimodal cache retreats to the first image, but the\n * model cannot inspect the old pixels again without a fresh tool/user image.\n */\n offloadSeenImagesForCache?: boolean\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 */\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 — so the pool moves on without remembering anything.\n *\n * The window/throttle split decides what the pool may CLAIM, never whether it\n * rotates (issue #54); the evidence that separates them is in\n * {@link classifyAccountRejection}.\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 /** 可选的数值耗时接收器;不接收提示词、凭据或错误正文。 */\n onRequestTiming?: RequestTimingSink\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. `rotation.resetAtMs` carries the provider's own\n * reset time when the rejection body published one, so the host can hold the\n * key out until then instead of waiting for a billing probe to learn the\n * 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/**\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, name the root cause instead of letting the degraded per-endpoint\n * view hide it behind a generic \"partial data\" note.\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 /**\n * True when the model publishes selectable effort levels, i.e. when thinking\n * is a choice this route can express. A model that neither offers levels nor\n * appears in `KNOWN_THINKING_MODELS` does not reason at all — the official\n * CLI's table marks it neither `reasoning_effort` nor `reasoning:!0` — so\n * the Messages transport must not open its thinking switch for it.\n */\n selectableEffort: boolean\n /** Folded system text (top-level system + system-role messages). */\n systemText: string\n /** Per-call request-image resolver; set only when the request carries images. */\n readImage: ReadRequestImage | undefined\n}\n\n/** UUID shape accepted by the official CLI's `toWireThreadId` helper. */\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n// UUIDv5's URL namespace. Keep this stable so a restored DSH session retains\n// the same provider thread ID across Host restarts.\nconst THREAD_ID_NAMESPACE = Buffer.from('6ba7b8119dad11d180b400c04fd430c8', 'hex')\n\n/**\n * Map the harness session identity to the CLI transport's UUID thread ID.\n *\n * The official CLI creates one thread ID per agent run and reuses it for the\n * tool-loop requests that follow. DSH stamps its loop-owned session ID onto\n * GenerateOptions, but ordinary IDs are `session-<UUID>`, not bare UUIDs.\n * UUIDv5 gives every non-UUID session ID a stable, wire-compatible mapping.\n * An already valid UUID remains unchanged; a one-shot call without a session\n * ID still gets a fresh thread ID.\n * This alone does not establish cache affinity (issue #64's A/B found none).\n */\nfunction cliThreadId(sessionId: string | undefined): string {\n if (!sessionId) return randomUUID()\n if (UUID_PATTERN.test(sessionId)) return sessionId\n const digest = createHash('sha1')\n .update(THREAD_ID_NAMESPACE)\n .update('dsh-commandcode-provider/session/')\n .update(sessionId)\n .digest()\n digest[6] = (digest[6]! & 0x0f) | 0x50\n digest[8] = (digest[8]! & 0x3f) | 0x80\n const hex = digest.toString('hex', 0, 16)\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\n/**\n * The CLI wire's explicit system-section form.\n *\n * The official CLI's current transport sends system text as an array and marks\n * stable sections with Anthropic-compatible ephemeral cache control. DSH's\n * adapter has one already-folded system string rather than the CLI's internal\n * section list, so preserve that text as one cacheable section. This does not\n * recover the CLI's separate static/dynamic boundaries or guarantee a hit.\n */\nfunction cliSystem(systemText: string): string | Record<string, unknown>[] {\n if (!systemText) return ''\n return [{\n type: 'text',\n text: systemText,\n cache_control: { type: 'ephemeral' },\n }]\n}\n\n/**\n * The Anthropic ephemeral cache marker, shared by every breakpoint this route\n * sets. One object is reused across positions because it is only ever\n * serialized, never mutated.\n *\n * No `ttl` is sent: the default 5-minute entry covers a continuously advancing\n * session, and `ttl: \"1h\"` is a separate billable tier whose read/write prices\n * are identical — it would only lengthen survival, not reduce cost.\n */\nconst EPHEMERAL_CACHE_CONTROL = { type: 'ephemeral' }\n\n/**\n * Content-block types that may carry the rolling breakpoint. Matches what the\n * official Command Code provider for pi marks through\n * `@earendil-works/pi-ai`'s `anthropic-messages` transport (its own list also\n * holds pi-internal `tool_addition` / `tool_removal`, which this route never\n * emits). Assistant-side blocks are deliberately excluded: a breakpoint on a\n * `thinking` or `tool_use` block caches a prefix the next turn invalidates.\n */\nconst CACHEABLE_BLOCK_TYPES: ReadonlySet<string> = new Set(['text', 'image', 'tool_result'])\n\n/**\n * Mark the last user turn as the rolling cache breakpoint.\n *\n * Anthropic caching is explicit — a prefix is stored only when a\n * `cache_control` marker names it — so an unmarked route re-prefills the whole\n * replayed history at the full input price on every turn. Measured cost of that\n * omission on a 10-turn session: $0.5648, all of it at the undiscounted\n * $2/M input rate, against $0.1869 with the three breakpoints this route sets.\n *\n * The final user message is the rolling boundary: DSH resends the whole\n * history each turn, so a marker here grows with the conversation, whereas a\n * fixed `system`-only marker would leave every later turn's history\n * uncached. {@link messagesMessageCodec} renders both user input and tool\n * results as `role: 'user'`, so this covers a tool loop's trailing turn too.\n */\nfunction markLastUserCacheControl(messages: unknown[]): void {\n const last = messages[messages.length - 1]\n if (!isRecord(last) || last.role !== 'user' || !Array.isArray(last.content)) return\n const lastBlock = last.content[last.content.length - 1]\n if (isRecord(lastBlock) && typeof lastBlock.type === 'string'\n && CACHEABLE_BLOCK_TYPES.has(lastBlock.type)) {\n lastBlock.cache_control = EPHEMERAL_CACHE_CONTROL\n }\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 // The official CLI's `toWirePermissionMode()` normalizes an absent/default\n // permission mode to \"standard\" before it reaches the wire (confirmed by a\n // live-service probe: both \"standard\" and \"default\" are accepted enum\n // members, and the CLI's own internal default is \"default\", not\n // \"standard\" — the normalization step is what turns it into this). Sent\n // for request-shape parity with the real client; not a cache fix (see\n // docs/issue-64-cache-review.md's \"root-cause boundary\" section, which\n // already tested this exact value on this transport and excluded it as\n // the cause).\n permissionMode: 'standard',\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: cliSystem(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: cliThreadId(options.sessionId),\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 * Build the Anthropic Messages request body for one call.\n *\n * Measured deviations from DeepSeek's own Messages API (the shape\n * `dsh-llm-deepseek` implements), all confirmed on 2026-09-29:\n *\n * - `thinking` accepts ONLY `{ type: 'adaptive' }` here. `enabled` and\n * `disabled` are refused with `\"thinking.type.enabled\" is not supported for\n * this model. Use \"thinking.type.adaptive\" and \"output_config.effort\" to\n * control thinking behavior.`, and a `between_tools` value fails validation\n * outright. The model reasons on its own; this switch only admits it.\n * - Reasoning strength travels in `output_config.effort`, whose accepted\n * values are `low | medium | high | xhigh | max` — there is no `none`, and\n * `xhigh` is absent from DeepSeek's own type.\n * - `stop_sequences` is a real field here, but this adapter still rejects\n * `GenerateOptions.stop` in `stream()` because Command Code documents no\n * equivalent for the other two transports.\n * - **`temperature` is never sent.** Adaptive thinking constrains it to 1:\n * `` `temperature` may only be set to 1 when thinking is enabled or in\n * adaptive mode `` (measured 2026-09-29 — every request carrying the other\n * transports' 0.3 default was refused with HTTP 400). Omitting the field\n * is the only way to honour both the thinking switch and a caller that\n * asked for a temperature, so Claude loses sampling control on this route\n * because the endpoint, not this adapter, removed it.\n * - `system` travels as a one-block ARRAY carrying `cache_control`, not as the\n * bare string the other two transports send. Anthropic's caching is opt-in\n * per block, and this route is the only Claude path, so the marker is what\n * makes a session's replayed history bill at the cache-read rate instead of\n * the full input rate. See {@link EPHEMERAL_CACHE_CONTROL}.\n */\nasync function buildMessagesBody(\n options: GenerateOptions,\n facts: Pick<GenerateCallFacts, 'maxTokens' | 'reasoningEffort' | 'selectableEffort' | 'systemText' | 'readImage'>,\n): Promise<Record<string, unknown>> {\n const body: Record<string, unknown> = {\n model: options.model,\n max_tokens: facts.maxTokens,\n stream: true,\n messages: await messagesToMessages(options.messages, facts.readImage),\n }\n // The thinking switch and the effort that drives it are one decision: the\n // endpoint's own wording is \"Use `thinking.type.adaptive` AND\n // `output_config.effort` to control thinking behavior\". Opening the switch\n // for a model that publishes neither (`claude-haiku-4-5-20251001` — no effort\n // levels, absent from `KNOWN_THINKING_MODELS`, so the official CLI does not\n // mark it `reasoning:!0` either) would ask a non-reasoning model to reason.\n // The field is accepted either way, so this is a correctness call rather than\n // a failure avoidance one.\n if (facts.selectableEffort) body.thinking = { type: 'adaptive' }\n if (facts.systemText) {\n body.system = [{\n type: 'text',\n text: facts.systemText,\n cache_control: EPHEMERAL_CACHE_CONTROL,\n }]\n }\n if (facts.reasoningEffort) body.output_config = { effort: facts.reasoningEffort }\n const tools: Record<string, unknown>[] = (options.tools ?? []).map((tool) => ({\n name: tool.name,\n description: tool.description,\n // The gateway rejects a tool whose root schema is not `type: 'object'`\n // (`tools.0.custom.input_schema.type: Field required`), so the same\n // normalization the other transports use applies here.\n input_schema: toolParametersSchema(tool.parameters),\n }))\n if (tools.length > 0) {\n // The last declaration is the one that closes the cached tools prefix;\n // marking an earlier tool would let the suffix re-prefill every turn.\n tools[tools.length - 1]!.cache_control = EPHEMERAL_CACHE_CONTROL\n body.tools = tools\n }\n markLastUserCacheControl(body.messages as unknown[])\n return body\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 */\n/** The generate endpoint one protocol posts to. */\nfunction protocolEndpoint(protocol: CommandCodeProtocol, apiBase: string): string {\n if (protocol === 'cli') return `${apiBase}/alpha/generate`\n return protocol === 'messages'\n ? `${apiBase}/provider/v1/messages`\n : `${apiBase}/provider/v1/chat/completions`\n}\n\ninterface GenerateConnectDeps {\n options: GenerateOptions\n connection: CommandCodeConnectionOptions\n fetchImpl: typeof fetch\n timing: RequestTiming\n /** Observe headers even on rejected attempts before rotation/fallback. */\n onResponse: (response: Response) => void\n}\n\n/** 错误正文只供诊断与分类使用,不能让坏网关占满内存或无限拖住重试。 */\nasync function readGenerateErrorBody(response: Response, abort: AbortController, timeoutMs: number): Promise<string> {\n if (response.body === null) return ''\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let text = ''\n let bytes = 0\n const limit = 64 * 1024\n let removeAbort: () => void = () => undefined\n const stopped = new Promise<undefined>((resolve) => {\n if (abort.signal.aborted) resolve(undefined)\n else abort.signal.addEventListener('abort', onAbort, { once: true })\n function onAbort() { resolve(undefined) }\n removeAbort = () => abort.signal.removeEventListener('abort', onAbort)\n })\n // 独立约束错误正文;正常长时间生成仍只受流空闲期限控制。\n const timer = setTimeout(() => abort.abort(), Math.min(timeoutMs, 30_000))\n try {\n while (bytes < limit) {\n const read = await Promise.race([reader.read(), stopped])\n if (read === undefined || read.done) break\n const remaining = limit - bytes\n text += decoder.decode(read.value.subarray(0, remaining), { stream: true })\n bytes += read.value.byteLength\n }\n return text + decoder.decode()\n } catch {\n // 已收到的片段仍可能带有账户拒绝或限流证据,读取失败不丢掉它。\n return text + decoder.decode()\n } finally {\n clearTimeout(timer)\n removeAbort()\n // cancel 的底层实现也可能挂起,不能把资源清理变成另一处无限等待。\n void reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\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). Returns\n * the live response plus its cleanup, or the rejection facts for the rotation\n * loop to classify. Every failure path cleans up before returning or throwing;\n * on success the caller-abort listener outlives the connect phase (it aborts a\n * stalled body read), so the streaming tail calls cleanup.\n */\nasync function connectGenerate(\n deps: GenerateConnectDeps,\n key: string,\n protocol: CommandCodeProtocol,\n serializedBody: string,\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 = protocolEndpoint(protocol, connection.apiBase)\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 sharedHeaders = {\n 'Content-Type': 'application/json',\n ...IDENTITY_ENCODING_HEADER,\n Authorization: `Bearer ${key}`,\n ...(zdr ? { 'x-cmd-zdr': '1' } : {}),\n ...attributionHeaders(),\n }\n const headers = protocol === 'cli'\n ? {\n ...sharedHeaders,\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': 'false',\n 'x-co-flag': 'false',\n }\n : {\n ...sharedHeaders,\n Accept: 'text/event-stream',\n // Deliberately no x-command-code-version / x-cli-environment on either\n // documented Provider API surface: those identify the CLI transport,\n // not a public API client. ZDR is the one business header both share.\n }\n // 请求体由调用层缓存,同协议换账号只替换请求头,不重复序列化历史。\n const finishHeaders = deps.timing.attempt(protocol, Buffer.byteLength(serializedBody))\n try {\n response = await fetchImpl(endpoint, {\n method: 'POST',\n headers,\n body: serializedBody,\n signal: connectAbort.signal,\n })\n finishHeaders(response.status)\n clearTimeout(connectTimer)\n } catch (error: unknown) {\n finishHeaders()\n cleanup()\n if (options.signal?.aborted) {\n throw error\n }\n if (connectTimedOut || (error instanceof DOMException && error.name === 'TimeoutError')) {\n throw headersTimeoutError({\n protocol, endpoint, body: serializedBody,\n timeoutMs: connection.requestTimeoutMs, 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 bilingual(\n 'TRANSPORT',\n `Command Code API request to ${endpoint} failed: ${errorChain(error)}`,\n 'Command Code API 请求连接失败——通常是网络或代理问题,请检查网络或代理设置后重试',\n { cause: error },\n )\n }\n\n deps.onResponse(response)\n if (!response.ok) {\n let errText: string\n try {\n errText = await readGenerateErrorBody(response, connectAbort, connection.requestTimeoutMs)\n if (options.signal?.aborted) throw options.signal.reason ?? new DOMException('已取消请求', 'AbortError')\n } finally {\n cleanup()\n }\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 /** Messages-transport block state, keyed by the wire `index`. */\n messagesBlocks: Map<number, MessagesBlockState>\n /** Messages 的用量分散在开始与增量事件中,缺失字段保留此前累计值。 */\n messagesUsage: TokenUsage | undefined\n /**\n * Per-emitted-block replay metadata, indexed by the harness chunk index.\n * Only the Messages transport records entries (the thinking `signature`);\n * the other two leave it empty, which is legal — an adapter whose metadata\n * is independent of block structure omits the field entirely.\n */\n replayBlocks: MessagesReplayBlock[]\n}\n\n/** One Messages content block while it streams. */\ninterface MessagesBlockState {\n type: 'text' | 'reasoning' | 'tool-call'\n text: string\n signature: string\n json: string\n id: string\n name: string\n /** The harness chunk index this block was opened under, or -1 before open. */\n chunkIndex: number\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 messagesBlocks: new Map(),\n messagesUsage: undefined,\n replayBlocks: [],\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 catalogState: {\n source: string\n expiresAt: number\n inflight?: Promise<CommandCodeModel[]>\n disk?: Promise<CommandCodeModel[]>\n } | undefined\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 gateway and account: a custom gateway can give the\n // same key a different tier. The key remains process-local and is 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 gateway and 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, { protocol: 'cli' | 'openai'; at: number }>()\n\n /** Namespace account-derived facts by gateway without exposing the key. */\n private accountCacheKey(apiBase: string, apiKey: string): string {\n return JSON.stringify([apiBase, apiKey])\n }\n /**\n * Consecutive header timeouts for the last request shape, counted ACROSS\n * `stream()` calls: dsh-llm-retry re-invokes this same instance, so this is\n * the only place a streak can live. Keyed by `sessionId` (not by `agent`:\n * `GenerateOptions` carries no agent reference, only `sessionId`) so\n * concurrent sessions on this one shared adapter instance cannot clear or\n * inflate each other's count. A call with no `sessionId` (a one-shot,\n * session-less caller) falls back to {@link GLOBAL_HEADER_TIMEOUT_KEY},\n * matching the old single-slot behavior for exactly that case. Bounded by\n * {@link MAX_HEADER_TIMEOUT_STREAK_ENTRIES} with FIFO eviction (`Map`\n * preserves insertion order) since the key space is per-session rather than\n * per-account/model, so it is not naturally small like `protocolCache`.\n */\n private readonly headerTimeoutStreaks = new Map<string, { fingerprint: string; count: number }>()\n private static readonly MAX_HEADER_TIMEOUT_STREAK_ENTRIES = 200\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 * Grade one failed attempt: a headers timeout that repeats on an unchanged\n * payload eventually leaves the retryable whitelist.\n *\n * `providerRetryPolicy()` cannot express this itself — dsh-llm's\n * `NormalRetryPolicyConfig` carries one `maxRetries` for every listed code.\n * Escalating here stops repeated identical header timeouts with a specific\n * diagnosis; the agent listener separately caps ordinary transient errors.\n *\n * @returns the error to surface: unchanged for any other failure, the\n * original timeout below the threshold, and a terminal one at it.\n */\n private gradeHeaderTimeout(\n error: unknown,\n protocol: CommandCodeProtocol,\n body: Record<string, unknown>,\n timeoutMs: number,\n sessionId: string | undefined,\n ): unknown {\n const timedOut = error instanceof LlmError && error.code === 'TIMEOUT'\n if (!timedOut) return error\n const key = sessionId ?? GLOBAL_HEADER_TIMEOUT_KEY\n const fingerprint = `${protocol}:${fingerprintValue(body).sha256}`\n const previous = this.headerTimeoutStreaks.get(key)\n const count = previous?.fingerprint === fingerprint ? previous.count + 1 : 1\n if (previous === undefined) {\n // FIFO eviction: the key space is per-session (unlike protocolCache's\n // per-account/model bound), so an unbounded Map would leak one entry\n // per abandoned session that timed out below the threshold and never\n // got a success or an escalation to clear it.\n if (this.headerTimeoutStreaks.size >= CommandCodeAdapter.MAX_HEADER_TIMEOUT_STREAK_ENTRIES) {\n const oldest = this.headerTimeoutStreaks.keys().next().value\n if (oldest !== undefined) this.headerTimeoutStreaks.delete(oldest)\n }\n } else {\n // Re-inserting moves the key to the end, so FIFO eviction above evicts\n // truly idle sessions first rather than one mid-streak.\n this.headerTimeoutStreaks.delete(key)\n }\n this.headerTimeoutStreaks.set(key, { fingerprint, count })\n if (count < MAX_CONSECUTIVE_HEADER_TIMEOUTS) return error\n // Reset so a later attempt starts a fresh streak instead of failing at once.\n this.headerTimeoutStreaks.delete(key)\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\n `Command Code API stopped retrying: the gateway returned no response headers on ${count} consecutive attempts at the same request, each after the full ${timeoutMs}ms budget, so this is not a network blip — it is provider queueing, a Go-plan capacity limit, or a network/proxy path problem. Resending the identical payload again is unlikely to help; wait for the provider to recover, or switch model or account.`,\n `Command Code API 已停止重试:同一请求连续 ${count} 次在 ${timeoutMs} 毫秒内都没有收到任何响应头,这不是网络抖动,而是服务商排队、Go 套餐容量限制或网络/代理链路问题。继续原样重发同一个请求通常无济于事——可以等服务商恢复,或换模型/换账号。`,\n )\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 * The official executor owns backoff and provider reset waits. Its high\n * route-wide cap lets a confirmed `RATE_LIMIT` window recover in-session;\n * our request-error listener limits `SERVER`/`TIMEOUT`/`EMPTY_RESPONSE`/\n * `THROTTLED` to three retries and `TRANSPORT` to its separate budget.\n * Waits double from 500 ms and cap at 15 minutes (±10% jitter). Permanent failures\n * (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`, plan\n * rejections) are absent from the whitelist and surface immediately instead\n * of looping. Waits the pool/adapter attach as `providerRetryAfterMs` are\n * honored verbatim at or below the 15-minute cap and never attached above it\n * (in normal mode a longer attached wait makes the executor abandon the\n * 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', THROTTLED_CODE, '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. One price per occurrence, in order, is a hard\n * 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 /** 地址或缓存文件变化时丢弃旧目录,防止旧网关的路由声明影响新请求。 */\n private currentCatalogState(connection: CommandCodeConnectionOptions = this.deps.options()) {\n const { apiBase, modelsCachePath } = connection\n const source = JSON.stringify([apiBase, modelsCachePath])\n if (this.catalogState?.source !== source) {\n this.catalog = []\n this.catalogState = { source, expiresAt: 0 }\n }\n return this.catalogState\n }\n\n /** 直接生成也使用本地可信目录,不额外联网;并发冷请求共用一次文件读取。 */\n private async catalogForGenerate(connection: CommandCodeConnectionOptions): Promise<CommandCodeModel[]> {\n const state = this.currentCatalogState(connection)\n if (this.catalog.length > 0 || state.expiresAt > 0) return this.catalog\n // 本地读取不能覆盖并发联网刷新刚取得的全局输出上限。\n state.disk ??= readModelsCache(connection.modelsCachePath, connection.apiBase, false).catch(() => [])\n const cached = await state.disk\n if (this.catalogState !== state) return cached\n if (this.catalog.length > 0 || state.expiresAt > 0) return this.catalog\n if (state.inflight === undefined) this.catalog = cached\n return cached\n }\n\n /** 共享一次刷新;调用者取消只结束自己的等待,不取消其他调用者的请求。 */\n private async loadCatalog(signal?: AbortSignal): Promise<CommandCodeModel[]> {\n signal?.throwIfAborted()\n const connection = this.deps.options()\n const state = this.currentCatalogState(connection)\n if (Date.now() < state.expiresAt) return this.catalog\n const { apiBase, modelsCachePath } = connection\n if (!state.inflight) {\n const fallback = this.catalog\n state.inflight = (async () => {\n let models: CommandCodeModel[]\n let ttl = MODEL_CATALOG_TTL_MS\n try {\n const { status, record } = await this.fetchJson(\n `${apiBase}/provider/v1/models`,\n { accept: 'application/json', ...IDENTITY_ENCODING_HEADER, ...attributionHeaders() },\n MODELS_TIMEOUT_MS,\n )\n if (status < 200 || status >= 300) throw new Error(`models endpoint returned ${status}`)\n models = parseCatalogResponse(record, apiBase)\n // 旧地址的并发刷新不得覆盖新地址的内存或磁盘目录。\n if (this.catalogState === state) {\n await writeModelsCache(modelsCachePath, apiBase, models, () => this.catalogState === state).catch(() => undefined)\n }\n } catch {\n ttl = MODEL_CATALOG_RETRY_MS\n models = await readModelsCache(modelsCachePath, apiBase).catch(() => fallback)\n }\n if (this.catalogState === state) {\n this.catalog = models\n state.expiresAt = Date.now() + ttl\n }\n return models\n })().finally(() => { delete state.inflight })\n }\n if (!signal) return state.inflight\n const inflight = state.inflight\n return new Promise((resolve, reject) => {\n const abort = () => reject(signal.reason)\n signal.addEventListener('abort', abort, { once: true })\n inflight.then(resolve, reject).finally(() => signal.removeEventListener('abort', abort))\n if (signal.aborted) abort()\n })\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, and it hid models the user's OTHER accounts\n // could run. The union is the honest question for a pool, and it only works\n // together with the entitlement rotation in the connect loop.\n const accesses = this.deps.options().filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess()\n // Visible-model allowlist, then the terminal settings page's per-model\n // boolean overrides (its schema seam can only give each model its own\n // flag, which cannot express \"this id is in the list\"). Both are defined\n // on {@link CommandCodeConnectionOptions}.\n const visible = this.deps.options().visibleModels\n const allow = Array.isArray(visible) ? visible.filter((id) => typeof id === 'string' && id !== '') : []\n const overrides = this.deps.options().modelVisibility\n return catalog\n .filter((model) => modelVisibleForAnyAccount(model.id, accesses))\n .filter((model) => modelIsVisible(model.id, allow, overrides))\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 /**\n * The per-model allowance bracket this account POOL falls into, or undefined\n * when there is nothing honest to show.\n *\n * The pricing page publishes per-model monthly allowances for Go, GOAT and\n * Pro. A pool whose highest plan is Provider,\n * Max or Ultra gets undefined rather than a neighbouring tier's figure. Taking\n * the HIGHEST tier matches the question the picker already answers for a pool\n * (see `modelVisibleForAnyAccount`): what the user can reach, not what the one\n * account serving this request happens to be. The fail-open shape is the same\n * too — an unreachable billing endpoint yields undefined, which hides the\n * allowance instead of inventing one.\n */\n async allowanceTier(): Promise<'go' | 'goat' | 'pro' | undefined> {\n const accesses = await this.loadPoolBillingAccess()\n if (accesses === undefined) return undefined\n let highest: number | undefined\n for (const access of accesses) {\n const weight = access?.tierWeight\n if (weight === undefined) continue\n if (highest === undefined || weight > highest) highest = weight\n }\n // `allowanceTierForWeight` owns the weight → bracket mapping (and the\n // decision that Provider, Max and Ultra have no bracket at all), so this\n // method only has to answer \"what is the highest plan in the pool?\".\n return allowanceTierForWeight(highest)\n }\n\n override async resolveModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<LlmResolvedModelInfo> {\n this.currentCatalogState()\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 // Every account endpoint runs the chat path's own `assertUsableApiKey`\n // 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 JSON GET and return its HTTP status with a parsed record. The\n * catalog, billing probe, and usage report each apply their own failure\n * policy. Non-2xx and invalid JSON bodies come back without a record; only\n * a fetch failure propagates to the caller.\n *\n * `timeoutMs` is the caller's budget, unless it provides its own signal.\n * The usage report passes the connection's request budget rather than the\n * catalog/picker's shorter default.\n */\n private async fetchJson(\n url: string,\n headers: Record<string, string>,\n timeoutMs: number = MODELS_TIMEOUT_MS,\n signal?: AbortSignal,\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: 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 private async loadPoolBillingAccess(): Promise<readonly (CommandCodeBillingAccess | undefined)[] | undefined> {\n const keys = await this.poolAccountKeys()\n if (keys.length === 0) return undefined\n const apiBase = this.deps.options().apiBase\n return Promise.all(keys.map((key) => this.loadBillingAccessForKey(apiBase, 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(apiBase: string, apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\n const cacheKey = this.accountCacheKey(apiBase, apiKey)\n const cached = this.billingAccess.get(cacheKey)\n if (cached !== undefined && Date.now() - cached.at < BILLING_ACCESS_TTL_MS) return cached.value\n const existing = this.billingAccessInflight.get(cacheKey)\n if (existing !== undefined) return existing\n const inflight = this.fetchBillingAccess(apiBase, apiKey)\n .then((value) => {\n this.billingAccess.set(cacheKey, { value, at: Date.now() })\n return value\n })\n .finally(() => {\n this.billingAccessInflight.delete(cacheKey)\n })\n this.billingAccessInflight.set(cacheKey, 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(apiBase: string, apiKey: string): Promise<CommandCodeBillingAccess | undefined> {\n try {\n const headers = await this.accountHeaders(apiKey)\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.fetchJson(`${apiBase}${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(apiBase: string, apiKey: string): number | undefined {\n const hit = this.billingAccess.get(this.accountCacheKey(apiBase, 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 cachedProtocol(apiBase: string, apiKey: string): 'cli' | 'openai' | undefined {\n const hit = this.protocolCache.get(this.accountCacheKey(apiBase, apiKey))\n if (hit === undefined || Date.now() - hit.at >= PROTOCOL_CACHE_TTL_MS) return undefined\n return hit.protocol\n }\n\n private rememberProtocol(apiBase: string, apiKey: string, protocol: 'cli' | 'openai'): void {\n this.protocolCache.set(this.accountCacheKey(apiBase, apiKey), { protocol, at: Date.now() })\n }\n\n /**\n * True when the catalog routes `model` to `/provider/v1/messages`.\n *\n * The catalog's own `supported_endpoints` is authoritative (it is what\n * upstream publishes per model); `requiresMessagesEndpoint()` — the\n * `claude-*` prefix rule — is the fallback for a catalog entry that carries\n * no route list, which is the shape every pre-1.55 cache file has.\n */\n private routesToMessages(model: string): boolean {\n const entry = this.catalog.find((candidate) => candidate.id === model)\n if (entry !== undefined && entry.supportedEndpoints.length > 0) {\n return entry.supportedEndpoints.includes('/messages')\n }\n return requiresMessagesEndpoint(model)\n }\n\n /**\n * Choose the initial protocol for one request.\n *\n * Models the Provider API serves only through `/provider/v1/messages` (the\n * Claude family) take the Messages transport on any tier and even under a\n * forced `'openai'` preference: that option is documented as \"prefer the\n * Provider API, still fall back\", and the 400 these models answer with on\n * Chat Completions (`Model \"<id>\" must be called via /provider/v1/messages`)\n * is a hard refusal, not a preference to honour.\n *\n * That decision is deliberately NOT written to `protocolCache`, which is\n * keyed by gateway and API key: it depends on the model, not just the account, so\n * remembering it would pin the whole ACCOUNT to one transport and drag\n * every other model along (issue #46).\n *\n * Otherwise a fresh protocol cache entry wins, then a cached (not\n * network-fetched) billing tier of Go — the one plan without Provider API\n * access. Unknown accounts default to Chat Completions and fall back to the\n * CLI transport only after an `upgrade_required` rejection.\n */\n private resolveProtocol(apiBase: string, apiKey: string, model: string): CommandCodeProtocol {\n const forced = this.deps.options().protocol\n if (forced === 'cli') return forced\n if (this.routesToMessages(model)) return 'messages'\n if (forced === 'openai') return forced\n const cached = this.cachedProtocol(apiBase, apiKey)\n if (cached !== undefined) return cached\n if (this.cachedBillingTierWeight(apiBase, apiKey) === GO_TIER_WEIGHT) {\n this.rememberProtocol(apiBase, apiKey, 'cli')\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: a\n * 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 I/O,\n * for every endpoint at once, so this path runs `assertUsableApiKey` too and\n * answers `blocked: 'invalid-key'`; and the four endpoints get the SAME\n * per-request budget as a chat call (`connection.requestTimeoutMs`, default\n * 60 s), not the catalog's 10 s probe budget, because on a slow link a 10 s\n * cap made every account query time out while chat kept working.\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.fetchJson(\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 (issue #51's follow-up: \"切到一个不可用账号\").\n * `exceeded` is therefore true when ANY published window is exceeded, and\n * `resetAt` is the LATEST reset among the exceeded ones — the binding\n * constraint, because a clear five-hour window buys nothing while the weekly\n * 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 credit balances are deliberately NOT part of this answer: they\n * carry no reset 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 { record: parsed } = await this.fetchJson(\n `${connection.apiBase}/alpha/billing/credits`,\n await this.accountHeaders(apiKey),\n )\n if (parsed === undefined) 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 const timing = openRequestTiming(options.model, this.deps.onRequestTiming)\n let outcome: 'finished' | 'error' | 'aborted' | 'cancelled' = 'cancelled'\n let errorCode: string | undefined\n try {\n for await (const chunk of this.streamRequest(options, timing)) {\n if (chunk.type === 'text-delta' || chunk.type === 'reasoning-delta' || chunk.type === 'tool-call-delta') {\n timing.first('firstContentMs')\n }\n if (chunk.type === 'finish') outcome = 'finished'\n yield chunk\n }\n } catch (error) {\n outcome = options.signal?.aborted ? 'aborted' : 'error'\n errorCode = error instanceof LlmError ? error.code : 'unknown'\n throw error\n } finally {\n await timing.close(outcome, errorCode)\n }\n }\n\n /**\n * One turn, with at most one output-ceiling downshift.\n *\n * The ceiling a model accepts is not published anywhere the request can be\n * built from (see `modelOutputTokenLimit`), and the endpoint states it only\n * by refusing. That refusal is worth one retry rather than a failed turn: the\n * harness's own recovery for it — compact the context — cannot help, because\n * nothing about the context is wrong, and resending the identical request\n * would be refused identically (issue #71). Reading the stated ceiling off\n * the rejection turns one wasted turn into one, for good: it is recorded\n * process-wide, so the next request for this model is built correctly\n * without spending the round trip again.\n *\n * Only BEFORE the first chunk reaches the host. Once a delta has been\n * delivered the answer is already partly on screen, and a second request\n * would duplicate it — so from that point the error stands and says what is\n * actually wrong. One downshift per turn, and a second refusal surfaces.\n */\n private async *streamRequest(options: GenerateOptions, timing: RequestTiming): AsyncIterable<StreamChunk> {\n for (let attempt = 0; ; attempt++) {\n const connection = this.deps.options()\n // Set before the hand-off, not after: a consumer that tears down on the\n // chunk has already seen it.\n let delivered = false\n try {\n for await (const chunk of this.streamAttempt(options, timing, connection)) {\n delivered = true\n yield chunk\n }\n return\n } catch (error) {\n const ceiling = delivered ? undefined : outputCeilingRefusal(connection.apiBase, options.model, error)\n if (attempt > 0 || ceiling === undefined) throw error\n }\n }\n }\n\n private async *streamAttempt(\n options: GenerateOptions,\n timing: RequestTiming,\n connection: C,\n ): AsyncIterable<StreamChunk> {\n this.currentCatalogState(connection)\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 request-image 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: ReadRequestImage | 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 = requestImages(attachments, options.signal, timing)\n }\n\n // The model id reaches key resolution so hosts with model→account routing\n // rules can pick the account that covers this model.\n const finishCredentials = timing.phase('credentials')\n let apiKey: string\n try { apiKey = await this.deps.resolveApiKey(connection, options.model) } finally { finishCredentials() }\n // 内存未预热时使用同网关的版本化磁盘目录;缺失仍保持原来的直接\n // 生成路径,不引入模型接口请求或新的联网失败点。\n const catalog = await this.catalogForGenerate(connection)\n options.signal?.throwIfAborted()\n const modelEntry = catalog.find((m) => m.id === options.model)\n // A catalog that has not warmed yet must still respect the model's own\n // output ceiling: the Messages endpoint refuses a `max_tokens` above it by\n // name, and falling back to the global default here would fail every first\n // request of a fresh process for a Messages-route model.\n //\n // Both candidates are ceilings, so the smaller binds. A warm catalog row is\n // a context-derived estimate (see parseCatalogResponse), and a value the\n // endpoint has already named outranks any estimate — otherwise a learned\n // limit would be masked by a catalog that warmed from the same guess.\n const modelMax = Math.min(\n modelEntry?.maxTokens ?? Infinity,\n modelOutputTokenLimit(connection.apiBase, options.model),\n )\n const requestedMaxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n const maxTokens = requestedMaxTokens\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 // (`resolveProtocol()` routes Claude to Messages on Provider API access).\n let protocol: CommandCodeProtocol = this.resolveProtocol(connection.apiBase, apiKey, options.model)\n // Image budget (issue #37): the body is built from the PROJECTED history,\n // never the raw one. Rung 0 is the standing budget; a 413 below steps down\n // the ladder. The session surface owns the offload set, so this throws\n // `IMAGE_OFFLOAD_REQUIRED` when more images must go; the retry then\n // arrives with the surface already updated.\n let requestOptions = withSurfaceOffload(\n options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!,\n connection.offloadSeenImagesForCache === true && protocol === 'cli' ? options.model : undefined,\n )\n const buildBody = async (target: CommandCodeProtocol): Promise<Record<string, unknown>> => {\n const finishBody = timing.phase('body')\n try {\n const facts = {\n maxTokens: requestedMaxTokens,\n reasoningEffort,\n // Reuse the lookup `stream()` already did: a model with no effort\n // levels offers nothing for the thinking switch to control.\n selectableEffort: supported !== undefined && supported.length > 0,\n systemText,\n readImage,\n }\n const built = target === 'cli'\n ? await buildCliBody(requestOptions, connection, facts)\n : target === 'messages'\n ? await buildMessagesBody(requestOptions, facts)\n : await buildOpenAIBody(requestOptions, facts)\n if (target === 'cli') recordOrEmpty(built.params).max_tokens = maxTokens\n else built.max_tokens = maxTokens\n return built\n } finally { finishBody() }\n }\n let body: Record<string, unknown> = await buildBody(protocol)\n const serializedBodies = new WeakMap<Record<string, unknown>, string>()\n\n // The opt-in trace now starts before the first connect attempt so a cache\n // miss can be correlated with the exact request shape that produced it.\n // The record contains hashes and counts only; see requestFingerprint().\n const trace = openStreamTrace(`${options.provider}/${options.model}`)\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 let attemptNumber = 0\n let responseMetadata: ResponseMetadata = { protocol, headers: {} }\n const connectDeps: GenerateConnectDeps = {\n options, connection, fetchImpl: this.fetchImpl, timing,\n onResponse: (response) => {\n // Any answer from the gateway ends a header-timeout streak, whatever\n // its status: the silence being measured is over.\n this.headerTimeoutStreaks.delete(options.sessionId ?? GLOBAL_HEADER_TIMEOUT_KEY)\n responseMetadata = { protocol, headers: responseIdentifiers(response.headers) }\n trace.record('response', {\n protocol,\n endpoint: protocolEndpoint(protocol, connection.apiBase),\n status: response.status,\n attempt: attemptNumber,\n accountsTried: tried.size,\n maxTokens,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n headers: responseMetadata.headers,\n })\n },\n }\n let connected: { response: Response; cleanup: () => void } | undefined\n try {\n for (;;) {\n tried.add(apiKey)\n attemptNumber++\n responseMetadata = { protocol, headers: {} }\n if (trace.enabled) trace.record('request', {\n attempt: attemptNumber,\n sessionId: options.sessionId,\n ...requestFingerprint(protocol, body),\n })\n let serialized = serializedBodies.get(body)\n if (serialized === undefined) {\n const finishSerialization = timing.phase('serialization')\n // The replacer runs at the one boundary every transport and every\n // field crosses, so a lone surrogate anywhere in the body is removed\n // before it can reach the wire. Non-string values pass through the\n // identity path, and a string without surrogates is returned as-is.\n try {\n serialized = JSON.stringify(body, (_key, value: unknown) => sanitizeSurrogates(value))\n } finally { finishSerialization() }\n serializedBodies.set(body, serialized)\n }\n const attempt = await connectGenerate(connectDeps, apiKey, protocol, serialized)\n if ('response' in attempt) {\n connected = attempt\n break\n }\n const providerError = parseProviderError(attempt.errText)\n // The 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), retry the same key through /alpha/generate without burning\n // the double TTFT on every later request.\n //\n // The Messages surface is included, but its downgrade is NOT cached:\n // the cache is keyed by gateway and API key, and a Claude-only refusal says\n // nothing about the account's other models, so remembering it would\n // drag DeepSeek, GLM and Qwen off the Provider API for the whole TTL\n // (issue #46). A Go-plan account never reaches here in the first place\n // — its cached billing tier already routes it to the CLI transport.\n if (\n protocol !== 'cli'\n && isUpgradeRequiredError(attempt.status, attempt.errText, providerError)\n ) {\n const wasMessages = protocol === 'messages'\n protocol = 'cli'\n if (!wasMessages) this.rememberProtocol(connection.apiBase, apiKey, 'cli')\n requestOptions = withSurfaceOffload(\n options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!,\n connection.offloadSeenImagesForCache === true ? options.model : undefined,\n )\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, as a durable\n // surface mutation rather than a local edit, so the extra omissions\n // survive the retry. Zero missing means the images are already gone and\n // the body is simply too big: fall through to the 413 diagnosis instead\n // of asking for an offload that cannot happen, which is also what keeps\n // the branch 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, providerError)\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 // 降级只描述上一账号;新账号必须按自己的套餐/缓存重新选择通道。\n const nextProtocol = this.resolveProtocol(connection.apiBase, apiKey, options.model)\n if (nextProtocol !== protocol) {\n protocol = nextProtocol\n requestOptions = withSurfaceOffload(\n options, this.surfaceOffload, REQUEST_IMAGE_BUDGETS[0]!,\n connection.offloadSeenImagesForCache === true && protocol === 'cli' ? options.model : undefined,\n )\n body = await buildBody(protocol)\n }\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, and `PROVIDER_HTTP_ERROR` sits\n // outside dsh-llm-retry's whitelist — so without this the turn dies on\n // the spot even though the provider said exactly when the same request\n // 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 if (\n rejection !== undefined\n && (rejection.reason === 'rate-limit' || rejection.reason === 'throttled')\n ) {\n const reset = rejection.resetAtMs\n const wait = reset === undefined\n ? (attempt.retryAfterMs ?? 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 bilingual(\n window ? 'RATE_LIMIT' : THROTTLED_CODE,\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 { status: attempt.status, ...(wait > 0 && wait <= RETRY_MAX_DELAY_MS ? { providerRetryAfterMs: wait } : {}) },\n )\n }\n throw generateHttpError(attempt.status, attempt.errText, attempt.retryAfterMs, providerError)\n }\n } catch (error) {\n trace.record('connect-error', { message: boundTraceText(errorChain(error)), responseMetadata })\n trace.close()\n if (options.signal?.aborted) throw error\n throw failureWithRequestId(\n this.gradeHeaderTimeout(error, protocol, body, connection.requestTimeoutMs, options.sessionId),\n responseMetadata,\n )\n }\n if (connected === undefined) {\n // Unreachable: the loop only exits via `break` or `throw`. The guard\n // 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 trace.record('end', { outcome: 'empty', code: 'PROVIDER_PROTOCOL_ERROR' })\n trace.close()\n throw failureWithRequestId(new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR'), responseMetadata)\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 // The request fingerprint was recorded before connect; this is the\n // response half of the same opt-in trace. See ./stream-trace.ts for why\n // the raw response stream remains the artifact that separates a provider\n // cut from a parser miss.\n const streamStartedAt = Date.now()\n let chunkCount = 0\n let totalBytes = 0\n let lastChunkAt = streamStartedAt\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 can legitimately stay silent for minutes while\n // thinking, and the official CLI sets no idle cap at all. reader.cancel()\n // unblocks a pending read(), which the loop then turns into a TIMEOUT\n // 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 let protocolStopped = 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 captureResponseIdentifiers(responseMetadata, event)\n if (protocol === 'messages' && isRecord(event) && event.type === 'message_stop') protocolStopped = true\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 function* handleLine(line: string): Generator<StreamChunk> {\n if (protocol === 'openai' && line.trim().replace(/^data:\\s*/, '') === '[DONE]') {\n protocolStopped = true\n return\n }\n yield* handle(parseStreamEventLine(line))\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 bilingual(\n 'TRANSPORT',\n `Command Code API stream from ${connection.apiBase} failed while reading: ${errorChain(error)}`,\n 'Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\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 bilingual(\n 'TIMEOUT',\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 )\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* handleLine(buffer)\n }\n break\n }\n const text = decoder.decode(value, { stream: true })\n if (value.byteLength > 0) timing.first('firstByteMs')\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* handleLine(line)\n if (protocolStopped) break\n }\n // OpenAI 的 finish_reason 之后还可能有独立用量包;Messages 在\n // message_stop 才结束。CLI 的 finish 则本身就是协议终止事件。\n if (protocolStopped || (protocol === 'cli' && 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\n ? undefined\n : emptyCompletionError(asm.finishReason, maxTokens, usage)\n trace.record('end', {\n outcome: failure === undefined\n ? 'finished'\n : failure.code === 'OUTPUT_TOKEN_LIMIT'\n ? 'output-token-limit'\n : '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 responseMetadata,\n })\n endRecorded = true\n if (failure !== undefined) throw failure\n // One envelope for both halves: response-level correlation ids and,\n // on the Messages transport, the per-block thinking signature the next\n // request must replay. DSH discards the whole envelope when `blocks`\n // does not line up with the emitted block count, so the array is\n // indexed by the same chunk index that was allocated at block-start.\n const replayBlocks = asm.replayBlocks\n const carryReplay = hasResponseIdentifiers(responseMetadata) || replayBlocks.length > 0\n yield carryReplay\n ? {\n ...finish,\n replayState: {\n response: responseMetadata,\n ...(replayBlocks.length > 0 ? { blocks: replayBlocks } : {}),\n },\n }\n : 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 response\n // was closed mid-generation: the gateway, an intermediary proxy, or the\n // network. Synthesizing a clean `stop` is what turned a truncated answer\n // into a turn that just ended, with nothing saying why\n // (`dsh-llm-deepseek`'s `translate()` raises this same code for this\n // same condition).\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 responseMetadata,\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 bilingual('EMPTY_RESPONSE', 'Command Code returned an empty response', 'Command Code 返回了空响应,重试通常可恢复')\n }\n throw bilingual(\n 'STREAM_CLOSED',\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 )\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 responseMetadata,\n })\n }\n throw options.signal?.aborted ? error : failureWithRequestId(error, responseMetadata)\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 `providerRetryAfterMs` so\n * dsh-llm-retry can wait exactly that long instead of guessing at the backoff\n * cadence — capped at RETRY_MAX_DELAY_MS, because in normal mode a longer\n * attached wait makes the executor abandon the retry outright.\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`, because that failure has a recovery the harness\n * performs and a generic provider error does not. Every message built here is\n * bilingual — the harness renders it verbatim in its retry chrome.\n */\ninterface ParsedProviderError {\n root?: Record<string, unknown>\n nested?: Record<string, unknown> | undefined\n code?: string | undefined\n type?: string | undefined\n /** The sentence to SHOW: one nesting level peeled when the body double-encoded it. */\n message?: string | undefined\n /**\n * The message exactly as the body carried it. Pattern matching must read\n * this, not {@link message}: the double-encoded form embeds a whole second\n * document whose `type` (`provider_error`) is part of how a gateway\n * distinguishes an over-reserved request from an ordinary one, and peeling\n * it before the test drops that evidence.\n */\n rawMessage?: string | undefined\n rateLimit?: Record<string, unknown> | undefined\n}\n\n/**\n * Unwrap one level of a double-encoded provider message.\n *\n * The Messages endpoint sometimes reports a rejection with `error.message`\n * holding a whole JSON document rather than the sentence\n * (`{\"type\":\"error\",\"error\":{\"type\":\"invalid_request_error\",\"message\":\"{\\\"type\\\":\n * \\\"error\\\",…}\"},\"request_id\":\"req_…\"}`, measured 2026-09-29). Showing that blob\n * to the user hides the actual refusal, so one nesting level is peeled; the\n * outer text is returned unchanged when it is not JSON or carries no message.\n */\nfunction unwrapProviderMessage(raw: string | undefined): string | undefined {\n if (raw === undefined) return undefined\n const trimmed = raw.trim()\n if (!trimmed.startsWith('{')) return raw\n try {\n const inner: unknown = JSON.parse(trimmed)\n if (!isRecord(inner)) return raw\n const nested = isRecord(inner.error) ? inner.error : undefined\n return stringValue((nested ?? inner).message) ?? raw\n } catch {\n return raw\n }\n}\n\n/** Parse a rejected body once, retaining the nested/root distinction. */\nfunction parseProviderError(errText: string): ParsedProviderError {\n try {\n const parsed: unknown = JSON.parse(errText)\n if (!isRecord(parsed)) return { message: errText }\n const nested = isRecord(parsed.error) ? parsed.error : undefined\n const body = nested ?? parsed\n const rawMessage = stringValue(body.message)\n return {\n root: parsed,\n nested,\n code: stringValue(body.code),\n type: stringValue(body.type),\n rawMessage,\n // The body itself is the floor, never `undefined`: the Messages endpoint\n // answers some rejections with bare prose (`Invalid input: expected\n // number, received undefined at max_tokens`, `Too small: expected array to\n // have >=1 items at messages`), and dropping those lost the only sentence\n // the user could act on.\n message: unwrapProviderMessage(rawMessage) ?? errText,\n rateLimit: isRecord(body.rateLimit) ? body.rateLimit : undefined,\n }\n } catch {\n return { message: errText }\n }\n}\n\nfunction generateHttpError(\n status: number,\n errText: string,\n retryAfterMs?: number,\n parsed: ParsedProviderError = parseProviderError(errText),\n): LlmError {\n // Historically this diagnosis reads only a nested `error` envelope; root\n // fields still feed account rotation and the Go-plan fallback below.\n const providerCode = parsed.nested === undefined ? undefined : parsed.code\n // The RAW message joins the detail: pattern tests below need every field the\n // body carried, including the parts `unwrapProviderMessage` peels off.\n const providerDetail = parsed.nested === undefined ? '' : [parsed.code, parsed.type, parsed.rawMessage ?? parsed.message]\n .filter((part): part is string => part !== undefined && part !== '')\n .join(' ')\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 const overflowDetail = providerDetail !== '' ? providerDetail : errText.slice(0, 500)\n // A request-side OUTPUT cap is not a context overflow, but it reads like one:\n // the endpoint's own rejection is `max_tokens: 200000 > 128000, which is the\n // maximum allowed number of output tokens for <model>` (measured 2026-09-29),\n // and `max_tokens` is one of the overflow patterns. Letting it through would\n // compact a session that is not oversized — at full price, on a long context —\n // and the reduced request would be refused identically. Checked first.\n if (status < 500 && OUTPUT_LIMIT_REJECTION.test(overflowDetail)) {\n // Quote what the endpoint said: \"200000 against a 128000 ceiling\" and a bare\n // validation error are different problems, and naming neither leaves the\n // user guessing which setting to change.\n const stated = /max_tokens:\\s*\\d+\\s*>\\s*\\d+/.exec(overflowDetail)?.[0]\n ?? (parsed.message !== undefined && parsed.message.length <= 200 ? parsed.message : undefined)\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\n `Command Code API error ${status}: this request's max_tokens is not valid for this model`\n + (stated ? ` (${stated})` : '')\n + ' — the session is not oversized, so compacting it will not help; lower \"Max output tokens\"'\n + ' or pick a model with a larger output ceiling',\n `Command Code API 返回 ${status}:本次请求的 max_tokens 对该模型不合法`\n + (stated ? `(${stated})` : '')\n + '——会话内容并未超长,压缩上下文无效;请调低「最大输出 token」或改用输出上限更大的模型',\n { status },\n )\n }\n if (status < 500 && isContextOverflowDetail(overflowDetail)) {\n return bilingual(\n CONTEXT_WINDOW_EXCEEDED_CODE,\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 { 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. The code is matched shape-insensitively because the provider\n // spells it both ways (`cmd_zdr_no_providers` in the JSON error body,\n // `CMD_ZDR_NO_PROVIDERS` in plain-text ones, exactly as the official CLI's\n // classifier reads it), and the CLI's own user guidance is to unset CMD_ZDR.\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\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 { status: 422 },\n )\n }\n if (status === 401) {\n // An invalid or missing credential is a config problem, not a transport\n // failure: retrying it identically cannot succeed.\n return bilingual(\n 'INVALID_CREDENTIAL',\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 { 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.\n return bilingual(\n 'PROVIDER_HTTP_ERROR',\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 { status: 413 },\n )\n }\n // 上游正文可能回显输入或返回整页英文错误;仅展示中文解释和有界错误码。\n // 分类仍使用上面的原始正文,不能因为收敛展示文案改变重试与压缩行为。\n const diagnosticCode = parsed.code ?? /^\\s*(MODEL_NOT_IN_PLAN|INSUFFICIENT_CREDITS|USAGE_EXCEEDED|PREMIUM_CREDITS_EXHAUSTED)\\b/i.exec(parsed.message ?? '')?.[1]\n const diagnostic = diagnosticCode !== undefined && /^[A-Za-z0-9_.:-]{1,80}$/.test(diagnosticCode)\n ? `(${diagnosticCode})` : ''\n return new LlmError(\n `Command Code 请求失败(HTTP ${status})${diagnostic}:`\n + (status === 429 ? '请求受到用量或速率限制,请稍后重试并检查账户额度。'\n : status === 408 ? '服务端处理超时,请稍后重试。'\n : status >= 500 ? '上游服务暂时无法完成请求,请稍后重试。'\n : '服务端拒绝了本次请求,请检查模型、套餐和请求设置。'),\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 \"temporarily unavailable\" class (Cloudflare's\n * 520-527 included) and the only sane answer to it is the byte-identical\n * resend the retry policy exists to make; 408 is the same story for the\n * request itself. Everything else stays permanent: a 400/403/404/409/422\n * rejection repeats identically on every attempt.\n */\nfunction httpErrorCode(status: number): string {\n if (status === 429) return THROTTLED_CODE\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` member\n // of an SSE chunk rather than as an event type of its own; ignoring it let\n // the stream end with no finish event, so a context-window or quota rejection\n // surfaced only as a generic EMPTY_RESPONSE (which the retry policy repeats)\n // and the real cause was lost.\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 a `reasoning_details` array, GLM/Qwen/Kimi with the\n // DeepSeek-native `reasoning_content`, and the OpenAI family with the scalar\n // `reasoning` PLUS a `reasoning_details` array whose entry is\n // `{ type: 'reasoning.summary', summary }` (measured live 2026-09-18 on\n // gpt-5.6-luna, 6/6 rounds: the scalar and the array's `summary` carried the\n // identical text every time). All three spellings are read here, in that\n // order, so no family's thinking is dropped; the scalar wins over the array,\n // which is a forward guard rather than the live path for any family (every\n // family that sends the array also sends a scalar alongside it). See\n // {@link reasoningDetailsText} for the array's two vocabularies.\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. */\n/**\n * Messages `usage` → the harness meter.\n *\n * The field names are the Anthropic ones, and unlike Chat Completions\n * `input_tokens` already excludes cache reads and writes, so it is mapped\n * as-is rather than reduced (the shape `dsh-llm-deepseek` implements).\n * Measured 2026-09-29: `{ input_tokens, cache_creation_input_tokens,\n * cache_read_input_tokens, output_tokens, output_tokens_details:\n * { thinking_tokens } }`, plus gateway additions the meter ignores.\n */\nfunction mapMessagesUsage(raw: unknown, previous?: TokenUsage): TokenUsage | undefined {\n if (!isRecord(raw)) return undefined\n const inputTokens = numberValue(raw.input_tokens) ?? previous?.inputTokens ?? 0\n const outputTokens = numberValue(raw.output_tokens) ?? previous?.outputTokens ?? 0\n const cacheRead = numberValue(raw.cache_read_input_tokens) ?? previous?.cacheReadTokens ?? 0\n const cacheWrite = numberValue(raw.cache_creation_input_tokens) ?? previous?.cacheWriteTokens ?? 0\n const details = isRecord(raw.output_tokens_details) ? raw.output_tokens_details : undefined\n const reasoningTokens = numberValue(details?.thinking_tokens) ?? previous?.reasoningTokens\n const usage: TokenUsage = {\n inputTokens: Math.max(0, inputTokens),\n outputTokens,\n cacheReadTokens: cacheRead,\n }\n if (cacheWrite > 0) usage.cacheWriteTokens = cacheWrite\n if (reasoningTokens !== undefined) usage.reasoningTokens = reasoningTokens\n return usage\n}\n\n/** The harness block type one Messages content block maps to. */\nfunction messagesBlockType(native: Record<string, unknown>): MessagesBlockState['type'] | undefined {\n if (native.type === 'text') return 'text'\n if (native.type === 'thinking') return 'reasoning'\n if (native.type === 'tool_use') return 'tool-call'\n return undefined\n}\n\n/**\n * Handle one Messages-transport stream event, appending harness StreamChunks.\n *\n * The event sequence is the Anthropic one measured on 2026-09-29:\n * `message_start`, then per content block `content_block_start` /\n * `content_block_delta`* / `content_block_stop`, then `message_delta`\n * (carrying `stop_reason` and the final usage) and `message_stop`. A `ping`\n * keepalive interleaves freely and carries no content. The terminal chunks are\n * NOT emitted here: `stream()` holds the success finish until it has validated\n * the assembled answer, and it attaches the replay envelope.\n */\nfunction handleMessagesEvent(asm: BlockAssembler, event: unknown): StreamChunk[] {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n\n switch (event.type) {\n case 'message_start': {\n const message = isRecord(event.message) ? event.message : undefined\n const usage = mapMessagesUsage(message?.usage)\n if (usage) {\n asm.messagesUsage = usage\n chunks.push({ type: 'usage', usage })\n }\n break\n }\n case 'content_block_start': {\n const wireIndex = numberValue(event.index)\n const native = isRecord(event.content_block) ? event.content_block : undefined\n const type = native ? messagesBlockType(native) : undefined\n if (wireIndex === undefined || type === undefined) break\n // Allocate the harness index only for a block this route can represent,\n // so replayBlocks stays aligned with the emitted block count.\n const chunkIndex = asm.nextIndex++\n const state: MessagesBlockState = {\n type,\n text: stringValue(native?.text) ?? '',\n signature: stringValue(native?.signature) ?? '',\n json: '',\n id: stringValue(native?.id) ?? '',\n name: stringValue(native?.name) ?? '',\n chunkIndex,\n }\n asm.messagesBlocks.set(wireIndex, state)\n asm.replayBlocks[chunkIndex] = { type }\n chunks.push({ type: 'block-start', index: chunkIndex, blockType: type })\n if (type === 'tool-call' && state.id !== '') {\n chunks.push({\n type: 'tool-call-delta',\n index: chunkIndex,\n id: ToolCallId(state.id),\n name: state.name,\n argumentsDelta: '',\n })\n }\n break\n }\n case 'content_block_delta': {\n const wireIndex = numberValue(event.index)\n const state = wireIndex === undefined ? undefined : asm.messagesBlocks.get(wireIndex)\n const delta = isRecord(event.delta) ? event.delta : undefined\n if (!state || !delta) break\n const index = state.chunkIndex\n if (delta.type === 'text_delta' && state.type === 'text') {\n const text = stringValue(delta.text) ?? ''\n state.text += text\n if (text.trim() !== '') asm.sawContent = true\n chunks.push({ type: 'text-delta', index, text })\n } else if (delta.type === 'thinking_delta' && state.type === 'reasoning') {\n const text = stringValue(delta.thinking) ?? ''\n state.text += text\n chunks.push({ type: 'reasoning-delta', index, text })\n } else if (delta.type === 'signature_delta' && state.type === 'reasoning') {\n // Not model-visible content: it rides the replay envelope so the next\n // request can send the block back, never a reasoning delta.\n state.signature += stringValue(delta.signature) ?? ''\n const entry = asm.replayBlocks[index]\n if (entry) entry.signature = state.signature\n } else if (delta.type === 'input_json_delta' && state.type === 'tool-call') {\n const fragment = stringValue(delta.partial_json) ?? ''\n state.json += fragment\n chunks.push({\n type: 'tool-call-delta',\n index,\n id: ToolCallId(state.id),\n name: state.name,\n argumentsDelta: fragment,\n })\n }\n break\n }\n case 'content_block_stop': {\n const wireIndex = numberValue(event.index)\n if (wireIndex === undefined) break\n const state = asm.messagesBlocks.get(wireIndex)\n if (!state) break\n asm.messagesBlocks.delete(wireIndex)\n const index = state.chunkIndex\n if (state.type === 'text') {\n if (state.text.trim() !== '') asm.sawContent = true\n chunks.push({ type: 'block-end', index, block: { type: 'text', text: state.text } })\n } else if (state.type === 'reasoning') {\n chunks.push({ type: 'block-end', index, block: { type: 'reasoning', text: state.text } })\n } else {\n if (state.id !== '') asm.sawContent = true\n chunks.push({\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: ToolCallId(state.id), name: state.name, arguments: state.json || '{}' },\n })\n }\n break\n }\n case 'message_delta': {\n const delta = isRecord(event.delta) ? event.delta : undefined\n const reason = stringValue(delta?.stop_reason)\n if (reason !== undefined) asm.finishReason = reason\n const usage = mapMessagesUsage(event.usage, asm.messagesUsage)\n if (usage) {\n asm.messagesUsage = usage\n chunks.push({ type: 'usage', usage })\n }\n break\n }\n case 'message_stop':\n chunks.push({ type: 'finish', reason: mapFinishReason(asm.finishReason) })\n break\n case 'ping':\n break\n case 'error':\n throw streamErrorToLlmError(event.error ?? event, stringValue(event.message))\n default:\n break\n }\n return chunks\n}\n\nfunction handleEvent(asm: BlockAssembler, protocol: CommandCodeProtocol, event: unknown): StreamChunk[] {\n if (protocol === 'cli') return handleCliEvent(asm, event)\n return protocol === 'messages' ? handleMessagesEvent(asm, event) : handleOpenAIEvent(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' || reason === 'tool_use') 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(\n reason: string | undefined, maxTokens: number, usage: TokenUsage | undefined,\n): 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. A\n // genuine context-window rejection has its own upstream wording and is\n // classified separately by `generateHttpError()`'s `isContextOverflowDetail`\n // branch / `streamErrorToLlmError()`'s in-band equivalent — not inferred\n // here from a client-side estimate (see 决策记录 for why the estimate-based\n // `requestContextBudget()`/`floored` signal this branch used to read was\n // removed, issue #74).\n return bilingual(\n 'OUTPUT_TOKEN_LIMIT',\n `Command Code reached the output token limit without producing answer text or a tool call (${detail})`,\n 'Command Code 已达到输出 token 上限,但没有生成正文或工具调用;请调整思考强度,或在模型和接口上限内增加输出预算',\n )\n }\n if (reason === 'content_filter' || reason === 'content-filter') {\n return bilingual('CONTENT_FILTER', `Command Code filtered the response (${detail})`, 'Command Code 拦截了响应,未生成正文或工具调用')\n }\n return bilingual(\n 'EMPTY_RESPONSE',\n `Command Code finished without producing answer text or a tool call (${detail})`,\n 'Command Code 返回了空响应(可能只有思考内容),重试通常可恢复',\n )\n}\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 * It must recognize the whole account-scoped class, not just 429/401: when it\n * did not, an account that could not pay, or could not run the model, stayed\n * \"usable\" in the pool and was handed out again on the next request (issue\n * #51's follow-up). The four reasons are defined on\n * {@link AccountRotationReason}; what this function owes them is the evidence\n * split:\n *\n * - `rate-limit` / `throttled`: the code `RATE_LIMITED` is the authoritative\n * signal — the CLI accepts the code OR a 429 status — and only a body that\n * NAMES a window (`error.rateLimit.window`, see {@link readWindowLimitEvidence})\n * may be called a spent one. A bare 429 is a burst/model/spend limiter the\n * billing endpoint cannot see, so it stays `throttled` and the host claims\n * no window (issue #54).\n * - `unavailable`: no credits, or a model outside this account's plan, so it\n * rotates but must NOT mark the key — the fact is about the model or the\n * balance, and either can change without the key changing.\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 carrying one of these must rotate\n * past the account instead of being retried as a transient provider failure,\n * because the same request against the same account cannot succeed. Only the\n * prose scan below is confined to 4xx.\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(\n status: number,\n errText: string,\n parsed: ParsedProviderError = parseProviderError(errText),\n): { reason: AccountRotationReason; resetAtMs?: number } | undefined {\n const code = (parsed.code ?? parsed.type)?.toUpperCase()\n if (status === 429 || code === 'RATE_LIMITED') {\n const evidence = readWindowLimitEvidence(errText, parsed)\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` enters the retry policy\n // 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.\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.\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/**\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 \"usage limit\n * for your plan\" wording (read as `weekly` when it says so, else `fiveHour`).\n * That is the CLI's own bar for calling a rejection a WINDOW limit, and it is\n * what keeps a bare 429 — a burst limiter, a model-level limit, a spend cap\n * `windowLimits` cannot show — from being reported as an exhausted window\n * (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(\n errText: string,\n parsed: ParsedProviderError,\n): { window?: 'fiveHour' | 'weekly' | 'daily'; resetAtMs?: number } {\n const named = stringValue(parsed.rateLimit?.window)\n const message = parsed.message ?? stringValue(parsed.root?.message) ?? ''\n const seconds = numberValue(parsed.rateLimit?.reset)\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\n/**\n * True when a pre-stream rejection is Command Code's Go-plan gate\n * (`upgrade_required`) — the only plan without Provider API access. Only this\n * class of rejection should fall back to the CLI `/alpha/generate` transport;\n * other 4xx/5xx must surface as ordinary errors so real account/model\n * problems are not masked.\n */\nfunction isUpgradeRequiredError(\n status: number,\n errText: string,\n parsed: ParsedProviderError = parseProviderError(errText),\n): 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 if ((parsed.code ?? parsed.type)?.toLowerCase() === 'upgrade_required') return true\n if (parsed.message?.toLowerCase().includes('go plan') && parsed.message.toLowerCase().includes('api access')) return true\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 * zh/en copy for the Host-side `/commandcode` usage command, as plain\n * constants: the command runs on the Host and has no access to the client's\n * `ctx.locale`, so the active locale is resolved by `pickCommandLocale()` and\n * the dictionaries are read by direct lookup. Distinct from\n * `./client/locales.ts` (the settings-page `settings.commandcode` namespace).\n *\n * zh is the source of truth for the key set; `en` must carry exactly the same\n * keys, which the `Record` type makes a compile error.\n */\n\n/** Active locale id for the `/commandcode` command. */\nexport type LocaleId = 'zh' | 'en'\n\n/** Dictionary keys used by the `/commandcode` command. */\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 | '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 | 'activeBadge'\n | 'invalidCredentialBadge'\n | 'cooldownBadge'\n | 'rateLimitBadge'\n | 'planLine'\n | 'planPeriodSuffix'\n | 'usageHeader'\n | 'requestsLine'\n | 'costLine'\n | 'tokensLine'\n | 'creditsHeader'\n | 'monthlyLine'\n | 'barLine'\n | 'windowsHeader'\n | 'fiveHourLine'\n | 'weeklyLine'\n | 'windowBarLine'\n | 'exceededWarning'\n | 'partialFailures'\n | 'noData'\n | 'errorText'\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 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 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: explicit `override`\n * (from `Config.lang`) → `LC_ALL` → `LANG` → the `'zh'` fallback that keeps\n * unconfigured deployments on their current output.\n *\n * Matched on the leading tag only — `zh_CN.UTF-8`, `zh-Hans` and `zh` all\n * map to `'zh'`, anything starting with `en` maps to `'en'`, everything else\n * falls back to `'zh'` rather than 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","/** Shared, dependency-free formatting for Host commands and browser surfaces. */\n\nexport function formatMoney(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\nexport function formatMoneyExact(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\nexport function formatTokensCompact(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/** The input is already in percent units; callers add the percent sign. */\nexport function formatSuccessRate(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** One window's fill ratio in [0, 1]; zero when uncapped. */\nexport function windowRatio(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.max(0, Math.min(1, used / cap))\n}\n\n/** Local date-time, with the empty state chosen by the caller. */\nexport function formatResetAt(ms: number): string {\n return ms <= 0 ? '' : new Date(ms).toLocaleString()\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()`. The command is Host-side\n * and has no access to the client's `ctx.locale`, so the active locale\n * arrives through `deps.getLocale()` and every string comes from\n * `./command-locales.ts` (a missing key falls back to the `en` copy).\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'\nimport { formatMoney, formatMoneyExact, formatSuccessRate, formatTokensCompact, formatResetAt, windowRatio } from './display-format.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 it\n * from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent (notably in\n * tests), the command renders with the default locale `'zh'`.\n */\n getLocale?: () => LocaleId\n}\n\n// ---------------------------------------------------------------------------\n// Number / time formatting (locale-independent; the locale only changes\n// the surrounding labels)\n// ---------------------------------------------------------------------------\n\nconst money = formatMoneyExact\nconst moneyShort = formatMoney\nconst tokensCompact = formatTokensCompact\nconst successRateText = formatSuccessRate\n\n/** A local date, or `n/a` when the provider published no reset time. */\nfunction resetLabel(ms: number): string {\n return formatResetAt(ms) || 'n/a'\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 = windowRatio(used, cap)\n const filled = Math.round(ratio * 10)\n return '█'.repeat(filled) + '░'.repeat(10 - filled)\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/prices`, `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`). This module is dependency-free so\n * the client bundle can inline it, and it holds the schema helpers and\n * descriptor boilerplate the wire files 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 endpoint\n * in the rejection message (e.g. `commandcode/report result:`), so each wire\n * file keeps its own diagnostic phrasing while sharing the helper 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). Callers that need the\n * narrowing in an `if` must therefore assign inside the positive branch.\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: `mode: 'strict'` carries the LAZY schema factory\n * (`create()`) the registry requires and the Gateway validates with\n * (`codec.create().parse`). There is NO `schema` member — issue #49.\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 result\n * — only the endpoint, method, result type symbol, and schema differ.\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 contracts for the Command Code Remotes the browser half mounts: the\n * account-usage report (`commandcode/report`), the model catalog\n * (`commandcode/models`) and the price table (`commandcode/prices`).\n *\n * The browser never holds the API key, so every one of these is produced\n * Host-side: the Host half registers a strict invocation descriptor against a\n * Cordis service (`src/usage-remote.ts`) and the browser half mounts the\n * matching contribution on `ctx.remote` (`src/client/index.ts`). This module\n * is the single source both halves share — the hand-rolled result validators\n * and the exact descriptor objects, so neither half can drift. It is\n * dependency-free because the client bundle inlines it.\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/**\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 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: an explicit `false` means the endpoint omitted the\n // balance, which cannot be told from a real zero — the panel keeps the\n // figure off the dashboard rather than drawing a consumed quota. An absent\n // flag (an older Host) stays unset and reads as \"assume reported\", so a\n // real balance is not lost cross-version. A PRESENT value must still be a\n // boolean, so a malformed frame is rejected 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 parsers return\n // undefined for an absent block, and an optional member is only set when\n // 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 * Per-model MONTHLY allowance in USD: how much of the plan's monthly credit\n * pool this one model may draw, already resolved by the Host against the\n * account pool's highest plan (the pricing page publishes an allowance for\n * Go, GOAT and Pro). Undefined when that plan has no published allowance\n * (Go, Provider, Max, Ultra) or when billing could not be read — the browser\n * shows nothing rather than guessing a neighbouring tier's figure.\n *\n * Deliberately a plain number and not the `{ go, goat, pro }` map: the bracket is\n * a Host decision that already depends on facts the browser does not hold, and\n * shipping both figures would invite a second, divergent rule here. Note this\n * is dollars per MONTH, unlike every rate in `CommandCodePriceTable`.\n */\n allowance?: number\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 numberField: catalogNumber,\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 // Same rule for the allowance: an older Host simply omits it, but a Host that\n // sends a non-number has broken the contract.\n if (source.allowance !== undefined) {\n model.allowance = catalogNumber(source, 'allowance', 'model.allowance')\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: a present non-number is a contract violation rather\n // than a silent zero (only a minority of models publish a cache-write rate).\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 instead of pasting an API key. The loopback server must live\n * in the Host half — it binds a local port and receives the key — so the page\n * drives it through the 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 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 Command Code Remotes (`commandcode/report`,\n * `commandcode/models`, `commandcode/prices`, `commandcode/login*`).\n *\n * The settings page needs facts the browser cannot fetch for itself — it never\n * holds the API key — so this module exposes them through the Typert Gateway:\n * a `TypertRemoteService` provides the receiver the Gateway resolves, and the\n * shared strict descriptors (`src/usage-wire.ts`, `src/login-wire.ts`) are\n * registered on the `typert` registry so the Gateway claims the endpoints.\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_HOST_CONTRIBUTION } 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 and `begin`\n * rejects with a plain message, so the page's manual paste path stays the\n * 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. Absent, the\n * `models` endpoint answers an empty list — the page's editors degrade to\n * 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 /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */\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. The\n * contribution is the combined one built below, so the type is structural\n * rather than tied to any one endpoint's 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 * Degrades per endpoint like the `/commandcode` command (failures land in\n * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which\n * the Gateway folds into 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 browser\n * never calls the Command Code API directly — the Host serves the catalog\n * (already fetched/cached by the adapter) so models can be picked from the\n * 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, served Host-side so the browser bundle never carries\n * a copy that could drift from the snapshot, and so a price update reaches an\n * 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).\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_HOST_CONTRIBUTION.invocations],\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), mirroring\n * what the official `command-code login` CLI command performs.\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 * The server contract is CLI-mirrored: POST-only `/callback`, a 10 KB body\n * cap, JSON responses (`{success:true}` / `{success:false,error}`), and\n * state-token equality as the anti-forgery check. Three deliberate hardenings\n * over the CLI build: the CORS origin is echoed only when allowlisted (the\n * CLI falls back to the first origin), `Connection: close`, and the denial\n * branch checks the state token before it ends the attempt.\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/** 登录总期限包含浏览器回调、密钥验证与存储,不能在收到回调后撤掉保护。 */\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 signal?: AbortSignal,\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 ...(signal === undefined ? {} : { signal }),\n })\n // 身份验证只用状态码,及时释放不再使用的正文连接。\n void response.body?.cancel().catch(() => undefined)\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 private attemptAbort: AbortController | 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.\n */\n private attemptSeq = 0\n /**\n * The start currently binding a port, if any. Every `begin()` arriving before\n * it settles joins it: two independent starts would each bind a loopback\n * server, and only the LAST one is reachable by `teardown()` — the orphan\n * keeps answering `/callback` for the process's lifetime, and ten of them\n * exhaust 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 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 — 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 this.attemptAbort = new AbortController()\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()` or a `dispose()` can arrive before any `waiting` status is\n // visible. Publishing one now would hand the user a live authUrl they\n // already asked to drop, so the freshly bound server is closed here.\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 // 回调成功只关闭监听服务,验证期间继续使用同一总期限。\n this.timer = setTimeout(() => {\n if (!this.ownsAttempt(attempt)) return\n this.teardown()\n this.setStatus({\n state: 'failed',\n reason: 'timeout',\n message: '登录未在规定时间内完成,请重试。',\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 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 if (failure !== undefined) this.teardown()\n else this.closeCallback()\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 this.attemptAbort?.signal,\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.teardown()\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.teardown()\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.teardown()\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.teardown()\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 /** 消费一次回调后关闭监听;保留总期限以约束后续验证。 */\n private closeCallback(): void {\n closeServer(this.server)\n this.server = undefined\n this.settle = undefined\n }\n\n /** 结束整个尝试,同时中止验证请求,迟到结果由所有权检查拦截。 */\n private teardown(): void {\n this.clearTimer()\n this.attemptAbort?.abort()\n this.attemptAbort = undefined\n this.closeCallback()\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 * Command Code web-search provider over `ctx.web`.\n *\n * The official CLI's built-in `web_search` tool POSTs\n * `{ query, numResults, allowedDomains?, blockedDomains? }` to\n * `{apiBase}/alpha/web-search` and reads `{ results: [{ title, url, snippet }] }`\n * back, authenticating with the SAME `Authorization: Bearer <key>` and\n * `x-command-code-version` headers the model adapter uses. This provider\n * therefore reuses the plugin's existing credential chain and `apiBase`, so\n * the model-facing `web_search` tool needs no separate configuration.\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`). A documented\n * reference only: disabling this plugin's `webSearch` toggle restores the\n * PREVIOUSLY selected backend, never this default (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 * dsh offers no public API to change the selected search provider at runtime,\n * so this seam mutates the instance field directly — 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\n * boot-time `searchProvider: commandcode` cordis patch is the durable\n * 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. `displaced`\n * is the backend it took over — restored on disable or unload — and\n * `undefined` means \"nothing was configured, leave auto-select\" and must\n * round-trip untouched.\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) OR \"the field already read `commandcode`\" (touch\n * nothing). Collapsing the two is what turned a user's own\n * `searchProvider: commandcode` pin into an auto-select, and then into\n * `WEB_PROVIDER_AMBIGUOUS` on every search.\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, the original `displaced` is kept —\n * the field currently holds our own id, which must never be mistaken for the\n * user's backend.\n * - Disabling hands the selection back to the remembered backend only when\n * this plugin actually took it over. A fresh boot straight into\n * `webSearch: false`, or a `preexisting` field, leaves it ALONE: writing the\n * empty memory back would clear the user's own `searchProvider: commandcode`\n * pin and hand the selection to dsh-web's auto-select, where a second usable\n * provider makes every later search throw `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).\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 — see the\n // `preexisting` note on {@link CommandCodeSearchSelection}.\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, reusing\n * the plugin's credential chain and `apiBase` so the model-facing `web_search`\n * tool needs no separate configuration. Selection between multiple search\n * providers is the web seam's job (pin `searchProvider: commandcode` if\n * 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). A MISSING credential maps to WEB_PROVIDER_CREDENTIAL_MISSING;\n // real rejections (INVALID_CREDENTIAL / RATE_LIMIT) keep their message\n // 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 * dsh-TUI owns its settings screen and asks plugins only to DECLARE what is\n * editable. Without 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 `/provider` wizard manages its `llm-pi-ai` routes\n * exclusively (issue #28). The seam is third-party, so this module carries\n * LOCAL structural types and reads the service defensively; registration rides\n * the plugin entry's `ctx.inject(['tuiSettingsSections'], …)`, so a profile\n * without dsh-TUI never activates the fiber.\n *\n * The API-key field is a **secret** field: the literal goes to the credentials\n * seam, never into a settings document. Its reference must stay out of the\n * host-reserved namespace (`DEEPSEEK_*`/`DSH_*`) — dsh-TUI silently DROPS a\n * field with a reserved ref, which would leave a page with no key input.\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. The\n * seam has no multi-select kind (`text | number | boolean | select`) and no\n * array element path a checkbox could own, so each model is its own `boolean`\n * field at `modelVisibility.<id>` whose `parse` writes its explicit boolean.\n * The format reads the allowlist LIVE so web changes are reflected when the\n * terminal renders. An empty allowlist means \"show every model\" to the adapter,\n * so the checkboxes render the EFFECTIVE set.\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'\nimport { PLAN_LABELS, PLAN_TIER_ORDER } from './plan-tiers.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 readonly value: string\n /** Display label (English; also the fallback). */\n readonly label: string\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 readonly descriptions?: TuiLocalizedText\n /** Optional one-line help rendered under the field. */\n readonly hint?: string\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 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 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/** Tiers in picker order; a model outside this set joins the \"Other\" group. */\nconst TIER_ORDER: readonly string[] = PLAN_TIER_ORDER\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. A model added\n * upstream after this build still reaches the user: an empty allowlist shows\n * everything, and a model named in the allowlist but absent here is rendered\n * 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 * The two option-bearing fields (`activeAccount`, `lang`) are `text` +\n * `options` rather than `select`, because a `select` cannot express \"unset\" —\n * cycling only ever lands on a declared option, so it would strand the user on\n * a pinned value with no way back to automatic. The `auto` sentinel plus a\n * `parse` that clears the path keeps unset reachable. `filterModelsByPlan`\n * formats its EFFECTIVE default (unset means true at the adapter) so a fresh\n * install reads true instead of 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 const stored = storedIds(deps.visibleModels())\n const overrides = deps.modelVisibility?.() ?? {}\n // Models this build's catalog cannot place (retired, 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: `${PLAN_LABELS[tier] ?? tier} models`,\n descriptions: { zh: `${PLAN_LABELS[tier] ?? tier} 模型` },\n }))\n // A tier this snapshot cannot place shares the \"Other\" group above.\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. 保存显式布尔值,不能因为与白名单相同就\n * 清除用户层:清除后可能重新露出基础配置中的相反开关。\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 return { kind: 'set', value: text.trim() === 'true' }\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: ['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: ['offloadSeenImagesForCache'],\n group: 'advanced',\n kind: 'boolean',\n label: 'Stop replaying images already seen',\n descriptions: { zh: '已看过的图片不再重复发送' },\n hint: 'CLI transport only. After this model has answered, durably replace older images with text to keep later prompt text cacheable. Old pixels need a fresh file read or attachment to inspect again. Off by default.',\n hintDescriptions: { zh: '仅 CLI 传输。模型看过图片并回复后,永久用文字替代旧图,以保留后续文本缓存;重看旧图需要重新读取文件或附加。默认关闭。' },\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.\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 * @returns a refresh function that re-registers the section when a fact it\n * renders changed — the plugin entry calls it from its\n * `loader/volatile-update` listener — or `undefined` when the seam is\n * unusable. The returned function is 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 rejecting host (a shadow-mode capability policy, a future contract\n // change) must not take the plugin down: the terminal simply keeps no\n // Command Code page, and the web settings 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 policy (`providerRetryPolicy` in `./adapter.ts`) is near-unbounded\n * on purpose — 1000 attempts doubling to a 15-minute cap — for failures the\n * provider ASKS to have retried. A connection that cannot be established is\n * not that: a blip the first few attempts absorb, or an outage no in-request\n * waiting fixes (attempt 11 alone already waits 512 s). So transport failures\n * get their own budget, cleared at each new STEP (one step = one model\n * request). `agent/status` → `idle` is NOT the reset (one `running` phase spans\n * a turn's steps), and neither is `assistant/attempt` (appended for the FAILED\n * attempt itself, which would clear the budget on every failure).\n *\n * Not counted here: the adapter's in-`stream()` pre-stream recovery (account\n * rotation, the 413 step-down, the Provider-API → CLI switch) — invisible to\n * the caller and bounded on its own.\n *\n * @module\n */\n\n/** Failure code this budget covers. */\nexport const TRANSPORT_FAILURE_CODE = 'TRANSPORT'\n\n/** Transport failures to absorb before the failure surfaces (default 5: ~15 s of blip cover on the route cadence). */\nexport const DEFAULT_TRANSPORT_MAX_RETRIES = 5\n\n/** Ceiling for the setting above (plausibility bound, not a recommendation; mirrored in `Config`'s schema and pinned by tests). */\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 * Pure and exported on purpose: the choice of event is the part of this design\n * that is easy to get plausibly wrong (see the module comment), so it is stated\n * once, where a test can pin it.\n *\n * @param type - the appended session event's type.\n * @returns `'reset'` for a new step, `'forget'` when the turn ended (the\n * session → agent mapping is no longer needed), otherwise `'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 too; it names the retry budget and the checks that actually help instead\n * of the bare \"fetch failed\" 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 * Volatile-config helpers for dsh 0.1.7's schema-derived profile Config.\n *\n * 0.1.7's `settings.describe()` projects each entry's schema through\n * `volatileForm()`, so a form contains ONLY nodes carrying `meta.volatile`\n * and a form edit is refused unless its path lies beneath a marked node. The\n * loader then resolves each marked field into a frozen `{ get() }` reference\n * that is written IN PLACE (no remount) and announced with\n * `loader/volatile-update`. Two helpers keep the rest of the plugin reading a\n * PLAIN `Config`: `markVolatile()` applies the mark, and\n * `unwrapVolatileConfig()` reads every top-level field through its reference\n * when one is present — FRESH per call, because a reference's identity is\n * stable while its value changes.\n *\n * Only TOP-LEVEL fields are marked (a form write names a top-level path such\n * as `accounts` or `modelVisibility.<id>`), so one unwrap level is complete.\n * The literal `apiKey` secret stays unmarked on purpose: no settings surface\n * writes it — page and TUI both write keys through the credentials seam — so a\n * config-file edit to it reloading the fiber is correct 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: it is a schemastery 3.18.3 feature and the\n * only supported engine (`dsh 0.2.0-rc.2`) pins `~3.18.4`, so the method is\n * always present. It is reached through a structural member so the caller's\n * declared field type survives — the mark changes what the schema PARSES to (a\n * live reference), not the plugin-facing `Config` shape.\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 */\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, MIT).\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 and the model picker lists the live catalog. Connection\n * facts are resolved per request from the live profile Config (volatile\n * fields, unwrapped per read) and the credential seam, so a changed key,\n * endpoint or cache path reaches the 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 { absorbTransientFailure, resetTransientFailures, transientBudgetMessage } from './transient-retry.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 } 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 { 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'\nimport { modelAllowanceFor } from './model-prices.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 * Opt-in cache mitigation for the CLI route: after this model has answered,\n * durably offload its earlier images before later turns. Old pixels then\n * require a fresh read/attachment if the model needs to inspect them again.\n * Defaults to false to preserve full image history.\n */\n offloadSeenImagesForCache?: boolean\n /**\n * Transport failures one request absorbs before the failure is surfaced;\n * defaults to 5. The route's policy allows long waits for confirmed usage\n * windows, while ordinary transient errors have a separate three-retry\n * budget. A transport failure is not\n * one of those, and after ~15.5 s of grace the wait is pure stall, so it is\n * capped here (issue #39). 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\"; applied 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.\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, and an entry with\n * neither `apiKey` nor `apiKeyEnv` is ignored. A pre-stream 429/401 marks\n * the key and the next account's key is retried transparently.\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`). It serves\n * whenever usable; an unknown id or an exhausted one falls back to rotation\n * order. Unset means \"first usable account\".\n */\n activeAccount?: string\n /**\n * Model → account routing rules, each listing catalog model ids for an\n * account slot id. A matching rule's account serves before {@link\n * activeAccount} and the passive rotation order; an unusable routed account\n * falls back, so the router is a hint, never a hard gate. First match wins.\n */\n modelAccountRules?: CommandCodeModelAccountRule[]\n /**\n * Whether to use Command Code as the backend for dsh's model-facing\n * `web_search` tool. Enabled registers a `commandcode` search provider on\n * `ctx.web` AND selects it over the shipped `deepseek-official` (or a\n * sibling plugin's pin), reusing the SAME key and apiBase as chat. Disabling\n * hands the selection back to whichever backend was there before, so a\n * sibling search plugin (e.g. modsearch) keeps working (issue #26). The\n * write rides dsh's internal `searchProviderId`, read per search call, so a\n * setting change lands on the next search without a restart. Defaults true.\n */\n webSearch?: boolean\n /**\n * Whether the Web sidebar shows the plans & quota card\n * (`sidebar.footer.action`). Defaults to false, so an unset document mounts\n * no sidebar quota surface and no background usage poll for it; the\n * dashboard cell behind it stays registered. Read by the browser client; the\n * adapter ignores it.\n */\n showSidebarQuota?: boolean\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, and a model\n * with no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` rather\n * than losing the guarantee. ZDR capacity is priced pass-through and usually\n * costs more; the price readout keeps quoting the ordinary catalog rates\n * (the real per-request price shows in Command Code's Studio).\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 the\n * explicit knob: `'zh'` or `'en'`, defaulting to `'zh'`. The web settings\n * page is unaffected — it follows the browser's language preference on its\n * own. The declared type is `string` (the schemastery `pattern` cannot\n * narrow literal types); `pickCommandLocale` treats an unknown value as\n * \"unset\" and then reads `LC_ALL`/`LANG`, which is only reachable when\n * `lang` is absent from a programmatically built config.\n */\n lang?: string\n}\n\n/**\n * The Config schema: every field volatile except the composition-only `apiKey`\n * secret. 0.1.7's settings forms are projected from the schema's\n * `meta.volatile` nodes, so an unmarked field would be invisible to AND\n * unwritable from the settings page. The loader also hands `apply()` a live\n * reference per marked field, so writes commit in place without remounting\n * this fiber — the `loader/volatile-update` listener at the bottom of `apply`\n * re-derives the two facts that are not re-read per request.\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.\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 offloadSeenImagesForCache: z.boolean().default(false),\n transportMaxRetries: z.number().min(0).max(MAX_TRANSPORT_MAX_RETRIES),\n filterModelsByPlan: z.boolean(),\n visibleModels: z.array(z.string()),\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 // 与账户移除原子提交的清理队列,仅存引用;凭据服务失败或页面中断后可重试。\n credentialCleanupRefs: z.array(z.string().role('credential-ref')),\n modelAccountRules: z.array(z.object({\n models: z.array(z.string()),\n account: z.string(),\n })),\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 * every settings-backed read.\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 offloadSeenImagesForCache: config.offloadSeenImagesForCache === true,\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.\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: a non-object or a\n * non-boolean entry is dropped rather than reaching the picker filter, and an\n * all-empty map reads as no map. Returns a fresh id → boolean map, or\n * 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 a\n // settings-page accounts change reaches the very next request.\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, re-read per resolution like every other\n // 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, and the marks are re-checked\n // against the live window limits only once every account is marked, so the\n // 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 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 unusable the pool's own RATE_LIMIT / INVALID_CREDENTIAL\n // error is what the caller sees, not the raw provider rejection.\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 — a `:free` model is still served by a\n // credits-empty account. `rate-limit` and `throttled` both mark but with\n // different causes, so the pool's own diagnosis never reports a plain\n // throttle as an exhausted usage window (issue #54).\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.\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.\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. An empty `settingsPath` means the whole\n // `llm-commandcode` section configures this provider.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n // Bounded retry for TRANSPORT failures (issue #39). The route policy allows\n // long recovery for a confirmed usage window; ordinary 520s now have their\n // own three-retry cap. A connection that cannot be established needs its\n // separate budget, or the shared cadence\n // turned a 10-second connect timeout into an ~8-minute stall, so the first\n // few transport failures are absorbed here and the rest surface with a\n // diagnosis. `dsh-llm-retry` still owns the wait between allowed attempts.\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, and the\n // diagnostic also goes to the log, which 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, provider, 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 || provider !== PROVIDER) return next()\n const session: unknown = Reflect.get(agent, 'session')\n if (typeof session === 'object' && session !== null) sessionAgents.set(session, agent)\n const transient = absorbTransientFailure(agent, failure.code)\n if (transient === 'exhausted') throw new Error(transientBudgetMessage(failure.code, failure.message))\n // 只约束次数;仍由官方重试器决定退避和 Retry-After,避免即时重发。\n if (transient === 'retry') return next()\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) {\n resetTransportFailures(agent)\n resetTransientFailures(agent)\n }\n })\n ctx.on('agent/status', ({ agent, status }) => {\n if (status === 'idle') {\n resetTransportFailures(agent)\n resetTransientFailures(agent)\n }\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 // activeAccount() (not the bare selectActiveAccount import) so a stale\n // `unknown` mark on the pinned account self-heals the same way a real\n // request would, instead of the badge reading it forever until the next\n // chat message happens to clear it (issue #51's follow-up report).\n const active = await pool.activeAccount()\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 per invocation from `Config.lang`\n // (explicit override) and the environment's `LC_ALL`/`LANG` (inferred\n // default), so a settings change reaches the next 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`), plus the browser-login flow the\n // same service carries (the Host binds a loopback callback server and stores\n // the delivered key through the credentials seam). Rides the optional\n // `typert` registry service, so profiles without the web stack never\n // activate it.\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: served\n // Host-side from the adapter's cached/fetched catalog, so the browser never\n // calls the Command Code API directly. Unfiltered, so an editor never loses\n // its own options — a rule can route a GOAT-only model the picker hides.\n // Each 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 // Per-model monthly allowance (how far this one model stretches the plan's\n // credit pool). The page publishes Go, GOAT and Pro figures, so the POOL's\n // bracket decides whether a figure exists at all — a Max/Provider account\n // gets none rather than a neighbouring tier's number. `listModels` above\n // already consulted the same cached billing facts, so this costs one lookup.\n const bracket = await adapter.allowanceTier()\n return {\n models: models.map((model) => {\n const tier = KNOWN_PLANS[model.id]\n const allowance = bracket === undefined ? undefined : modelAllowanceFor(model.id)?.[bracket]\n return {\n id: model.id,\n name: model.name.replace(/\\s*\\(CC\\)$/, ''),\n ...(tier === undefined ? {} : { tier }),\n ...(allowance === undefined ? {} : { allowance }),\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. It reuses\n // the SAME credential chain and apiBase as the model adapter, so DSH's\n // model-facing web_search tool needs no separate key or endpoint config.\n //\n // Whether `commandcode` WINS over the shipped `deepseek-official` (or a\n // sibling search plugin's pin, e.g. modsearch) is `Config.webSearch`. The\n // seam has no public runtime selector, so the plugin writes its private\n // `searchProviderId` field (read per call) via\n // `applyCommandCodeSearchSelection`; see src/web-search.ts for why that\n // write is safe. The tracked selection remembers whichever backend was\n // displaced, so turning the toggle off — and disposing the fiber — hands the\n // selection back to it (issue #26) instead of forcing the factory default.\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 dsh-TUI settings page: without it a TUI-only user has no way to enter\n // the API key (issue #28). The seam is optional, exactly like `commands` and\n // `web`, so a profile without dsh-TUI never activates this fiber.\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 section is re-registered when this list changes (the refresh call\n // below), since the host renders a fixed option list per declaration.\n accountSlots: () => slots().map((slot) => ({ id: slot.id, label: slot.label })),\n // Read live, so a checkbox judges its inherited state against the\n // current document, and an id this build's catalog does not place still\n // 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. A profile without a settings service simply keeps\n // 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`) — never rename one without the other, or a mismatch\n // strands existing users' non-secret settings in `settings.yaml.imported`.\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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"}
|