@mars-sea/dsh-commandcode-provider 0.13.2 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["record","tokensOf","record","counts","counts","parseCatalog","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/analytics.ts","../src/wire-shared.ts","../src/analytics-wire.ts","../src/analytics-history.ts","../src/response-encoding.ts","../src/timeout-limits.ts","../src/model-visibility.ts","../src/transient-retry.ts","../src/accounts.ts","../src/provider-errors.ts","../src/stream-trace.ts","../src/stream-response.ts","../src/image-request.ts","../src/image-tokens.ts","../src/request-timing.ts","../src/gateway-facts.ts","../src/adapter.ts","../src/command-locales.ts","../src/display-format.ts","../src/commands.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/enrollment-wire.ts","../src/usage-remote.ts","../src/login.ts","../src/enrollment.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 * Token buckets contributed by summarization calls, already folded into\n * `groups` but deliberately NOT part of the harness's own `tokenUsage`\n * projection.\n *\n * Compaction issues its own `ctx.llm.stream()` call, so its cost is real\n * spend, but it produces no `assistant/message` or `assistant/attempt` event\n * — the only two the harness meter folds (see `token-meter/src/usage-projection.ts`).\n * The summary therefore lands in this projection alone, and the composer\n * readout subtracts this field before asserting that both projections\n * describe the same durable cut. Without the split the equality check fails\n * and the whole readout disappears whenever a session compacts.\n *\n * Always present: `parseState` backfills it to zero for state written before\n * this field existed.\n */\n summaryTokens: CostTokens\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.82.1) 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.82.1 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 //\n // `off` is NOT a strength: it is the DeepSeek family's \"do not think\" level\n // (command-code@1.73.3), and the official CLI sends it verbatim as\n // `reasoning_effort:\"off\"` rather than omitting the field. Its presence here\n // is what makes the adapter treat `off` as a real choice for these models\n // instead of the host's \"no effort requested\" signal - see the lookup in\n // `stream()`. No other family lists it: the Messages transport's\n // `output_config.effort` has no such value, so `off` stays dropped there.\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 // Still a three-level set at 1.74.3: unlike its V4 siblings, this one never\n // gained `off`, so thinking cannot be switched off on this variant.\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0.\n 'deepseek/deepseek-v4.1-flash': ['off', 'low', 'high', 'max'],\n // command-code@1.67.0; the same four-level set as its `deepseek-v4.1-flash`\n // sibling, whose throughput-focused variant this is.\n 'deepseek/deepseek-v4.1-flash-fast': ['off', 'low', 'high', 'max'],\n // command-code@1.73.3 added `off` (\"Allow disabling thinking for DeepSeek\n // models\") to the DeepSeek V4 line and the 4.1 pair above - but NOT to\n // `deepseek-v4-flash-fast`, which the 1.74.3 table still ships at three.\n 'deepseek/deepseek-v4-flash': ['off', 'high', 'max'],\n 'deepseek/deepseek-v4-flash-vision-exp': ['off', 'high', 'max'],\n 'deepseek/deepseek-v4-pro': ['off', 'high', 'max'],\n // command-code@1.82.0 (\"Gemini Argon\") and the only registry addition in the\n // 1.81.0 -> 1.82.1 train. Three selectable levels, the same set the Gemini\n // Flash family carries.\n 'google/gemini-4-argon': ['low', 'medium', 'high'],\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.80.0 (\"Add Muse Wonder\"): the Muse family's newest member and\n // the only registry addition in the 1.79.2 -> 1.81.0 train. It carries the\n // same four-level set as Muse Spark 1.1/1.2 (no `max`).\n 'meta/muse-wonder-1.0': ['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 // `stealth/space-bunny-alpha` (command-code@1.65.0, `max` added by 1.73.4)\n // was RETIRED by command-code@1.74.3: the artifact drops its own four-level\n // effort list and ships the row as `hidden` instead, the official Desktop\n // changelog for 2026-10-06 says \"Remove Space Bunny Alpha from the model\n // picker\", and the model is gone from `/provider/v1/models` as well as the\n // pricing page.\n // `stealth/pixel-canary` (the second stealth preview, `xhigh` instead of\n // `high`) was RETIRED by command-code@1.73.1: the CLI hides it behind\n // `isPixelCanaryEnded()` (past 2026-10-01T06:00:00Z) and it is gone from\n // `/provider/v1/models` and the pricing page.\n // command-code@1.77.0 closed both out here as well: neither carries an effort\n // list any more, both sit in the CLI's non-selectable set (its\n // `listSelectableModelIds()` filters them out), and both left the ZDR\n // exclusion set — so no table in this file names either one any more.\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 // command-code@1.75.0 (\"Add Mistral Large 4\") — the only model the 1.74.3 ->\n // 1.77.0 train added. A three-level set; Vision per the official registry and\n // the CLI's inputModalities:[\"text\",\"image\"] (see `KNOWN_IMAGE_MODELS`), and\n // Go-tier availability (see `KNOWN_PLANS`).\n 'mistral/mistral-large-4': ['low', 'medium', 'high'],\n // command-code@1.78.0 (\"Add Claude Haiku 5.5 (Pro and above)\") and 1.79.0\n // (\"Add Glyph Cluster as a free model, 100 requests a day\") are the only\n // registry additions in the 1.77.0 -> 1.79.1 train. Both carry selectable\n // efforts, so neither belongs in KNOWN_THINKING_MODELS; Claude Haiku 5.5 takes\n // the Claude family's five-level set, while the free Glyph Cluster preview\n // stops at four and offers no `max`.\n 'claude-haiku-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'stealth/glyph-cluster:free': ['low', 'medium', 'high', '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 // command-code@1.78.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'claude-haiku-5-5',\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 // command-code@1.82.0; Vision per the official registry, the CLI's\n // inputModalities:[\"text\",\"image\"] and the docs page's \"Text input, Vision,\n // Reasoning\" capability label.\n 'google/gemini-4-argon',\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 // command-code@1.80.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\",\"file\"] — the only model in this catalog\n // that also declares the `file` modality.\n 'meta/muse-wonder-1.0',\n // command-code@1.75.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'mistral/mistral-large-4',\n 'moonshotai/Kimi-K2.5',\n 'moonshotai/Kimi-K2.6',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'moonshotai/Kimi-K3',\n 'sakana/fugu-ultra',\n // command-code@1.65.0; Vision per the official registry and inputModalities.\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.82.1` `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 dropped\n * `meituan/LongCat-2.0`, which sat in `modelSupportsZdr` alone through\n * 1.73.0; the 1.74.3 table lists it in NEITHER set, so as of this snapshot it\n * is no longer excluded. The official docs (commandcode.ai/docs/resources/\n * zdr) put coverage 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), 1.67.0 added one\n * (`deepseek/deepseek-v4.1-flash-fast`), 1.68.0 changed nothing, and 1.74.1\n * removed one (`meituan/LongCat-2.0`). The 1.74.2/1.74.3 pair changed nothing\n * here either (22 members as of 2026-10-06); 1.77.0 dropped the two retired\n * stealth previews, back to 20 members as of 2026-10-07, and 1.79.0 added the\n * free `stealth/glyph-cluster:free` preview — 21 members as of 2026-10-08.\n *\n * 1.77.0 also settled the two retired stealth previews (see `KNOWN_EFFORTS`):\n * 1.74.3 still named both in the ZDR anchors, so they stayed listed here on\n * purpose — an id a stale session named still got a truthful answer. The 1.77.0\n * artifact names neither in its exclusion set and filters both out of\n * `listSelectableModelIds()`, so they are pruned along with the rest of the\n * tables and `supportsZeroDataRetention` now answers TRUE for them, matching\n * what the current CLI says.\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 retired stealth\n // previews, the pricing page carries no ZDR note for this row — the artifact\n // is the evidence, and the sibling `deepseek-v4.1-flash` stays ZDR-covered.\n 'deepseek/deepseek-v4.1-flash-fast',\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 // command-code@1.80.0. The CLI's exclusion set names it, so a ZDR request for\n // it is refused; the pricing page carries no ZDR note for this row, so the\n // artifact is the evidence. 22 members as of 1.82.1 — Gemini 4 Argon, the\n // only registry addition in the 1.81.0 -> 1.82.1 train, is NOT in the set.\n 'meta/muse-wonder-1.0',\n 'minimax/minimax-m3-free',\n 'poolside/laguna-s-2.1-free',\n 'sakana/fugu-ultra',\n // command-code@1.79.0. The free Glyph Cluster preview is the ONE entry here\n // whose exclusion the official pricing page states in prose rather than\n // leaving to the artifact: its tip reads \"Free while the preview lasts. Up to\n // 100 requests a day. Not routed under ZDR.\" The CLI's own exclusion set\n // carries the same membership.\n 'stealth/glyph-cluster:free',\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: 77 of the 89\n * catalog ids as of 2026-10-14. Each row carries a comment naming the entry it\n * came from.\n *\n * Two of those 77 rest on more than a vendor lookup, both hand-recorded in the\n * script's `MANUAL_CEILINGS`. `gpt-6.1-sol` (128000) comes from OpenAI's own row\n * and is corroborated by every other provider carrying it.\n * `inclusionai/ling-3.1-flash:free` (32768) has no models.dev row at all, so it\n * takes the Ling family's uniform ceiling; `inclusionai/ling-3.0-flash-sante:free`\n * (32768) lost both its vendor row and its unanimous third-party vote (vercel\n * files 32000), and is pinned so a regeneration cannot drop a live model's\n * ceiling back to the default. All are still correctable — a stricter gateway\n * costs one refused request, and `streamRequest()` remembers what the endpoint\n * said.\n *\n * The 12 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-haiku-5-5', 128000],\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 // google\n ['google/gemini-4-argon', 32768],\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 // manual: no vendor row and no longer unanimous (vercel 32000); Ling family ceiling 32768, see MANUAL_CEILINGS\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 // meta\n ['meta/muse-wonder-1.0', 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 // 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.82.1 (2026-10-14): 89 catalog\n * ids at 54/64/79/87/89 cumulative, a strict superset chain. Mistral Large 4\n * (1.75.0) was the only addition at the 1.77.0 check; the 1.78.0/1.79.0 pair\n * added Claude Haiku 5.5 at Pro and the free Glyph Cluster preview at Go.\n * 1.79.2 lowers Haiku 5.5's minimum plan to GOAT; 1.80.0 adds Muse Wonder at\n * Max; 1.82.0 adds Gemini 4 Argon at Pro and nothing else moves. Every other\n * tier is unchanged.\n * The only removals since 1.49.0 are the two retired stealth previews (Pixel\n * Canary at 1.73.1, Space Bunny Alpha at 1.74.3). Per-entry tags below name the\n * releases that added or moved 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 // command-code@1.75.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 above.\n 'mistral/mistral-large-4': '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.79.0 (\"Add Glyph Cluster as a free model, 100 requests a\n // day\"); the pricing page's embedded availability grants every tier\n // (individual-go through teams-pro) — the \"all\":true shape shared by the Ling\n // free models above. Its zero-credit deal (see KNOWN_DEALS) also makes it lead\n // the picker.\n 'stealth/glyph-cluster:free': '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 (10 more) ---\n // command-code@1.79.2 lowers the 1.78.0 Pro gate to GOAT: individual-go\n // remains false, individual-goat and all higher tiers are true.\n 'claude-haiku-5-5': 'goat',\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 (15 more) ---\n 'claude-haiku-4-5-20251001': 'pro',\n 'claude-sonnet-4-6': 'pro',\n 'claude-sonnet-5': 'pro',\n // command-code@1.82.0; individual-go / go-v1 / goat all false, Pro and every\n // higher tier true — one tier above the Gemini Flash family above it.\n 'google/gemini-4-argon': '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 (2) ---\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 // command-code@1.80.0; the same Max-and-above availability as `gpt-6.1-sol`\n // (every lower tier false, only individual-max / individual-ultra /\n // teams-pro true) and the note \"Available on Max and above.\"\n 'meta/muse-wonder-1.0': '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.79.0 (\"Add Glyph Cluster as a free model, 100 requests a\n // day\"): 100% off \"Free while the preview lasts\", the same 100-requests-a-day\n // cap as its Ling predecessors and likewise no published end date, so no\n // `expiresAt`. The pricing page publishes it at a literal zero, which\n // `modelPriceTable()` serves from this deal, so it gets no row in the vendored\n // price table either. Unlike those free models it is NOT ZDR-routed — the\n // page's own tip says so outright (see `KNOWN_NON_ZDR_MODELS`).\n 'stealth/glyph-cluster:free': { label: 'FREE', free: true },\n // `stealth/space-bunny-alpha` (command-code@1.65.0, 100% off \"Free while the\n // stealth preview lasts\", auto-applied, no published end date) left this map\n // on 2026-10-06: command-code@1.74.3 hides the model, the catalog and the\n // pricing page dropped it, and the official Desktop changelog says \"Remove\n // Space Bunny Alpha from the model picker\". Its twin Pixel Canary left the\n // same way when command-code@1.73.1 retired it.\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-haiku-5-5', rates: [0.1, 0.5, 0.01, 0.125], allowance: { go: 6, goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":100000,\"rates\":[0.1,0.5,0.01,0.125]},{\"rates\":[0.5,2.5,0.05,0.625]}] },\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.1, 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: 100, pro: 100 } },\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: 'gemini-4-argon', rates: [2, 10, 0.1], allowance: { go: 6, goat: 20, pro: 20 } },\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: 60, pro: 70 } },\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: 'mistral-large-4', rates: [1.36, 4.18, 0.14], allowance: { go: 10, goat: 40, pro: 50 } },\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: 'muse-wonder-1.0', rates: [4, 20, 0.2], allowance: { go: 6, goat: 20, pro: 20 } },\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\n/** 工具参数可为对象或完整 JSON 字符串;不把未完成的字符串片段当作完整参数。 */\n\nexport function 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","/** 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/** The four buckets of an already-parsed record, or undefined when one is missing. */\nfunction costTokensOf(value: unknown): CostTokens | undefined {\n const t = record(value)\n if (!t || !COST_TOKEN_KEYS.every(k => finite(t[k]))) return undefined\n return t as unknown as CostTokens\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)\n return !!g && typeof g.provider === 'string' && typeof g.model === 'string'\n && (g.at === null || finite(g.at)) && finite(g.contextTokens) && costTokensOf(g.tokens) !== undefined\n }\n const sel = record(s.selection), last = record(s.last)\n // `summaryTokens` arrived with the compaction-summary fold. State written\n // before it carries no such key, so backfill zero instead of rejecting:\n // refusing would make every already-persisted session lose its readout on\n // upgrade. A present-but-malformed value is still an error.\n const summaryTokens = facts.summaryTokens === undefined ? zeroCostTokens() : costTokensOf(facts.summaryTokens)\n if (summaryTokens === undefined\n || !(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), facts: { ...(facts as unknown as SessionCostFacts), summaryTokens } }\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 /** Groups that still carry tokens; a retry that replaced a group can drive one to zero. */\n const liveGroups = (groups: CostUsageGroup[]): CostUsageGroup[] =>\n groups.filter(g => COST_TOKEN_KEYS.some(k => g.tokens[k] > 0))\n /**\n * Fold one settled usage group into `groups`, first undoing the group a retry\n * supersedes. Shared by turn/step settlements and summary calls, which have\n * no turn/step of their own.\n */\n const foldGroup = (groups: CostUsageGroup[], previous: CostUsageGroup | undefined, group: CostUsageGroup, tokens: CostTokens): void => {\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 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(costGroupKey(group, table))\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 }\n return {\n key: 'commandCodeCost', stateVersion: version,\n stateSchema: { parse: parseState },\n init: (): CostState => ({ selection: null, at: null, last: null, facts: { pricingKey: version, groups: [], summaryTokens: zeroCostTokens() } }),\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 // A compaction summary is the compactor's own `ctx.llm.stream()` call. It\n // is real spend, but it settles on no turn/step and emits none of the\n // `assistant/*` events the harness meter folds, so its usage exists only\n // here. Price it into `groups` AND count it in `summaryTokens`: the\n // readout subtracts the latter before checking that this projection and\n // `tokenUsage` still describe the same durable cut.\n if (event.type === 'compaction/summary') {\n const summary = tokensOf(data.usage)\n if (summary === undefined) return state\n const group: CostUsageGroup = {\n provider: typeof data.provider === 'string' ? data.provider : '',\n model: typeof data.model === 'string' ? data.model : '',\n at: finite(event.time) ? event.time : null,\n contextTokens: summary.uncachedInputTokens + summary.cacheReadTokens + summary.cacheWriteTokens,\n tokens: summary,\n }\n const groups = state.facts.groups.map(g => ({ ...g, tokens: { ...g.tokens } }))\n foldGroup(groups, undefined, group, summary)\n const summaryTokens = { ...state.facts.summaryTokens }\n for (const k of COST_TOKEN_KEYS) summaryTokens[k] += summary[k]\n return { ...state, facts: { pricingKey: version, groups: liveGroups(groups), summaryTokens } }\n }\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 foldGroup(groups, previous, group, tokens)\n return { ...state, last: { turn: data.turn, step: data.step, group }, facts: { pricingKey: version, groups: liveGroups(groups), summaryTokens: state.facts.summaryTokens } }\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","/** 在宿主内折叠原始历史;每次请求保留计价时间和上下文,禁止使用已合并的会话成本桶。 */\nimport { assistantStreamFirstTokenTime } from '@deepseek-ai/dsh-llm'\nimport type { AssistantStreamRecord } from '@deepseek-ai/dsh-llm'\nimport { COST_TOKEN_KEYS, pricingKey, requestRates, zeroCostTokens, type CostTokens } from './cost-facts.ts'\nimport type { CommandCodeModelPrice, CommandCodePriceTable } from './usage-wire.ts'\nimport type { AnalyticsMetrics, AnalyticsQuery, AnalyticsReport, AnalyticsScenario } from './analytics-wire.ts'\nimport { isRecord } from './wire-guards.ts'\n\nexport interface AnalyticsEvent { seq: number; type: string; time: number; data: unknown }\nexport interface AnalyticsLog { inheritedEventCount: number; events: readonly AnalyticsEvent[] }\nexport interface RequestFact {\n session: string; model: string; at: number; retry: boolean; outcome: 'completed' | 'failed' | 'cancelled' | 'unknown'\n tokens?: CostTokens; latencyMs?: number; ttftMs?: number; decodeMs?: number\n}\nconst record = (v: unknown): Record<string, unknown> | undefined => isRecord(v) ? v : undefined\nconst number = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v >= 0\nfunction tokensOf(v: unknown): CostTokens | undefined {\n const u = record(v)\n if (!u || !number(u.inputTokens) || !number(u.outputTokens)) return undefined\n if (u.cacheReadTokens !== undefined && !number(u.cacheReadTokens) || u.cacheWriteTokens !== undefined && !number(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/** 同一次尝试的用量覆盖前值;重试开始才新建请求,继承前缀只恢复模型选择。 */\nexport function foldRequests(session: string, log: AnalyticsLog): RequestFact[] {\n const facts: RequestFact[] = []\n let provider = '', model = '', current: RequestFact | undefined, own = false, started = false, listed = false, turn = -1, step = -1\n const begin = (event: AnalyticsEvent, data: Record<string, unknown>, retry: boolean) => {\n turn = Number(data.turn); step = Number(data.step); own = event.seq >= log.inheritedEventCount; started = true\n current = { session, model, at: event.time, retry, outcome: 'unknown' }\n listed = own && provider === 'commandcode'\n if (listed) facts.push(current)\n }\n for (const event of log.events) {\n const d = record(event.data)\n if (!d) continue\n if (event.type === 'request/header') {\n const config = record(record(d.header)?.config)\n provider = typeof config?.provider === 'string' ? config.provider : ''\n model = typeof config?.model === 'string' ? config.model : ''\n if (current && current.outcome === 'unknown') {\n current.model = model\n if (own && provider === 'commandcode' && !listed) { facts.push(current); listed = true }\n // 当前尝试始终是最后一条;避免每次请求扫描全部历史。\n if (provider !== 'commandcode' && listed) { facts.pop(); listed = false }\n }\n continue\n }\n // 压缩摘要是压缩器自己发的一次 `ctx.llm.stream()`:它不落在任何 turn/step 上,\n // 也不产生 `request/header`,用量只出现在这个事件里。只登记本路由的摘要,并且\n // 不碰 current / listed / provider 状态 —— 摘要在两次请求之间发生,不属于它们。\n // provider 与 model 由事件自带(后端上报),不从上一个 header 继承。\n if (event.type === 'compaction/summary') {\n if (event.seq >= log.inheritedEventCount && d.provider === 'commandcode') {\n const tokens = tokensOf(d.usage)\n facts.push({\n session, model: typeof d.model === 'string' ? d.model : '', at: event.time, retry: false, outcome: 'completed',\n ...tokens === undefined ? {} : { tokens },\n })\n }\n continue\n }\n if (event.type === 'step/start' || event.type === 'llm/retry-started') { begin(event, d, event.type === 'llm/retry-started'); continue }\n if (!current && ['assistant/message', 'assistant/attempt', 'assistant/chunk'].includes(event.type)) {\n begin(event, d, false); started = false\n }\n if (!current) continue\n if (event.type === 'turn/end' && d.turn === turn) {\n const reason = record(d.reason)?.kind\n if (current.outcome === 'unknown') {\n if (reason === 'error') current.outcome = 'failed'\n else if (reason === 'aborted') current.outcome = 'cancelled'\n }\n current = undefined\n continue\n }\n if (d.turn !== turn || d.step !== step) continue\n if (event.type === 'llm/retry') { current.outcome = 'failed'; continue }\n if (!['assistant/message', 'assistant/attempt', 'assistant/chunk'].includes(event.type)) continue\n const chunk = record(d.chunk)\n let tokens = tokensOf(d.usage)\n if (event.type === 'assistant/chunk' && chunk?.type === 'usage') tokens = tokensOf(chunk.usage)\n if (tokens === undefined && Array.isArray(d.stream)) {\n for (let i = d.stream.length - 1; i >= 0; i--) {\n const item = record(d.stream[i]), c = item?.type === 'chunk' ? record(item.chunk) : undefined\n if (c?.type === 'usage') { tokens = tokensOf(c.usage); if (tokens) break }\n }\n }\n if (tokens) current.tokens = tokens\n if (event.type === 'assistant/message') current.outcome = d.interrupted === true ? 'cancelled' : 'completed'\n // 只有保存了定时流的结算才测速度。旧消息的落盘时间不能冒充模型耗时。\n if (started && Array.isArray(d.stream) && event.time >= current.at) {\n current.latencyMs = event.time - current.at\n const first = assistantStreamFirstTokenTime(d.stream as AssistantStreamRecord[])\n if (first !== undefined && first >= current.at && first <= event.time) {\n current.ttftMs = first - current.at\n if (current.tokens) current.decodeMs = event.time - first\n }\n }\n }\n return facts\n}\n\nexport const emptyMetrics = (): AnalyticsMetrics => ({ sessions: 0, requests: 0, completed: 0, failed: 0, cancelled: 0, unknown: 0, retries: 0, usageSamples: 0, pricedRequests: 0, cost: 0, tokens: zeroCostTokens(), latencySamples: 0, latencyMs: 0, ttftSamples: 0, ttftMs: 0, decodeSamples: 0, decodeMs: 0, decodeTokens: 0 })\nfunction priceRequest(f: RequestFact, id: string, table: CommandCodePriceTable, prices: ReadonlyMap<string, CommandCodeModelPrice>): number | undefined {\n if (!f.tokens) return undefined\n const price = prices.get(id)\n if (!price) return undefined\n if (price.free === true) return 0\n const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens\n const r = requestRates(price, f.at, context, table)\n if (f.tokens.cacheWriteTokens > 0 && r.cacheWriteCost === undefined) return undefined\n return (f.tokens.uncachedInputTokens * r.inputCost + f.tokens.outputTokens * r.outputCost + f.tokens.cacheReadTokens * r.cacheReadCost + f.tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6\n}\nfunction aggregate(facts: RequestFact[], table: CommandCodePriceTable, prices: ReadonlyMap<string, CommandCodeModelPrice>): AnalyticsMetrics {\n const m = emptyMetrics(); m.sessions = new Set(facts.map(f => f.session)).size\n for (const f of facts) {\n m.requests++; m[f.outcome]++; if (f.retry) m.retries++\n if (f.tokens) { m.usageSamples++; for (const k of COST_TOKEN_KEYS) m.tokens[k] += f.tokens[k] }\n const cost = priceRequest(f, f.model, table, prices)\n if (cost !== undefined) { m.pricedRequests++; m.cost += cost }\n if (f.latencyMs !== undefined) { m.latencySamples++; m.latencyMs += f.latencyMs }\n if (f.ttftMs !== undefined) { m.ttftSamples++; m.ttftMs += f.ttftMs }\n if (f.decodeMs !== undefined && f.decodeMs > 0 && f.tokens) { m.decodeSamples++; m.decodeMs += f.decodeMs; m.decodeTokens += f.tokens.outputTokens }\n }\n return m\n}\nexport interface ScenarioModel { id: string; name: string; contextWindow: number | null; images: boolean; efforts: string[] }\nexport function buildAnalytics(facts: RequestFact[], query: AnalyticsQuery, table: CommandCodePriceTable, catalog: ScenarioModel[], now = Date.now()): AnalyticsReport {\n const selected = query.mode === 'range' ? facts.filter(f => f.at >= query.from && f.at < query.to) : facts\n const prices = new Map<string, CommandCodeModelPrice>()\n for (const p of table.models) for (const id of [p.id, p.slug]) if (!prices.has(id)) prices.set(id, p)\n const totals = aggregate(selected, table, prices)\n const models = [...new Set(selected.map(f => f.model))].map(id => ({ id, ...aggregate(selected.filter(f => f.model === id), table, prices) })).sort((a, b) => b.cost - a.cost || a.id.localeCompare(b.id))\n const scenarios: AnalyticsScenario[] = catalog.map(model => {\n let cost = 0, pricedRequests = 0, excludedRequests = 0, unknownRequests = 0\n for (const f of selected) {\n if (!f.tokens) { unknownRequests++; continue }\n const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens\n // 输入和输出同时占据上下文;不适配的请求不得混进可比较的成本。\n if (model.contextWindow !== null && context + f.tokens.outputTokens > model.contextWindow) { excludedRequests++; continue }\n const priced = priceRequest(f, model.id, table, prices)\n if (priced === undefined) unknownRequests++\n else { cost += priced; pricedRequests++ }\n }\n return { ...model, cost, pricedRequests, excludedRequests, unknownRequests }\n })\n const elapsed = query.mode === 'range' ? Math.min(query.to, now) - query.from : 0\n const monthlyEstimate = elapsed >= 86400000 && totals.requests > 0 && totals.pricedRequests === totals.requests\n ? totals.cost * (30 * 86400000 / elapsed) : null\n return { generatedAt: now, pricingKey: pricingKey(table), query, status: 'ready', scannedSessions: 0, matchedSessions: totals.sessions, unreadableSessions: 0, skippedSessions: 0, truncated: false, catalogUnavailable: false, totals, models, scenarios, monthlyEstimate }\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","/** 模型分析的只读契约;只传数字和模型能力,不传会话正文、标题、路径或密钥。 */\nimport type { InvocationDescriptor, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'\nimport { makeBoundaryValidator, makeRemoteDescriptor, makeStrictCodec, REMOTE_PACKAGE } from './wire-shared.ts'\nimport type { CostTokens } from './cost-facts.ts'\n\nexport type AnalyticsQuery = { mode: 'recent'; limit: number } | { mode: 'range'; from: number; to: number }\nexport interface AnalyticsMetrics {\n sessions: number; requests: number; completed: number; failed: number; cancelled: number; unknown: number; retries: number\n usageSamples: number; pricedRequests: number; cost: number; tokens: CostTokens\n latencySamples: number; latencyMs: number; ttftSamples: number; ttftMs: number; decodeSamples: number; decodeMs: number; decodeTokens: number\n}\nexport interface AnalyticsModel extends AnalyticsMetrics { id: string }\nexport interface AnalyticsScenario {\n id: string; name: string; contextWindow: number | null; images: boolean; efforts: string[]\n cost: number; pricedRequests: number; excludedRequests: number; unknownRequests: number\n}\nexport interface AnalyticsReport {\n generatedAt: number; pricingKey: number; query: AnalyticsQuery\n status: 'ready' | 'unavailable'\n scannedSessions: number; matchedSessions: number; unreadableSessions: number; skippedSessions: number; truncated: boolean; catalogUnavailable: boolean\n totals: AnalyticsMetrics; models: AnalyticsModel[]; scenarios: AnalyticsScenario[]\n monthlyEstimate: number | null\n}\nconst g = makeBoundaryValidator('commandcode/analytics')\nconst nonnegative = (s: Record<string, unknown>, k: string): number => {\n const n = g.numberField(s, k, k)\n return n >= 0 ? n : g.reject(k)\n}\nconst count = (s: Record<string, unknown>, k: string): number => {\n const n = nonnegative(s, k)\n return Number.isSafeInteger(n) ? n : g.reject(k)\n}\nexport function parseAnalyticsQuery(value: unknown): AnalyticsQuery {\n const s = g.record(value, 'query')\n if (s.mode === 'recent') {\n const limit = count(s, 'limit')\n if (limit < 1 || limit > 100) return g.reject('limit')\n return { mode: 'recent', limit }\n }\n if (s.mode !== 'range') return g.reject('mode')\n const from = count(s, 'from'), to = count(s, 'to')\n if (to <= from || to - from > 366 * 86400000 || to > 8640000000000000) return g.reject('range')\n return { mode: 'range', from, to }\n}\nconst counts = ['sessions', 'requests', 'completed', 'failed', 'cancelled', 'unknown', 'retries', 'usageSamples', 'pricedRequests', 'latencySamples', 'ttftSamples', 'decodeSamples'] as const\nconst quantities = ['cost', 'latencyMs', 'ttftMs', 'decodeMs', 'decodeTokens'] as const\nconst tokenKeys = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\nfunction metrics(value: unknown): AnalyticsMetrics {\n const s = g.record(value, 'metrics'), result = {} as AnalyticsMetrics\n for (const k of counts) result[k] = count(s, k)\n for (const k of quantities) result[k] = nonnegative(s, k)\n const tokens = g.record(s.tokens, 'tokens')\n result.tokens = Object.fromEntries(tokenKeys.map(k => [k, nonnegative(tokens, k)])) as unknown as CostTokens\n if (result.completed + result.failed + result.cancelled + result.unknown !== result.requests\n || result.pricedRequests > result.usageSamples || result.usageSamples > result.requests\n || result.retries > result.requests || result.ttftSamples > result.requests || result.latencySamples > result.requests || result.decodeSamples > result.requests) return g.reject('coverage')\n return result\n}\nconst nullable = (s: Record<string, unknown>, k: string): number | null => s[k] === null ? null : nonnegative(s, k)\nexport function parseAnalyticsReport(value: unknown): AnalyticsReport {\n const s = g.record(value, 'report')\n if (s.status !== 'ready' && s.status !== 'unavailable') return g.reject('status')\n if (!Array.isArray(s.models) || !Array.isArray(s.scenarios) || s.models.length > 1000 || s.scenarios.length > 1000) return g.reject('models')\n return {\n generatedAt: count(s, 'generatedAt'), pricingKey: count(s, 'pricingKey'), query: parseAnalyticsQuery(s.query), status: s.status,\n scannedSessions: count(s, 'scannedSessions'), matchedSessions: count(s, 'matchedSessions'), unreadableSessions: count(s, 'unreadableSessions'), skippedSessions: count(s, 'skippedSessions'),\n truncated: g.booleanField(s, 'truncated', 'truncated'), catalogUnavailable: g.booleanField(s, 'catalogUnavailable', 'catalogUnavailable'),\n totals: metrics(s.totals), monthlyEstimate: nullable(s, 'monthlyEstimate'),\n models: s.models.map(value => { const m = g.record(value, 'model'); return { ...metrics(m), id: g.stringField(m, 'id', 'id') } }),\n scenarios: s.scenarios.map(value => {\n const m = g.record(value, 'scenario')\n if (!Array.isArray(m.efforts) || !m.efforts.every(v => typeof v === 'string')) return g.reject('efforts')\n return { id: g.stringField(m, 'id', 'id'), name: g.stringField(m, 'name', 'name'), contextWindow: nullable(m, 'contextWindow'), images: g.booleanField(m, 'images', 'images'), efforts: m.efforts as string[], cost: nonnegative(m, 'cost'), pricedRequests: count(m, 'pricedRequests'), excludedRequests: count(m, 'excludedRequests'), unknownRequests: count(m, 'unknownRequests') }\n }),\n }\n}\nexport const ANALYTICS_DESCRIPTOR: InvocationDescriptor = {\n ...makeRemoteDescriptor('commandcode/analytics', 'analytics', `${REMOTE_PACKAGE}#AnalyticsReport`, { parse: parseAnalyticsReport }),\n parameters: [{ name: 'query', wire: 'query', source: 'json' as const, codec: makeStrictCodec(`${REMOTE_PACKAGE}#AnalyticsQuery`, { parse: parseAnalyticsQuery }) }],\n}\nexport const ANALYTICS_REMOTE_CONTRIBUTION: TypertRemoteContribution = { package: REMOTE_PACKAGE, descriptors: [ANALYTICS_DESCRIPTOR] }\n","/** 可选宿主历史服务:读实时优先的完整语料库,绝不加载会话为实时或写回日志。 */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { CommandCodeAdapter } from './adapter.ts'\nimport { KNOWN_EFFORTS } from './capabilities.ts'\nimport { buildAnalytics, foldRequests, type AnalyticsLog, type RequestFact, type ScenarioModel } from './analytics.ts'\nimport { parseAnalyticsQuery, type AnalyticsQuery, type AnalyticsReport } from './analytics-wire.ts'\nimport { modelPriceTable } from './model-prices.ts'\n\nexport interface HistoryQuery {\n listSessions(signal?: AbortSignal): Promise<Array<{ header: { id: string } }>>\n readSession(id: string): Promise<AnalyticsLog>\n}\nexport const ANALYTICS_SESSION_LIMIT = 500\nexport const ANALYTICS_EVENT_LIMIT = 200000\n/** 逐会话失败隔离;上限和遗漏计数会返回界面,部分结果不能伪装成完整历史。 */\nexport async function readAnalyticsHistory(history: HistoryQuery | undefined, input: AnalyticsQuery, catalog: () => Promise<ScenarioModel[]>, signal?: AbortSignal): Promise<AnalyticsReport> {\n const query = parseAnalyticsQuery(input), table = modelPriceTable()\n if (!history) return { ...buildAnalytics([], query, table, []), status: 'unavailable' }\n const records = await history.listSessions(signal)\n const facts: RequestFact[] = []\n let scannedSessions = 0, unreadableSessions = 0, skippedSessions = 0, events = 0, truncated = records.length > ANALYTICS_SESSION_LIMIT\n for (const entry of records.slice(0, ANALYTICS_SESSION_LIMIT)) {\n if (signal?.aborted) throw new Error('模型分析已取消')\n if (events >= ANALYTICS_EVENT_LIMIT) { truncated = true; break }\n scannedSessions++\n try {\n const log = await history.readSession(entry.header.id)\n // 老宿主或第三方服务缺少精确继承边界时跳过,不能猜测分支切点。\n if (!Number.isSafeInteger(log.inheritedEventCount) || log.inheritedEventCount < 0 || log.inheritedEventCount > log.events.length) { skippedSessions++; continue }\n events += log.events.length\n if (events > ANALYTICS_EVENT_LIMIT) { skippedSessions++; truncated = true; break }\n facts.push(...foldRequests(entry.header.id, log))\n } catch { unreadableSessions++ }\n }\n let selected = facts\n if (query.mode === 'recent') {\n const latest = new Map<string, number>()\n for (const f of facts) latest.set(f.session, Math.max(latest.get(f.session) ?? 0, f.at))\n const ids = new Set([...latest].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, query.limit).map(([id]) => id))\n selected = facts.filter(f => ids.has(f.session))\n }\n let models: ScenarioModel[] = [], catalogUnavailable = false\n if (signal?.aborted) throw new Error('模型分析已取消')\n try { models = await catalog() } catch { catalogUnavailable = true }\n const report = buildAnalytics(selected, query, table, models)\n return { ...report, scannedSessions, unreadableSessions, skippedSessions, truncated, catalogUnavailable, monthlyEstimate: truncated || unreadableSessions > 0 || skippedSessions > 0 ? null : report.monthlyEstimate }\n}\n/** 用反射和可选 fiber 对接,保持未挂载历史服务的无界面/TUI 配置可用。 */\nexport function createAnalyticsReader(ctx: Context, adapter: Pick<CommandCodeAdapter, 'listModels' | 'resolveModel'>) {\n let history: HistoryQuery | undefined, busy = false\n ctx.inject(['sessionQuery'], c => {\n const service = c.get('sessionQuery') as HistoryQuery | undefined\n if (typeof service?.listSessions !== 'function' || typeof service.readSession !== 'function') return\n history = service\n c.effect(() => () => { if (history === service) history = undefined }, 'commandcode analytics history')\n })\n return async (query: AnalyticsQuery, signal?: AbortSignal): Promise<AnalyticsReport> => {\n if (busy) throw new Error('模型分析正在读取历史,请稍后刷新')\n busy = true\n try {\n return await readAnalyticsHistory(history, query, async () => {\n const available = await adapter.listModels('commandcode')\n return Promise.all(available.map(async m => {\n const resolved = await adapter.resolveModel('commandcode', m.id)\n return { id: m.id, name: m.name.replace(/ \\(CC\\)$/, ''), contextWindow: resolved.context?.contextWindow ?? null, images: resolved.inputModalities?.includes('image') ?? false, efforts: [...(KNOWN_EFFORTS[m.id] ?? [])] }\n }))\n }, signal)\n } finally { busy = false }\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/** 不包含解析秘密的账号定义;作用域独立复制列表及模型规则。 */\nexport interface CommandCodeAccountSelection {\n slots: readonly CommandCodeAccountSlot[]\n preferredId?: string | undefined\n modelAccountRules: readonly CommandCodeModelAccountRule[]\n}\n\n/** 仅复制账号定义;凭据服务的秘密仍在每次解析时读取。 */\nexport function captureAccountSelection(selection: CommandCodeAccountSelection): CommandCodeAccountSelection {\n return Object.freeze({\n slots: Object.freeze(selection.slots.map(slot => Object.freeze({ ...slot }))),\n preferredId: selection.preferredId,\n modelAccountRules: Object.freeze(selection.modelAccountRules.map(rule => {\n const models = [...rule.models]\n Object.freeze(models)\n return Object.freeze({ ...rule, models })\n })),\n })\n}\n\n/** 账号选择与展示共用恢复规则;宿主作用域内的状态按网关与密钥共享。 */\nexport class CommandCodeAccountPool {\n /** 当前作用域内按密钥共享的健康状态;不记录到日志。 */\n private states = new Map<string, CommandCodeAccountState>()\n /** 当前网关与密钥的显式探测时间,限制失败探测的频率。 */\n private explicitProbes = new Map<string, number>()\n private scopedStates = new Map<string, { states: Map<string, CommandCodeAccountState>; probes: Map<string, number> }>()\n constructor(private readonly deps: CommandCodeAccountPoolDeps) {}\n\n /** 每个调用持有自己的定义和探测,只有同网关的健康事实共享;不临时改写全局依赖。 */\n scope(context: CommandCodeAccountSelection & { apiBase: string; probeWindow: CommandCodeAccountPoolDeps['probeWindow'] }): CommandCodeAccountPool {\n const selection = captureAccountSelection(context)\n let shared = this.scopedStates.get(context.apiBase)\n if (shared === undefined) {\n shared = { states: new Map(), probes: new Map() }\n this.scopedStates.set(context.apiBase, shared)\n }\n const scoped = new CommandCodeAccountPool({\n ...this.deps,\n slots: () => selection.slots,\n preferredId: () => selection.preferredId,\n modelAccountRules: () => selection.modelAccountRules,\n probeWindow: context.probeWindow,\n })\n scoped.states = shared.states\n scoped.explicitProbes = shared.probes\n scoped.scopedStates = this.scopedStates\n return scoped\n }\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). Scoped rules stay fixed for the call; credential values re-resolve.\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","/** 连接拒绝与流内错误共享同一分类,避免错误恢复因响应载体不同而漂移。 */\nimport { CONTEXT_WINDOW_EXCEEDED_CODE, isContextWindowExceededError, LlmError, type LlmErrorOptions } from '@deepseek-ai/dsh-llm'\nimport { RETRY_MAX_DELAY_MS } from './accounts.ts'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport { booleanValue, isRecord, numberValue, stringValue } from './wire-guards.ts'\n\n/** Keep the two user-facing languages and error metadata together. */\nexport function bilingual(code: string, en: string, zh: string, options?: LlmErrorOptions): LlmError {\n return new LlmError(`${en};${zh}`, code, options)\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 */\nexport const 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 */\nexport function 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 * 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 */\nexport function 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\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\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. */\nexport function 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\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 *\n * The optional `priorRejection` records a refusal from an earlier transport\n * attempt in this same call (see {@link isMessagesPermissionRejection}), so a\n * failed CLI fallback still shows what the Messages surface said first. It is\n * presentation only: classification, retry budget and failure code all keep\n * reading the current attempt.\n */\nexport function generateHttpError(\n status: number,\n errText: string,\n retryAfterMs?: number,\n parsed: ParsedProviderError = parseProviderError(errText),\n // 本次调用此前失败过的有界标识(目前只有 messages 的 `permission_error`)。\n // 只进入最终文案,不参与分类、重试预算与失败码,否则展示层会反过来改变行为。\n priorRejection?: string,\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 safeIdentifier = (value: string | undefined): string | undefined =>\n value !== undefined && /^[A-Za-z0-9_.:-]{1,80}$/.test(value) ? value : undefined\n const diagnosticCode = safeIdentifier(parsed.code)\n ?? /^\\s*(MODEL_NOT_IN_PLAN|INSUFFICIENT_CREDITS|USAGE_EXCEEDED|PREMIUM_CREDITS_EXHAUSTED)\\b/i.exec(parsed.message ?? '')?.[1]\n // Messages 接口常只有 type;两个字段分别校验,非法 code 不能掩盖合法 type。\n const diagnosticType = safeIdentifier(parsed.type)\n const identifiers = [\n diagnosticCode === undefined ? undefined : `错误码:${diagnosticCode}`,\n diagnosticType === undefined ? undefined : `错误类型:${diagnosticType}`,\n ].filter((value): value is string => value !== undefined)\n const diagnostic = identifiers.length === 0 ? '' : `(${identifiers.join(';')})`\n // 以本次(回退后的 CLI 直连)结果为主,另附此前反代侧的拒绝标识:只报第二段\n // 链路,用户无从判断 messages 端点拒绝过什么。标识再过一次同样的有界校验,\n // 免得上游正文里的任意串经此进入展示文案。\n const priorIdentifier = priorRejection === undefined ? undefined : safeIdentifier(priorRejection)\n const priorNote = priorIdentifier === undefined\n ? ''\n : `此前 Messages 接口以 ${priorIdentifier} 拒绝,已回退 CLI 直连,仍未成功。`\n return new LlmError(\n `Command Code 请求失败(HTTP ${status})${diagnostic}:`\n + (status === 429 ? '请求受到用量或速率限制,请稍后重试并检查账户额度。'\n : status === 408 ? '服务端处理超时,请稍后重试。'\n : status >= 500 ? '上游服务暂时无法完成请求,请稍后重试。'\n : '服务端拒绝了本次请求,请检查模型、套餐和请求设置。')\n + priorNote,\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 * 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 */\nexport function 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 * 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\nexport function 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 */\nexport const 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 */\nexport function 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/**\n * True when the Messages surface (`/provider/v1/messages`) refused one request\n * with Anthropic's `permission_error` (issue #84).\n *\n * 职责:把「反代 Claude 链路对该账号不放行」这一种拒绝,从普通权限失败里\n * 单独认出来,交给适配器决定是否改用 CLI 直连(`/alpha/generate`)。\n *\n * 为什么边界如此窄:只认 HTTP 403 加上结构化的 `code`/`type` 等于\n * `permission_error`,不扫原始正文。正文可能回显输入或返回整页英文错误,\n * 扫文本会把无关失败也变成一次传输切换;而真正「模型不在套餐内」的拒绝\n * (`MODEL_NOT_IN_PLAN` 等其它标识)继续按原样上报,不被这条规则吞掉。\n */\nexport function isMessagesPermissionRejection(\n status: number,\n parsed: ParsedProviderError,\n): boolean {\n if (status !== 403) return false\n return (parsed.code ?? parsed.type)?.toLowerCase() === 'permission_error'\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 * 调度层只转交响应;三种线上事件的装配差异保留在本模块内部。 */\nimport { randomUUID } from 'node:crypto'\nimport { LlmError, ProviderRequestId, ToolCallId, errorChain, type FinishReason, type StreamChunk, type TokenUsage } from '@deepseek-ai/dsh-llm'\nimport { bilingual, streamErrorToLlmError } from './provider-errors.ts'\nimport { isRecord, numberValue, stringValue, recordOrEmpty } from './wire-guards.ts'\nimport { boundTraceText, STREAM_TRACE_ENV, type StreamTrace } from './stream-trace.ts'\nimport type { RequestTiming } from './request-timing.ts'\n\n/** 仅供本次消费生命周期使用,不作为服务商错误或用户取消向外传播。 */\nclass ConsumerStreamClosed extends Error {}\n\n/**\n * 读循环唤醒闸门的标记值:底层 read() 既不结算、取消也叫不醒时,由闸门结束这次等待。\n * 它不是错误,只在读循环内部出现,用来把「读取完成」与「读取卡住」区分开。\n */\nconst READ_STALLED = Symbol('readStalled')\n\n/**\n * 异步生成器的 return 会排在正在等待的 next 后面,因此必须先通过独立信号\n * 唤醒当前读取,再让生成器执行 finally。消费方已结束时不再交付用量或错误。\n */\nexport function ownedResponseStream(\n callerSignal: AbortSignal | undefined,\n run: (signal: AbortSignal) => AsyncIterable<StreamChunk>,\n): AsyncIterable<StreamChunk> {\n const consumer = new AbortController()\n const signal = callerSignal ? AbortSignal.any([callerSignal, consumer.signal]) : consumer.signal\n const source = run(signal)[Symbol.asyncIterator]()\n let closed = false\n const done = (): IteratorResult<StreamChunk> => ({ done: true, value: undefined })\n const iterator: AsyncIterableIterator<StreamChunk> = {\n [Symbol.asyncIterator]() { return this },\n async next() {\n if (closed) return done()\n try {\n const result = await source.next()\n return closed ? done() : result\n } catch (error) {\n if (closed) return done()\n throw error\n }\n },\n async return() {\n if (!closed) {\n closed = true\n consumer.abort(new ConsumerStreamClosed('消费方已结束读取'))\n }\n await source.return?.()\n return done()\n },\n }\n return iterator\n}\n\nexport interface StreamResponseContext {\n protocol: CommandCodeProtocol\n signal: AbortSignal | undefined\n maxTokens: number\n apiBase: string\n streamIdleTimeoutMs: number\n responseMetadata: ResponseMetadata\n trace: StreamTrace\n timing: RequestTiming\n /** 解除连接阶段转交的取消监听;任何退出路径均调用一次。 */\n cleanup(): void\n}\n\n/** 唯一过程入口;诊断或释放失败不能在成功结束后再制造第二个结束。 */\nexport async function* settleStreamResponse(response: Response, context: StreamResponseContext): AsyncIterable<StreamChunk> {\n try { yield* readResponse(response, context) }\n finally {\n try { context.cleanup() } catch { /* 本地连接监听释放失败不改变模型结果。 */ }\n context.trace.close()\n }\n}\n\nasync function* readResponse(response: Response, context: StreamResponseContext): AsyncIterable<StreamChunk> {\n const { protocol, signal, maxTokens, apiBase, streamIdleTimeoutMs, responseMetadata, trace, timing } = context\n if (!response.body) {\n trace.record('end', { outcome: 'empty', code: 'PROVIDER_PROTOCOL_ERROR' })\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 cancelReader = () => {\n try { void reader.cancel().catch(() => undefined) }\n catch { /* 已释放的读取器不影响已决定的终止结果。 */ }\n }\n // 读取唤醒闸门:空闲计时器与取消信号都先解开它,再尽力取消底层读取。合规流上\n // cancel() 自己就会以 done 结算挂起的 read();但被包装或被垫片替换的 body 可能\n // 既不给结果也不响应取消,只依赖 cancel() 会让空闲期限、调用者取消和消费方结束\n // 三条路径一起卡死。闸门让这三条路径始终有界,且不改变正常读取的顺序。\n let openGate: (() => void) | undefined\n const wakeRead = () => openGate?.()\n const onAbort = () => { wakeRead(); cancelReader() }\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. Firing opens the\n // read gate — so the loop ends even for a reader that ignores cancel() —\n // and best-effort cancels the underlying read; the loop turns that into a\n // TIMEOUT failure instead of hanging forever.\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n let idleFired = false\n const armIdle = () => {\n if (idleTimer !== undefined) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleFired = true\n wakeRead()\n cancelReader()\n }, streamIdleTimeoutMs)\n }\n const clearIdle = () => {\n if (idleTimer !== undefined) {\n clearTimeout(idleTimer)\n idleTimer = undefined\n }\n }\n /** 空闲期限结束读循环时的唯一错误文本;读取结算与读取卡住两条路径共用。 */\n const idleTimeoutError = () => bilingual(\n 'TIMEOUT',\n `Command Code API stream from ${apiBase} was idle for ${streamIdleTimeoutMs}ms`\n + ' (no events) and was treated as a dead connection',\n `Command Code API 流式响应已 ${streamIdleTimeoutMs} 毫秒无任何事件,被判定为死连接——长思考模型可在设置中调大流空闲超时`,\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 /** 读循环收束(读到 EOF 或读取卡住)共用的诊断事实,两处记录字段保持一致。 */\n const eofFacts = () => ({\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 // 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 (isRecord(event) && ((protocol === 'messages' && event.type === 'message_stop')\n || (protocol === 'cli' && event.type === 'finish'))) protocolStopped = true\n const chunks = handleEvent(asm, protocol, event)\n // 一个线上事件已经解析完毕后,先保存其结束与用量事实。消费者可在\n // 任意块片段处取消;取消只停止交付,不能丢掉此时已经解析到的用量。\n for (const chunk of chunks) {\n if (chunk.type === 'finish') finish = chunk\n else if (chunk.type === 'usage') usage = chunk.usage\n }\n for (const chunk of chunks) {\n if (chunk.type === 'finish' || chunk.type === 'usage') continue\n signal?.throwIfAborted()\n yield chunk\n }\n }\n function* handleLine(line: string): Generator<StreamChunk> {\n signal?.throwIfAborted()\n if (protocol === 'openai' && line.trim().replace(/^data:\\s*/, '') === '[DONE]') {\n protocolStopped = true\n return\n }\n yield* handle(parseStreamEventLine(line))\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n try {\n for (;;) {\n signal?.throwIfAborted()\n let read: ReadableStreamReadResult<Uint8Array> | typeof READ_STALLED\n // 每次读取换一个新闸门:上一轮的闸门一旦解开就不再代表这次等待。\n const gate = new Promise<typeof READ_STALLED>(resolve => { openGate = () => resolve(READ_STALLED) })\n armIdle()\n try {\n const pending = reader.read()\n // 闸门先到时这个读取会被放弃:它可能永不结算,也可能迟到以「读取器已释放」\n // 拒绝。结果已经不再需要,挂一个空 catch 免得它升级成未处理拒绝(Node 默认致命)。\n void pending.catch(() => undefined)\n read = await Promise.race([pending, gate])\n } catch (error: unknown) {\n // A mid-stream transport failure (connection reset, TLS teardown)\n // surfaces here. Caller cancellation propagates as-is.\n signal?.throwIfAborted()\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 ${apiBase} failed while reading: ${errorChain(error)}`,\n 'Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\n { cause: error },\n )\n } finally {\n clearIdle()\n openGate = undefined\n }\n if (read === READ_STALLED) {\n // 期限或取消叫不醒底层读取:闸门自己结束等待。取消优先——调用者取消必须\n // 原样传播,不能被记成超时失败;只有在没有取消时才按空闲期限失败。\n trace.record('eof', { ...eofFacts(), readStalled: true })\n signal?.throwIfAborted()\n throw idleTimeoutError()\n }\n signal?.throwIfAborted()\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', eofFacts())\n if (idleFired) throw idleTimeoutError()\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 [index, line] of lines.entries()) {\n yield* handleLine(line)\n if (protocolStopped) {\n let ignoredLines = 0\n for (let rest = index + 1; rest < lines.length; rest++) if (lines[rest]?.trim()) ignoredLines++\n const buffered = buffer.trim().length\n if (ignoredLines > 0 || buffered > 0) trace.record('protocol-stop', { protocol, ignoredLines, buffered })\n break\n }\n }\n // OpenAI 的 finish_reason 之后还可能有独立用量包;Messages 在\n // message_stop 才结束。CLI 的 finish 则本身就是协议终止事件。\n if (protocolStopped) break\n }\n signal?.throwIfAborted()\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 signal?.throwIfAborted()\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 // 未收到生成结束原因的 EOF 不能伪造成功;正文或工具片段存在时\n // 按断流处理,纯思考或空白仍按空响应处理,保留既有重试分类。\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 ${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: signal?.aborted ? signal.reason instanceof ConsumerStreamClosed ? 'cancelled' : '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 endRecorded = true\n signal?.throwIfAborted()\n throw failureWithRequestId(error, responseMetadata)\n } finally {\n clearIdle()\n signal?.removeEventListener('abort', onAbort)\n // 消费者提前结束没有继续接收的能力,不能在 finally 强行交付用量。\n if (!endRecorded) trace.record('end', { outcome: signal?.aborted && !(signal.reason instanceof ConsumerStreamClosed) ? 'aborted' : 'cancelled',\n ...(usage === undefined ? {} : { usage }), chunks: chunkCount, bytes: totalBytes, responseMetadata })\n cancelReader()\n // 取消立即终止本地读取;不等底层 cancel 承诺,以免它拖住整个响应。\n try { reader.releaseLock() } catch { /* 本地清理失败不覆盖成功或原始错误。 */ }\n }\n}\n\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 */\nexport type CommandCodeProtocol = 'cli' | 'openai' | 'messages'\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\nexport function 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. */\nexport interface 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. */\nexport function 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\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 * 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 * 三种协议共享的块装配状态;正文与思考分别至多有一个正在输出的块。\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\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/**\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/** 三种协议的结束原因统一映射为宿主分类,保留线上名称用于诊断。 */\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/** 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 * 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","/** 请求耗时只记录阶段、计数和状态;不记录消息、凭据、请求头或错误正文。 */\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","/** 网关事实的唯一所有者:目录先校验再发布,调用快照与跨调用学习分别持有。 */\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { LlmError } from '@deepseek-ai/dsh-llm'\nimport { DEFAULT_MESSAGES_MAX_TOKENS, MODEL_OUTPUT_TOKEN_LIMITS, requiresMessagesEndpoint } from './capabilities.ts'\nimport { isRecord, numberValue, stringValue } from './wire-guards.ts'\nimport { OUTPUT_LIMIT_REJECTION, parseOutputCeiling } from './provider-errors.ts'\n\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 131_072\nexport const MODEL_CATALOG_TTL_MS = 5 * 60_000\nconst MODEL_CATALOG_RETRY_MS = 10_000\nconst MODEL_CACHE_VERSION = 3\nexport interface GatewaySource { apiBase: string; modelsCachePath: string }\nexport interface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n /** 保留来源公布值,派生预算不能作为持久化的权威上限。 */\n publishedMaxTokens?: number\n supportedEndpoints: readonly string[]\n}\nconst learned = new Map<string, Map<string, number>>()\nconst published = new Map<string, Map<string, number>>()\n// 跨实例发布序号只按网关共享;刷新失败也不能把发布权交还旧响应。\nconst generations = new Map<string, number>()\nconst validLimit = (value: number | undefined): value is number => value !== undefined && Number.isSafeInteger(value) && value > 0\nconst fallbackLimit = (model: string) => MODEL_OUTPUT_TOKEN_LIMITS.get(model) ?? (requiresMessagesEndpoint(model) ? DEFAULT_MESSAGES_MAX_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS)\nexport function learnedOutputLimit(apiBase: string, model: string): number {\n return learned.get(apiBase)?.get(model) ?? Infinity\n}\nexport function modelOutputTokenLimit(apiBase: string, model: string): number {\n return Math.min(published.get(apiBase)?.get(model) ?? fallbackLimit(model), learnedOutputLimit(apiBase, model))\n}\n\n/** 是否更新共享事实与是否值得重试是两个问题;以本次实发预算判断拒绝。 */\nexport function outputCeilingRefusal(apiBase: string, model: string, sent: number, error: unknown): number | undefined {\n if (!(error instanceof LlmError) || !OUTPUT_LIMIT_REJECTION.test(error.message)) return undefined\n const stated = parseOutputCeiling(error.message)\n if (!validLimit(stated) || stated >= sent) return undefined\n let limits = learned.get(apiBase)\n if (limits === undefined) learned.set(apiBase, limits = new Map())\n const next = Math.min(stated, learnedOutputLimit(apiBase, model))\n limits.set(model, next)\n return next\n}\n\nfunction normalizeModel(raw: unknown, apiBase: string, disk: boolean): CommandCodeModel | undefined {\n if (!isRecord(raw)) return undefined\n const id = stringValue(raw.id), name = stringValue(raw.name)\n const contextWindow = numberValue(disk ? raw.contextWindow : raw.context_length)\n if (!id || !name || contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) return undefined\n const limit = numberValue(disk ? raw.publishedMaxTokens : raw.max_output_tokens)\n const endpoints = disk ? raw.supportedEndpoints : raw.supported_endpoints\n return {\n id, name, contextWindow,\n maxTokens: Math.min(contextWindow, validLimit(limit) ? limit : fallbackLimit(id), learnedOutputLimit(apiBase, id)),\n ...(validLimit(limit) ? { publishedMaxTokens: limit } : {}),\n supportedEndpoints: Array.isArray(endpoints) ? endpoints.filter((item): item is string => typeof item === 'string') : [],\n }\n}\nfunction parseCatalog(value: unknown, apiBase: string): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n const rows = value.data.map(raw => normalizeModel(raw, apiBase, false)).filter((row): row is CommandCodeModel => row !== undefined)\n if (rows.length === 0) throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n return rows\n}\nasync function readCache(source: GatewaySource): Promise<CommandCodeModel[]> {\n const value: unknown = JSON.parse(await readFile(source.modelsCachePath, 'utf8'))\n if (!isRecord(value) || value.version !== MODEL_CACHE_VERSION || value.apiBase !== source.apiBase || !Array.isArray(value.models)) throw new Error('Invalid model cache source')\n const rows = value.models.map(raw => normalizeModel(raw, source.apiBase, true)).filter((row): row is CommandCodeModel => row !== undefined)\n if (rows.length === 0) throw new Error('Empty model cache')\n return rows\n}\nfunction publish(apiBase: string, rows: readonly CommandCodeModel[]): void {\n published.set(apiBase, new Map(rows.flatMap(row => row.publishedMaxTokens === undefined ? [] : [[row.id, row.publishedMaxTokens] as const])))\n}\nasync function writeCache(source: GatewaySource, rows: readonly CommandCodeModel[], mayCommit: () => boolean): Promise<void> {\n await mkdir(dirname(source.modelsCachePath), { recursive: true })\n const temp = `${source.modelsCachePath}.${process.pid}.${randomUUID()}.tmp`\n try {\n await writeFile(temp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, apiBase: source.apiBase, models: rows }, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 })\n if (mayCommit()) await rename(temp, source.modelsCachePath)\n } finally { await rm(temp, { force: true }).catch(() => undefined) }\n}\ninterface CatalogState {\n source: string\n rows: CommandCodeModel[]\n expiresAt: number\n disk?: Promise<CommandCodeModel[]>\n inflight?: Promise<CommandCodeModel[]>\n}\nfunction copyRows(rows: readonly CommandCodeModel[]): CommandCodeModel[] {\n return rows.map(row => ({ ...row, supportedEndpoints: [...row.supportedEndpoints] }))\n}\n\nexport class GatewayFacts {\n private state: CatalogState | undefined\n constructor(private readonly fetchCatalog: (source: GatewaySource) => Promise<unknown>) {}\n private forSource(source: GatewaySource): CatalogState {\n const identity = JSON.stringify([source.apiBase, source.modelsCachePath])\n if (this.state?.source !== identity) this.state = { source: identity, rows: [], expiresAt: 0 }\n return this.state\n }\n /** 模型解析保持原有热目录直读;不把生成的磁盘冷读取推广到其他入口。 */\n knownModel(source: GatewaySource, model: string): CommandCodeModel | undefined {\n const row = this.forSource(source).rows.find(candidate => candidate.id === model)\n return row === undefined ? undefined : copyRows([row])[0]\n }\n /** 生成只读取本地目录;捕获状态后不再转向实例的新来源。 */\n async snapshot(source: GatewaySource): Promise<CommandCodeModel[]> {\n const state = this.forSource(source)\n if (state.rows.length > 0 || state.expiresAt > 0) return copyRows(state.rows)\n state.disk ??= readCache(source).catch(() => [])\n const rows = await state.disk\n if (state.rows.length > 0 || state.expiresAt > 0) return copyRows(state.rows)\n if (state.inflight === undefined) state.rows = rows\n return copyRows(rows)\n }\n async refresh(source: GatewaySource, signal?: AbortSignal): Promise<CommandCodeModel[]> {\n signal?.throwIfAborted()\n const state = this.forSource(source)\n if (Date.now() < state.expiresAt) return copyRows(state.rows)\n if (state.inflight === undefined) {\n const generation = (generations.get(source.apiBase) ?? 0) + 1\n generations.set(source.apiBase, generation)\n const mayPublish = () => this.state === state && generations.get(source.apiBase) === generation\n state.inflight = (async () => {\n let rows: CommandCodeModel[], ttl = MODEL_CATALOG_TTL_MS\n try {\n rows = parseCatalog(await this.fetchCatalog(source), source.apiBase)\n if (mayPublish()) {\n publish(source.apiBase, rows)\n await writeCache(source, rows, mayPublish).catch(() => undefined)\n }\n } catch {\n ttl = MODEL_CATALOG_RETRY_MS\n rows = state.rows.length > 0 ? state.rows : await readCache(source).catch(() => [])\n // 磁盘只能在尚无联网刷新及共享有效事实的冷启动补充来源,不能倒灌。\n if (mayPublish() && !published.has(source.apiBase) && rows.length > 0) publish(source.apiBase, rows)\n }\n state.rows = rows\n state.expiresAt = Date.now() + ttl\n return rows\n })().finally(() => { delete state.inflight })\n }\n const inflight = state.inflight\n if (!signal) return copyRows(await inflight)\n const rows = await new Promise<CommandCodeModel[]>((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 return copyRows(rows)\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 and the pre-stream account rotation loop. 目录、发布与\n * 上限事实由 ./gateway-facts.ts 持有,本适配器只消费单次调用的独立快照。 已连接响应的读取与收束由 ./stream-response.ts 负责。\n * 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 { homedir } from 'node:os'\nimport { 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'\nimport { bilingual, MAX_TRUSTED_RESET_MS, parseProviderError, generateHttpError, parseRetryAfterMs, classifyAccountRejection, isUpgradeRequiredError, isMessagesPermissionRejection, type AccountRotationReason } from './provider-errors.ts'\nexport type { AccountRotationReason } from './provider-errors.ts'\nimport { ownedResponseStream, settleStreamResponse, responseIdentifiers, failureWithRequestId, type CommandCodeProtocol, type ResponseMetadata } from './stream-response.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef, ImageRequestTarget, RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\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 GenerateOptions,\n type LlmModelInfo,\n type LlmProviderInfo,\n type LlmResolvedModelInfo,\n type RequestMessage,\n type StreamChunk,\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 } from './stream-trace.ts'\nimport { openRequestTiming, type RequestTiming, type RequestTimingSink } from './request-timing.ts'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport { isRecord, numberValue, stringValue, recordOrEmpty } 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\nimport { GatewayFacts, modelOutputTokenLimit, learnedOutputLimit, outputCeilingRefusal, type CommandCodeModel } from './gateway-facts.ts'\nexport { DEFAULT_MAX_OUTPUT_TOKENS, MODEL_CATALOG_TTL_MS } from './gateway-facts.ts'\n\n// ---------------------------------------------------------------------------\n// Request / connection defaults (protocol constants). The model/plan/deal\n// capability snapshot lives in ./capabilities.ts — the sync-only surface.\n// ---------------------------------------------------------------------------\nexport const COMMAND_CODE_CLI_VERSION = '1.82.1'\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`, retired by Command Code on\n * 2026-10-01 and named here only as the probe's subject) and a 1 000 000-window\n * one (`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\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\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. */\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/** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */\nfunction periodTimestampValue(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 * 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// 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\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\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 * 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/** 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?: (connection: C) => 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 periodStart?: number\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 currentPeriodStart?: 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 const result: CommandCodeUsage = {\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 // 未上报统计口径不能默认写成账期,客户端必须明确显示周期未确认。\n periodBasis: stringValue(usage.periodBasis) ?? 'unreported',\n }\n const start = periodTimestampValue(usage.periodStart)\n if (start > 0 && Number.isFinite(new Date(start).getTime())) result.periodStart = start\n return result\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 * Read the account identity and organization scope from whoami. Every billing\n * and usage request must use this same organization, so getUsage reads it first.\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\n/** 仅在宿主内部区分阶段;报告继续通过既有 failures 文本传递,避免更改严格远端协议。 */\ntype JsonResponseFailure =\n | { stage: 'read'; identifiers: readonly string[]; timedOut: boolean }\n | { stage: 'parse' }\n | { stage: 'shape'; shape: string }\n\nconst JSON_READ_ERROR_NAMES = new Set(['Error', 'TypeError', 'SyntaxError', 'AbortError', 'TimeoutError'])\nconst JSON_READ_ERROR_CODES = new Set([\n 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'ERR_STREAM_PREMATURE_CLOSE', 'ERR_INVALID_STATE',\n 'UND_ERR_SOCKET', 'UND_ERR_BODY_TIMEOUT', 'UND_ERR_ABORTED', 'Z_DATA_ERROR', 'Z_BUF_ERROR',\n])\nconst JSON_CONTENT_TYPES = new Set([\n 'application/json', 'application/problem+json', 'text/html', 'text/plain', 'application/octet-stream',\n])\nconst JSON_CONTENT_ENCODINGS = new Set(['identity', 'gzip', 'x-gzip', 'deflate', 'br', 'zstd'])\n\n/** 原异常消息可能包含正文、账号或地址,只保留白名单标识,并有界读取 cause 链。 */\nfunction jsonReadErrorIdentifiers(error: unknown): string[] {\n const identifiers = new Set<string>()\n const seen = new Set<unknown>()\n let current = error\n for (let depth = 0; depth < 4 && isRecord(current) && !seen.has(current); depth++) {\n seen.add(current)\n if (typeof current.name === 'string' && JSON_READ_ERROR_NAMES.has(current.name)) identifiers.add(current.name)\n if (typeof current.code === 'string' && JSON_READ_ERROR_CODES.has(current.code)) identifiers.add(current.code)\n current = current.cause\n }\n return [...identifiers]\n}\n\n/** 响应头只作为线索:不据此拒绝可解析正文,也不把未经筛选的头值放入账号报告。 */\nfunction jsonResponseMetadata(response: Response): string[] {\n const metadata: string[] = []\n const contentType = response.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase()\n if (contentType) metadata.push(`内容类型:${JSON_CONTENT_TYPES.has(contentType) ? contentType : '其他'}`)\n const encoding = response.headers.get('content-encoding')?.trim().toLowerCase()\n if (encoding) metadata.push(`内容编码:${JSON_CONTENT_ENCODINGS.has(encoding) ? encoding : '其他'}`)\n return metadata\n}\n\nfunction jsonResponseFailureDetail(response: Response, failure: JsonResponseFailure): string {\n let detail: string\n if (failure.stage === 'read') {\n const reason = failure.timedOut ? '读取响应正文超时' : '响应正文读取中断'\n detail = `${reason}${failure.identifiers.length === 0 ? '' : `(${failure.identifiers.join(' / ')})`}`\n } else if (failure.stage === 'parse') {\n detail = '响应正文不是有效的 JSON(结构化数据解析失败;SyntaxError)'\n } else {\n detail = `响应 JSON 顶层应为对象,实际为${failure.shape}`\n }\n const metadata = jsonResponseMetadata(response)\n return `${detail}${metadata.length === 0 ? '' : `;${metadata.join(';')}`}`\n}\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\ninterface RequestFacts<C> {\n connection: C\n catalog: Promise<CommandCodeModel[]>\n fallbackLimit: number\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private readonly gatewayFacts = new GatewayFacts(async (source) => {\n const { status, record } = await this.fetchJson(\n `${source.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 return record\n })\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 * The dimensions and byte target this route actually puts on the wire.\n *\n * The base default answers with the NORMALIZED original (`image.width`,\n * `image.height`, `image.bytes`), which is right only for an adapter that\n * does not resize. This route always re-encodes through\n * `readImageRequest(ref, requestImageTarget(ref))` — long edge 1568, encoded\n * bytes capped at 1 MiB — so the default would over-report both dimensions\n * and bytes for every image, most visibly for Retina screenshots.\n *\n * `imageRequestPricing` above already prices at this same target; exposing it\n * here keeps the harness's own readers (the CUA screenshot path calls\n * `ctx.llm.imageRequestTarget`) consistent with what the gateway receives.\n * @param _provider - registered provider route; one route per adapter here.\n * @param _model - exact model id; the target is model-independent on this route.\n * @param image - normalized attachment whose request projection is resolved.\n * @returns the same target `readImageRequest` encodes to, before base64 expansion.\n */\n override imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): ImageRequestTarget {\n return requestImageTarget(image)\n }\n\n override async listModels(\n provider: string,\n opts?: { unfiltered?: boolean },\n ): Promise<readonly LlmModelInfo[]> {\n const connection = { ...this.deps.options() }\n const catalog = await this.gatewayFacts.refresh(connection)\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 = connection.filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess(connection)\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 = connection.visibleModels\n const allow = Array.isArray(visible) ? visible.filter((id) => typeof id === 'string' && id !== '') : []\n const overrides = connection.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 const connection = { ...this.deps.options() }\n const entry = this.gatewayFacts.knownModel(connection, model) ??\n (await this.gatewayFacts.refresh(connection, 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 unusable bodies come back without a record; only\n * a failure before receiving the response propagates to the caller.\n * 正文读取、JSON 解析与顶层结构分别诊断,不能把已收到响应后的断流当成格式错误。\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>; responseFailure?: string }> {\n const requestSignal = signal ?? AbortSignal.timeout(timeoutMs)\n const response = await this.fetchImpl(url, {\n headers,\n // A hung account endpoint must not stall the picker / usage card forever.\n signal: requestSignal,\n })\n if (!response.ok) return { status: response.status }\n let text: string\n try {\n text = await response.text()\n } catch (error: unknown) {\n const identifiers = jsonReadErrorIdentifiers(error)\n if (requestSignal.aborted) {\n for (const identifier of jsonReadErrorIdentifiers(requestSignal.reason)) {\n if (!identifiers.includes(identifier)) identifiers.push(identifier)\n }\n }\n const timedOut = identifiers.includes('TimeoutError') || identifiers.includes('ETIMEDOUT')\n || identifiers.includes('UND_ERR_BODY_TIMEOUT')\n return {\n status: response.status,\n responseFailure: jsonResponseFailureDetail(response, { stage: 'read', identifiers, timedOut }),\n }\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n return {\n status: response.status,\n // JSON.parse 的原异常会回显正文片段;只保留解析阶段与固定异常名。\n responseFailure: jsonResponseFailureDetail(response, { stage: 'parse' }),\n }\n }\n if (isRecord(parsed)) return { status: response.status, record: parsed }\n const shape = parsed === null ? '空值' : Array.isArray(parsed) ? '数组'\n : typeof parsed === 'string' ? '字符串' : typeof parsed === 'number' ? '数字' : '布尔值'\n return {\n status: response.status,\n responseFailure: jsonResponseFailureDetail(response, { stage: 'shape', shape }),\n }\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(connection: C = { ...this.deps.options() }): Promise<readonly (CommandCodeBillingAccess | undefined)[] | undefined> {\n const keys = await this.poolAccountKeys(connection)\n if (keys.length === 0) return undefined\n const apiBase = connection.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(connection: C): Promise<readonly string[]> {\n try {\n const keys = await this.deps.resolveAccountKeys?.(connection)\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(connection)]\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, entry?: CommandCodeModel): boolean {\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(connection: C, apiKey: string, model: string, entry?: CommandCodeModel): CommandCodeProtocol {\n const { apiBase, protocol: forced } = connection\n if (forced === 'cli') return forced\n if (this.routesToMessages(model, entry)) 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, capturedConnection?: C): Promise<CommandCodeUsageReport> {\n const connection = capturedConnection ?? { ...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, responseFailure } = await this.fetchJson(\n `${base}${path}`,\n headers,\n connection.requestTimeoutMs,\n )\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}${responseFailure ? `;${responseFailure}` : ''}`)\n failed.push(responseFailure ? { 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 // 与官方命令行一致:先固定组织,再并行读取余额和订阅;汇总必须等账期起点。\n // 不使用本地自然月作为替代,订阅失败时仍让汇总独立降级。\n const whoami = await getJson('/alpha/whoami')\n const { account, orgId } = parseAccountIdentity(whoami)\n if (account !== undefined) report.account = account\n const scopedPath = (path: string, since?: string): string => {\n const params = new URLSearchParams()\n if (orgId !== undefined) params.set('orgId', orgId)\n if (since !== undefined) params.set('since', since)\n const query = params.toString()\n return query ? `${path}?${query}` : path\n }\n const [credits, subscription] = await Promise.all([\n getJson(scopedPath('/alpha/billing/credits')),\n getJson(scopedPath('/alpha/billing/subscriptions')),\n ])\n const subData = subscription !== undefined && isRecord(subscription.data) ? subscription.data : undefined\n const rawStart = subData?.currentPeriodStart\n const periodStart = periodTimestampValue(rawStart)\n const validStart = periodStart > 0 && Number.isFinite(new Date(periodStart).getTime())\n // 保留上游时间的字符串/毫秒表示,仅编码查询值,不重算日期或时区。\n const since = validStart ? String(rawStart) : undefined\n const usage = await getJson(scopedPath('/alpha/usage/summary', since))\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 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: periodTimestampValue(subData?.currentPeriodEnd),\n }\n if (validStart) report.plan.currentPeriodStart = periodStart\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, connection: C = { ...this.deps.options() }): Promise<{ exceeded: boolean; resetAt: number } | undefined> {\n try {\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 stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n // 迭代器可能延后消费;调用返回时就固定连接,不能等第一次 next() 再读设置。\n const connection: C = Object.freeze({ ...this.deps.options() })\n const facts: RequestFacts<C> = {\n connection,\n // 同时捕获目录状态;旧迭代器消费不能重新绑定并撤销新来源的刷新。\n catalog: this.gatewayFacts.snapshot(connection),\n fallbackLimit: modelOutputTokenLimit(connection.apiBase, options.model),\n }\n return ownedResponseStream(options.signal, signal => this.streamWithTiming(options, signal, facts))\n }\n\n private async *streamWithTiming(options: GenerateOptions, signal: AbortSignal, facts: RequestFacts<C>): 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, signal }, timing, facts)) {\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' : signal.aborted ? 'cancelled' : 'error'\n if (outcome !== 'cancelled') 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, facts: RequestFacts<C>): AsyncIterable<StreamChunk> {\n options.signal?.throwIfAborted()\n const { connection } = facts\n const catalog = await facts.catalog\n options.signal?.throwIfAborted()\n const modelEntry = catalog.find(row => row.id === options.model)\n const initialMax = Math.min(options.maxTokens ?? Infinity, modelEntry?.maxTokens ?? facts.fallbackLimit, DEFAULT_GENERATE_MAX_TOKENS)\n const budget = { max: initialMax, sent: initialMax }\n for (let attempt = 0; ; attempt++) {\n let delivered = false\n try {\n for await (const chunk of this.streamAttempt(options, timing, connection, modelEntry, budget)) {\n delivered = true\n yield chunk\n }\n return\n } catch (error) {\n const ceiling = delivered ? undefined : outputCeilingRefusal(connection.apiBase, options.model, budget.sent, error)\n if (attempt > 0 || ceiling === undefined) throw error\n budget.max = Math.min(budget.max, ceiling)\n }\n }\n }\n\n private async *streamAttempt(\n options: GenerateOptions,\n timing: RequestTiming,\n connection: C,\n modelEntry: CommandCodeModel | undefined,\n budget: { max: number; sent: number },\n ): AsyncIterable<StreamChunk> {\n options.signal?.throwIfAborted()\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 options.signal?.throwIfAborted()\n let maxTokens = Math.min(budget.max, learnedOutputLimit(connection.apiBase, options.model))\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n // `off` carries two meanings, and only the snapshot tells them apart. The\n // host passes it as \"no reasoning strength requested\" — the Messages\n // transport's `output_config.effort` has no `none`, so it must send no\n // `output_config` at all (measured, see docs/agent-reference/\n // adapter-protocol.md). But since command-code@1.73.3 the DeepSeek V4 line\n // publishes `off` as a real level, and the official CLI sends it verbatim\n // as `reasoning_effort:\"off\"` (its body builder spreads the effort\n // whenever it is a non-empty string) instead of dropping the field. So a\n // model that LISTS `off` gets it on the wire; every other model keeps\n // dropping it, which is what the unsupported-effort path relies on.\n const declared = effort !== undefined && supported?.includes(effort) ? effort : undefined\n const reasoningEffort = effort === 'off' && declared === undefined ? undefined : declared\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, apiKey, options.model, modelEntry)\n // 反代 messages 端点对本次账号的权限拒绝(issue #84)。只活在一次 stream()\n // 调用里,并在最终错误文案中留痕:它描述的是这一条 Claude 链路,既不能\n // 缓存成整个网关的协议结论,也不该覆盖 CLI 直连自己的失败原因。\n let messagesPermissionRejection: string | undefined\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,\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 // 最后一次异步装配之后再收紧,指纹、正文及实发预算必须描述同一次连接。\n const lower = Math.min(maxTokens, learnedOutputLimit(connection.apiBase, options.model))\n if (lower < maxTokens) {\n maxTokens = lower\n budget.max = Math.min(budget.max, lower)\n if (protocol === 'cli') recordOrEmpty(body.params).max_tokens = lower\n else body.max_tokens = lower\n serializedBodies.delete(body)\n }\n budget.sent = maxTokens\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 // 第二类触发(issue #84):messages 端点用 `permission_error` 拒绝。\n // 反代转发 Claude 的那条链路可能单独对该账号失效,而同一把密钥的 CLI\n // 直连仍然可用(2026-10-14 实测:GOAT 账号请求 /alpha/generate +\n // claude-haiku-5-5 正常返回)。触发面由\n // `isMessagesPermissionRejection` 收紧到 403 加结构化 permission_error,\n // 其余权限失败继续原样上报,避免把真实限制伪装成传输问题。\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 const messagesPermissionDenied = protocol === 'messages'\n && isMessagesPermissionRejection(attempt.status, providerError)\n if (\n protocol !== 'cli'\n && (messagesPermissionDenied\n || isUpgradeRequiredError(attempt.status, attempt.errText, providerError))\n ) {\n const wasMessages = protocol === 'messages'\n if (messagesPermissionDenied) {\n messagesPermissionRejection = providerError.code ?? providerError.type\n }\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 // 权限拒绝同理:它属于刚被换下的那把密钥,不能跟着新账号继续报。\n messagesPermissionRejection = undefined\n const nextProtocol = this.resolveProtocol(connection, apiKey, options.model, modelEntry)\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(\n attempt.status, attempt.errText, attempt.retryAfterMs, providerError, messagesPermissionRejection,\n )\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 yield* settleStreamResponse(response, {\n protocol, signal: options.signal, maxTokens,\n apiBase: connection.apiBase, streamIdleTimeoutMs: connection.streamIdleTimeoutMs,\n cleanup, trace, timing, responseMetadata,\n })\n }\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 响应正文读取或解析失败,请根据下方详情排查并重试',\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 'Reading or parsing the Command Code response failed; check the details below and retry',\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/** 只有官方汇总与订阅共同确认同一起点,才展示完整账期;旧宿主和部分响应保持未知。 */\nexport function formatUsageBillingPeriod(usageStart: number | undefined, planStart: number | undefined, planEnd: number | undefined): string {\n if (usageStart === undefined || planStart !== usageStart || planEnd === undefined || usageStart <= 0 || planEnd <= usageStart) return ''\n const start = new Date(usageStart)\n const end = new Date(planEnd)\n if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime())) return ''\n return `${start.toLocaleDateString()} – ${end.toLocaleDateString()}`\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.totalCount))\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 * 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 if (usage.periodStart !== undefined) {\n report.usage.periodStart = numberField(usage, 'periodStart', 'usage.periodStart')\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 if (plan.currentPeriodStart !== undefined) {\n report.plan.currentPeriodStart = numberField(plan, 'currentPeriodStart', 'plan.currentPeriodStart')\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","/** 账号开通的双方使用契约。状态和恢复记录不携带密钥,密钥只出现在手动开通输入。 */\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport { makeBoundaryValidator, makeRemoteDescriptor, makeStrictCodec, REMOTE_PACKAGE } from './wire-shared.ts'\n\nexport interface EnrollmentInput {\n id: string\n pageId: string\n mode: 'browser' | 'manual'\n label: string\n /** 用户未填写名称时,允许使用浏览器登录返回的账号名。 */\n automaticName: boolean\n key?: string\n}\nexport type EnrollmentPhase = 'creating' | 'waiting' | 'writing' | 'naming' | 'finished' | 'cancelling' | 'cancelled' | 'failed' | 'cleanup-needed'\nexport interface EnrollmentState {\n id: string\n ref: string\n phase: EnrollmentPhase\n message: string\n authUrl?: string\n suggestedName?: string\n}\n/** 配置中的恢复日志:先登记,再写凭据;只保留引用与阶段,不保留密钥或连接身份。 */\nexport interface EnrollmentRecord {\n id: string\n ref: string\n phase: 'pending' | 'naming' | 'cleanup'\n label: string\n}\nconst guard = makeBoundaryValidator('commandcode/enrollment')\nconst phases: readonly EnrollmentPhase[] = ['creating', 'waiting', 'writing', 'naming', 'finished', 'cancelling', 'cancelled', 'failed', 'cleanup-needed']\nexport function parseEnrollmentState(value: unknown): EnrollmentState {\n const source = guard.record(value, 'state')\n const phase = source.phase\n if (!phases.includes(phase as EnrollmentPhase)) return guard.reject('phase')\n const state: EnrollmentState = {\n id: guard.stringField(source, 'id', 'id'), ref: guard.stringField(source, 'ref', 'ref'),\n phase: phase as EnrollmentPhase, message: guard.stringField(source, 'message', 'message'),\n }\n for (const field of ['authUrl', 'suggestedName'] as const) {\n if (source[field] !== undefined) state[field] = guard.stringField(source, field, field)\n }\n return state\n}\nexport function parseEnrollmentInput(value: unknown): EnrollmentInput {\n const source = guard.record(value, 'input')\n const id = guard.stringField(source, 'id', 'id')\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(id)) return guard.reject('id')\n if (source.mode !== 'browser' && source.mode !== 'manual') return guard.reject('mode')\n const input: EnrollmentInput = {\n id, pageId: parsePage(source).pageId, mode: source.mode, label: guard.stringField(source, 'label', 'label').trim(),\n automaticName: guard.booleanField(source, 'automaticName', 'automaticName'),\n }\n if (!input.label || input.label.length > 200) return guard.reject('label')\n if (input.mode === 'manual') {\n input.key = guard.stringField(source, 'key', 'key').trim()\n if (!input.key) return guard.reject('key')\n } else if (source.key !== undefined) return guard.reject('key')\n return input\n}\nexport interface EnrollmentPage { pageId: string }\nfunction parsePage(value: unknown): EnrollmentPage {\n const source = guard.record(value, 'page')\n const pageId = guard.stringField(source, 'pageId', 'pageId')\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(pageId)) return guard.reject('pageId')\n return { pageId }\n}\nexport interface EnrollmentAction extends EnrollmentPage { id: string; name?: string }\nconst actionSchema: TypertSchema<EnrollmentAction> = {\n parse(value) {\n const source = guard.record(value, 'action')\n const action: EnrollmentAction = { id: guard.stringField(source, 'id', 'id'), ...parsePage(source) }\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(action.id)) return guard.reject('id')\n if (source.name !== undefined) action.name = guard.stringField(source, 'name', 'name').trim()\n if (action.name !== undefined && (!action.name || action.name.length > 200)) return guard.reject('name')\n return action\n },\n}\nconst stateSchema = { parse: parseEnrollmentState }\nconst listSchema: TypertSchema<EnrollmentState[]> = {\n parse(value) { return Array.isArray(value) ? value.map(parseEnrollmentState) : guard.reject('list') },\n}\nexport const ENROLLMENT_DESCRIPTORS: readonly InvocationDescriptor[] = [\n ...['enrollmentBegin', 'enrollmentStatus', 'enrollmentCancel', 'enrollmentName', 'enrollmentRetry'].map((method) => ({\n ...makeRemoteDescriptor(`commandcode/${method}`, method, `${REMOTE_PACKAGE}#EnrollmentState`, stateSchema),\n parameters: [{ name: 'input', wire: 'input', source: 'json' as const,\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#${method}Input`, method === 'enrollmentBegin' ? { parse: parseEnrollmentInput } : actionSchema) }],\n })),\n { ...makeRemoteDescriptor('commandcode/enrollmentPending', 'enrollmentPending', `${REMOTE_PACKAGE}#EnrollmentStateList`, listSchema),\n parameters: [{ name: 'input', wire: 'input', source: 'json', codec: makeStrictCodec(`${REMOTE_PACKAGE}#EnrollmentPage`, { parse: parsePage }) }] },\n { ...makeRemoteDescriptor('commandcode/enrollmentWatch', 'enrollmentWatch', `${REMOTE_PACKAGE}#EnrollmentReady`, {\n parse(value: unknown) { return value === true ? true : guard.reject('ready') },\n }), mode: 'stream',\n parameters: [{ name: 'input', wire: 'input', source: 'json', codec: makeStrictCodec(`${REMOTE_PACKAGE}#EnrollmentPage`, { parse: parsePage }) }] },\n]\nexport const ENROLLMENT_REMOTE_CONTRIBUTION: TypertRemoteContribution = { package: REMOTE_PACKAGE, descriptors: ENROLLMENT_DESCRIPTORS }\n","/**\n * Host half of the Command Code Remotes (`commandcode/report`,\n * `commandcode/models`, `commandcode/prices`, `commandcode/analytics`, `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'\nimport { ENROLLMENT_DESCRIPTORS, type EnrollmentAction, type EnrollmentInput, type EnrollmentPage, type EnrollmentState } from './enrollment-wire.ts'\nimport type { AccountEnrollmentManager } from './enrollment.ts'\nimport { ANALYTICS_DESCRIPTOR, type AnalyticsQuery, type AnalyticsReport } from './analytics-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 enrollment?: AccountEnrollmentManager\n analytics?: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsReport>\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 async analytics(query: AnalyticsQuery): Promise<AnalyticsReport> {\n if (!this.deps.analytics) throw new Error('宿主不支持模型分析,请更新插件')\n return this.deps.analytics(query, this.ctx.invocation?.signal)\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 async enrollmentBegin(input: EnrollmentInput): Promise<EnrollmentState> {\n const manager = this.requireEnrollment()\n const owner = this.enrollmentOwner(input)\n if (!manager.hasPage(owner)) throw new Error('账号开通页面观察流未建立')\n return manager.begin(owner, input)\n }\n async enrollmentStatus(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().status(this.enrollmentOwner(input), input.id)\n }\n async enrollmentCancel(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().cancel(this.enrollmentOwner(input), input.id)\n }\n async enrollmentName(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().name(this.enrollmentOwner(input), input.id, input.name)\n }\n async enrollmentRetry(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().retry(this.enrollmentOwner(input), input.id, input.name)\n }\n async enrollmentPending(input: EnrollmentPage): Promise<EnrollmentState[]> { return this.requireEnrollment().pending(this.enrollmentOwner(input)) }\n async *enrollmentWatch(input: EnrollmentPage): AsyncIterable<boolean> {\n const invocation = this.ctx.invocation\n if (!invocation) throw new Error('账号开通必须从已连接的页面调用')\n const manager = this.requireEnrollment()\n const release = manager.watch(this.enrollmentOwner(input))\n let abort: (() => void) | undefined\n try {\n const ended = new Promise<void>((resolve) => {\n abort = () => resolve()\n invocation.signal.addEventListener('abort', abort, { once: true })\n if (invocation.signal.aborted) resolve()\n })\n if (invocation.signal.aborted) return\n yield true\n await ended\n } finally {\n if (abort) invocation.signal.removeEventListener('abort', abort)\n release()\n }\n }\n private enrollmentOwner(input: EnrollmentPage): string { return `${this.enrollmentPeer().id}:${input.pageId}` }\n private enrollmentPeer() {\n const invocation = this.ctx.invocation\n if (!invocation) throw new Error('账号开通必须从已连接的页面调用')\n return invocation.peer\n }\n private requireEnrollment(): AccountEnrollmentManager {\n if (!this.deps.enrollment) throw new Error('宿主不支持账号开通,请更新插件')\n return this.deps.enrollment\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, ANALYTICS_DESCRIPTOR, ...LOGIN_HOST_CONTRIBUTION.invocations, ...ENROLLMENT_DESCRIPTORS],\n })\n // The registry's own effect would outlive this fiber; withdraw the\n // contribution when the plugin unloads.\n remoteCtx.effect(() => () => void unregister(), 'dsh-commandcode-provider: usage remote')\n })\n}\n","/**\n * Host half of the Command Code browser login (the loopback flow), 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 /** 取消只能阻止尚未发出的写入;补偿者须等这些实际存储任务结束。 */\n private readonly pendingStores = new Set<Promise<void>>()\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 /** 结束验证/监听并等待已开始的写入,供账号开通过程安全补偿。 */\n async cancelAndDrain(): Promise<void> {\n this.cancel()\n await this.starting?.catch(() => undefined)\n this.cancel()\n await Promise.allSettled([...this.pendingStores])\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 START a key write or publish a status. A write already\n * handed to storage is tracked separately: cancelAndDrain() lets the owning\n * enrollment wait for it before compensation, without pretending it can be\n * aborted halfway through.\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 const store = Promise.resolve().then(() => {\n // 微任务排队期间的取消仍应阻止副作用。\n if (this.ownsAttempt(attempt)) return this.deps.storeKey(credentials, targetRef)\n })\n this.pendingStores.add(store)\n try { await store } finally { this.pendingStores.delete(store) }\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","/** 宿主拥有账号开通的副作用;页面/连接只拥有取消权。恢复日志先于凭据写入落盘。 */\nimport type { EnrollmentInput, EnrollmentRecord, EnrollmentState } from './enrollment-wire.ts'\nimport type { CommandCodeLoginCredentials } from './login.ts'\nimport type { CommandCodeLoginStatus } from './login-wire.ts'\n\ninterface Account { label?: string; apiKeyEnv?: string; apiKey?: string }\nexport interface EnrollmentConfig {\n apiKeyEnv?: string\n accounts?: Account[]\n accountEnrollmentTasks?: EnrollmentRecord[]\n credentialCleanupRefs?: string[]\n modelAccountRules?: { models: string[]; account: string }[]\n activeAccount?: string\n}\nexport interface EnrollmentSettings {\n writable: boolean\n read(): { value: EnrollmentConfig; revision: number; base?: EnrollmentConfig }\n mutate(ops: { op: 'set'; path: string[]; value: unknown }[], revision: number): Promise<void>\n}\nexport interface EnrollmentLogin {\n begin(ref?: string): Promise<CommandCodeLoginStatus>\n status(): CommandCodeLoginStatus\n onChange(listener: () => void): () => void\n cancelAndDrain(): Promise<void>\n dispose(): void\n}\nexport interface EnrollmentDeps {\n settings(): EnrollmentSettings | undefined\n describe(ref: string): Promise<{ configured: boolean; writable: boolean }>\n set(ref: string, key: string): Promise<void>\n unset(ref: string): Promise<void>\n login(store: (credentials: CommandCodeLoginCredentials) => Promise<void>): EnrollmentLogin\n}\ninterface Task {\n owner: string\n state: EnrollmentState\n cancelled: boolean\n writeStarted?: boolean\n cleanupStarted?: boolean\n work?: Promise<void>\n flow?: EnrollmentLogin\n}\nconst terminal = (state: EnrollmentState) => ['finished', 'cancelled', 'failed', 'cleanup-needed', 'naming'].includes(state.phase)\n\nexport class AccountEnrollmentManager {\n private readonly tasks = new Map<string, Task>()\n private writes: Promise<unknown> = Promise.resolve()\n private closed = false\n private readonly pages = new Set<string>()\n constructor(private readonly deps: EnrollmentDeps) {}\n /** 每页独立的持续调用才代表页面生命期;宿主的 operator Peer 由所有浏览器共享。 */\n watch(owner: string): () => void {\n if (this.closed || this.pages.has(owner)) throw new Error('账号开通页面已关闭或重复连接')\n this.pages.add(owner)\n return () => { this.pages.delete(owner); this.disconnect(owner) }\n }\n hasPage(owner: string): boolean { return this.pages.has(owner) }\n\n /** begin 不等待整个过程;客户端预先生成的 id 让早到的取消也能生效。 */\n begin(owner: string, input: EnrollmentInput): EnrollmentState {\n this.prune()\n const existing = this.tasks.get(input.id)\n if (existing) return this.owned(owner, input.id).state\n if (this.closed) throw new Error('账号开通服务已关闭')\n if (this.records().some((record) => record.id === input.id)) throw new Error('已有未完成记录,请先处理')\n const task: Task = { owner, cancelled: false, state: { id: input.id, ref: '', phase: 'creating', message: '正在创建账号' } }\n this.tasks.set(input.id, task)\n task.work = this.run(task, input).catch(() => {\n task.state = { ...task.state, phase: 'cleanup-needed', message: '收尾未完成,请重试' }\n })\n return task.state\n }\n status(owner: string, id: string): EnrollmentState {\n const task = this.tasks.get(id)\n if (task) return this.owned(owner, id).state\n const record = this.records().find((record) => record.id === id)\n if (!record) throw new Error('账号开通过程不存在')\n return this.recovered(record)\n }\n pending(owner: string): EnrollmentState[] {\n return this.records().filter((record) => {\n const task = this.tasks.get(record.id)\n return !task || ((task.owner === '' || task.owner === owner) && terminal(task.state))\n })\n .map((record) => this.tasks.get(record.id)?.state ?? this.recovered(record))\n }\n /** 离开已登录的待命名过程等同接受已有名称,其余阶段等待写入结束再补偿。 */\n async cancel(owner: string, id: string): Promise<EnrollmentState> {\n this.prune()\n let task = this.tasks.get(id)\n if (!task) {\n if (this.records().some((record) => record.id === id)) return this.retry(owner, id)\n // 取消先于 begin 到达时留下墓碑,不能随后创建账号。\n task = { owner, cancelled: true, state: { id, ref: '', phase: 'cancelled', message: '已取消' } }\n this.tasks.set(id, task)\n return task.state\n }\n task = this.owned(owner, id)\n if (task.state.phase === 'naming') return this.name(owner, id)\n if (terminal(task.state)) return task.state\n task.cancelled = true\n task.state = { ...task.state, phase: 'cancelling', message: '正在等待写入结束并清理' }\n await task.flow?.cancelAndDrain()\n await task.work\n return task.state\n }\n disconnect(owner: string): void {\n for (const [id, task] of this.tasks) if (task.owner === owner) void this.cancel(owner, id).catch(() => {}).finally(() => { task.owner = '' })\n }\n dispose(): void { this.closed = true; for (const task of this.tasks.values()) this.disconnect(task.owner) }\n\n async name(owner: string, id: string, name?: string): Promise<EnrollmentState> {\n const task = this.tasks.get(id)\n if (task) this.owned(owner, id)\n const record = this.records().find((item) => item.id === id)\n if (!record && task?.state.phase === 'finished') return task.state\n if (!record || (record.phase !== 'naming' && task?.state.phase !== 'naming')) throw new Error('账号尚未进入待命名阶段')\n try {\n await this.change((value) => {\n const accounts = value.accounts ?? []\n if (!accounts.some((account) => account.apiKeyEnv === record.ref)) throw new Error('账号已被移除')\n return {\n ...(name?.trim() ? { accounts: accounts.map((account) => account.apiKeyEnv === record.ref ? { ...account, label: name.trim() } : account) } : {}),\n accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).filter((item) => item.id !== id),\n }\n })\n return this.publish(task, { id, ref: record.ref, phase: 'finished', message: '账号开通完成' })\n } catch {\n return this.publish(task, { id, ref: record.ref, phase: 'naming', message: '账号已登录,名称保存失败,请重试或接受已有名称', ...(name ? { suggestedName: name } : {}) })\n }\n }\n async retry(owner: string, id: string, name?: string): Promise<EnrollmentState> {\n const existing = this.tasks.get(id)\n if (existing) {\n this.owned(owner, id)\n await existing.work\n if (!terminal(existing.state)) throw new Error('账号开通仍在进行')\n }\n const record = this.records().find((item) => item.id === id)\n if (!record) return this.status(owner, id)\n if (record.phase === 'naming' || existing?.state.phase === 'naming') return this.name(owner, id, name)\n const task = existing ?? { owner, cancelled: true, writeStarted: true, state: this.recovered(record) }\n this.tasks.set(id, task)\n task.work = this.cleanup(task).catch(() => { task.state = { ...task.state, phase: 'cleanup-needed', message: '清理未完成,请重试' } })\n await task.work\n return task.state\n }\n private async run(task: Task, input: EnrollmentInput): Promise<void> {\n try {\n await this.change(async (value) => {\n const base = value.apiKeyEnv ?? 'COMMANDCODE_API_KEY'\n const occupied = new Set([base, ...(value.accounts ?? []).map((account) => account.apiKeyEnv), ...(value.credentialCleanupRefs ?? []), ...(value.accountEnrollmentTasks ?? []).map((item) => item.ref)])\n let n = 2\n let ref = ''\n // 配置未引用的环境/存储密钥也属于已占用引用,不能用新开通覆盖。\n for (let attempt = 0; attempt < 128; attempt++, n++) {\n if (occupied.has(`${base}_${n}`)) continue\n const candidate = `${base}_${n}`\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(candidate)) throw new Error('凭据引用无效')\n const info = await this.deps.describe(candidate)\n if (info.configured) continue\n if (!info.writable) throw new Error('凭据不可写')\n ref = candidate\n break\n }\n if (!ref) throw new Error('没有可用凭据引用')\n task.state = { ...task.state, ref }\n return {\n accounts: [...(value.accounts ?? []), { label: input.label, apiKeyEnv: ref }],\n accountEnrollmentTasks: [...(value.accountEnrollmentTasks ?? []), { id: input.id, ref, phase: 'pending', label: input.label }],\n }\n })\n if (task.cancelled) return await this.cleanup(task)\n const info = await this.deps.describe(task.state.ref)\n // 分配引用不应覆盖环境或其他凭据;真正写入仍由凭据服务执行权限检查。\n if (info.configured || !info.writable) throw new Error('凭据引用已占用或不可写')\n let suggested: string | undefined\n if (input.mode === 'manual') await this.store(task, input.key!)\n else {\n const flow = this.deps.login(async (credentials) => { await this.store(task, credentials.apiKey) })\n task.flow = flow\n const result = await new Promise<CommandCodeLoginStatus>((resolve, reject) => {\n const off = flow.onChange(() => {\n const status = flow.status()\n if (status.state === 'success' || status.state === 'failed') { off(); resolve(status) }\n })\n void flow.begin(task.state.ref).then((status) => {\n if (!task.cancelled && status.state === 'waiting') task.state = { ...task.state, phase: 'waiting', message: '等待浏览器登录', ...(status.authUrl ? { authUrl: status.authUrl } : {}) }\n if (task.cancelled) void flow.cancelAndDrain()\n }, (error: unknown) => { off(); reject(error) })\n })\n if (result.state !== 'success') throw new Error('浏览器登录未完成')\n suggested = input.automaticName ? result.userName?.trim() : undefined\n }\n if (task.cancelled) return await this.cleanup(task)\n // 先登记已登录事实,再尝试命名。命名失败绝不走删除凭据的补偿分支。\n task.state = { ...task.state, phase: 'naming', message: '账号已登录,正在保存名称', ...(suggested ? { suggestedName: suggested } : {}) }\n try {\n await this.change((value) => ({ accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).map((item) => item.id === input.id ? { ...item, phase: 'naming', label: suggested || item.label } : item) }))\n } catch {\n if (task.state.phase === 'finished') return\n task.state = { ...task.state, message: '账号已登录,名称保存失败,请重试或接受已有名称' }\n return\n }\n await this.name(task.owner, input.id, suggested)\n } catch {\n // 清理本身失败必须留待用户重试,不能被开通失败分支再次自动执行。\n if (task.cleanupStarted) throw new Error('账号清理未完成')\n await task.flow?.cancelAndDrain()\n if (task.state.ref && this.records().some((item) => item.id === task.state.id)) await this.cleanup(task)\n else task.state = { ...task.state, phase: task.cancelled ? 'cancelled' : 'failed', message: task.cancelled ? '已取消' : '账号开通失败,未创建账号' }\n } finally { task.flow?.dispose() }\n }\n private async store(task: Task, key: string): Promise<void> {\n if (task.cancelled) throw new Error('已取消')\n task.state = { ...task.state, phase: 'writing', message: '正在保存凭据' }\n task.writeStarted = true\n await this.deps.set(task.state.ref, key)\n if (!(await this.deps.describe(task.state.ref)).configured) throw new Error('凭据写入未确认')\n }\n private async cleanup(task: Task): Promise<void> {\n task.cleanupStarted = true\n const { id, ref } = task.state\n const snapshot = this.settings().read()\n if ((snapshot.value.apiKeyEnv ?? 'COMMANDCODE_API_KEY') === ref || snapshot.base?.accounts?.some((account) => account.apiKeyEnv === ref)) throw new Error('不能清理默认或继承账号')\n await this.change((value) => {\n const record = (value.accountEnrollmentTasks ?? []).find((item) => item.id === id)\n if (!record || record.phase === 'naming') throw new Error('不能清理已登录账号')\n return {\n accounts: (value.accounts ?? []).filter((account) => account.apiKeyEnv !== ref),\n modelAccountRules: (value.modelAccountRules ?? []).filter((rule) => rule.account !== ref),\n ...(value.activeAccount === ref ? { activeAccount: '' } : {}),\n credentialCleanupRefs: [...new Set([...(value.credentialCleanupRefs ?? []), ref])],\n accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).map((item) => item.id === id ? { ...item, phase: 'cleanup' } : item),\n }\n })\n const value = this.settings().read().value\n if ((value.apiKeyEnv ?? 'COMMANDCODE_API_KEY') === ref || (value.accounts ?? []).some((account) => account.apiKeyEnv === ref) || (value.modelAccountRules ?? []).some((rule) => rule.account === ref) || value.activeAccount === ref) throw new Error('引用仍被使用,不能清理')\n const info = await this.deps.describe(ref)\n if (info.configured && task.writeStarted) {\n if (!info.writable) throw new Error('凭据不可清理')\n await this.deps.unset(ref)\n if ((await this.deps.describe(ref)).configured) throw new Error('凭据删除未确认')\n }\n await this.change((current) => ({\n accountEnrollmentTasks: (current.accountEnrollmentTasks ?? []).filter((item) => item.id !== id),\n credentialCleanupRefs: (current.credentialCleanupRefs ?? []).filter((item) => item !== ref),\n }))\n task.state = { id, ref, phase: task.cancelled ? 'cancelled' : 'failed', message: task.cancelled ? '已取消并清理' : '开通失败,已清理临时账号' }\n }\n private settings(): EnrollmentSettings {\n const settings = this.deps.settings()\n if (!settings?.writable) throw new Error('设置服务不可写')\n return settings\n }\n private records(): EnrollmentRecord[] { return this.deps.settings()?.read().value.accountEnrollmentTasks ?? [] }\n private change(patch: (value: EnrollmentConfig) => Record<string, unknown> | Promise<Record<string, unknown>>): Promise<void> {\n const work = this.writes.catch(() => {}).then(async () => {\n const settings = this.settings()\n const { value, revision } = settings.read()\n const fields = await patch(value)\n await settings.mutate(Object.entries(fields).map(([key, item]) => ({ op: 'set', path: [key], value: item })), revision)\n })\n this.writes = work\n return work\n }\n private owned(owner: string, id: string): Task {\n const task = this.tasks.get(id)\n if (!task || (task.owner !== '' && task.owner !== owner)) throw new Error('不能操作其他连接的开通过程')\n if (task.owner === '') task.owner = owner\n return task\n }\n private publish(task: Task | undefined, state: EnrollmentState): EnrollmentState { if (task) task.state = state; return state }\n /** 只淘汰已完成且没有恢复日志的旧状态,活跃过程和未收尾事实始终保留。 */\n private prune(): void {\n if (this.tasks.size < 256) return\n const recorded = new Set(this.records().map((record) => record.id))\n for (const [id, task] of this.tasks) {\n if (this.tasks.size < 256) break\n if (terminal(task.state) && !recorded.has(id) && !this.pages.has(task.owner)) this.tasks.delete(id)\n }\n }\n private recovered(record: EnrollmentRecord): EnrollmentState {\n return { id: record.id, ref: record.ref, phase: record.phase === 'naming' ? 'naming' : 'cleanup-needed', message: record.phase === 'naming' ? '已登录账号等待确认名称' : '账号开通收尾未完成,请重试', ...(record.phase === 'naming' ? { suggestedName: record.label } : {}) }\n }\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 /** 使用搜索已捕获的网关解析账号,探测不能在等待后转到另一个网关。 */\n resolveKey(apiBase?: string): 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, apiBase)\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, apiBase: string): Promise<string> {\n let key: string | undefined\n try {\n key = await this.deps.resolveKey(apiBase)\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 every\n * supported engine ships `~3.18.4` or `~3.18.5-alpha.1`, so the\n * method is 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 { createAnalyticsReader } from './analytics-history.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, captureAccountSelection, type CommandCodeAccountSelection } 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 { AccountEnrollmentManager, type EnrollmentSettings } from './enrollment.ts'\nimport type { EnrollmentRecord } from './enrollment-wire.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 accountEnrollmentTasks?: EnrollmentRecord[]\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 accountEnrollmentTasks: z.array(z.object({\n id: z.string(), ref: z.string().role('credential-ref'),\n phase: z.union(['pending', 'naming', 'cleanup']), label: z.string(),\n })),\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 accountSelection?: CommandCodeAccountSelection\n}\n\n/** 宿主入口总是携带账号定义;程序化连接解析仍兼容既有返回形状。 */\ntype HostCommandCodeOptions = ResolvedCommandCodeOptions & { accountSelection: CommandCodeAccountSelection }\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 = (): HostCommandCodeOptions => {\n const raw = current()\n return { ...resolveAdapterOptions(raw), accountSelection: captureAccountSelection({\n slots: slots(raw), preferredId: preferredId(raw), modelAccountRules: raw.modelAccountRules ?? [],\n }) }\n }\n\n // 账号定义与连接同步捕获;本次内部轮换固定定义,新调用读取新配置。\n const slots = (raw: Config = current()): CommandCodeAccountSlot[] => {\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 // 临时账号即使已写入密钥,也不能在开通完成前进入轮转池。\n if (raw.accountEnrollmentTasks?.some((task) => task.ref === refName && task.phase !== 'naming')) continue\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 // 固定账号与账号列表来自同一次配置读取,避免等待后拼接不同版本。\n const preferredId = (config: Config = current()): string | undefined => {\n const raw = config.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 seam owns the layer order, and that order is engine-dependent: the\n // provider-managed store wins over the inherited environment from\n // 0.2.1-alpha.3 on, where the environment used to win. This call does not\n // care which — it asks for the resolved value — but a miss here is\n // genuinely unconfigured, not \"absent from the store\".\n const hit = await credentials.resolve(ref)\n return hit?.value\n }\n // No service means the headless profile, which disables the credentials\n // line on purpose: only the launch environment (process, project `.env`,\n // `$DSH_HOME/.env`) is left, so a key saved only in the product store is\n // deliberately invisible to a one-shot run.\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 // 所有调用者显式持有连接;恢复探测与健康状态不能使用等待后才读取的新网关。\n const scopedPool = (connection: HostCommandCodeOptions): CommandCodeAccountPool => pool.scope({\n apiBase: connection.apiBase,\n ...connection.accountSelection,\n probeWindow: (key) => adapter.probeWindowLimits(key, connection),\n })\n\n const resolveApiKey = async (connection: HostCommandCodeOptions, model?: string): Promise<string> => {\n const resolved = await scopedPool(connection).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. The headless profile mounts no credentials service, so a'\n + ' key saved only in the store never reaches it: export the variable or put it in a'\n + ' .env file for those runs.',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter: CommandCodeAdapter<HostCommandCodeOptions> = 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: HostCommandCodeOptions,\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 const accounts = scopedPool(connection)\n if (rejection !== 'unavailable') accounts.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 accounts.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 (connection): Promise<readonly string[]> => {\n const accounts = await scopedPool(connection).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 const connection = options()\n const accounts = scopedPool(connection)\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 // 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 accounts.activeAccount()\n // 先完成共享恢复,再读健康事实;不能用探测前的标记展示已恢复账号。\n const described = await accounts.describeAccounts()\n const byId = new Map(described.map((account) => [account.slot.id, account]))\n const entries = await Promise.all(connection.accountSelection.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, connection)\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 let enrollmentSettings: EnrollmentSettings | undefined\n const enrollment = new AccountEnrollmentManager({\n settings: () => enrollmentSettings,\n describe: async (ref) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n return credentials.describe(credentialRef(ref))\n },\n set: async (ref, key) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n await credentials.set(credentialRef(ref), key)\n },\n unset: async (ref) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n await credentials.unset(credentialRef(ref))\n },\n login: (storeKey) => new CommandCodeLoginFlow({ apiBase: () => options().apiBase, storeKey }),\n })\n ctx.effect(() => () => enrollment.dispose(), 'dsh-commandcode-provider: account enrollment')\n applyUsageRemote(ctx, { adapter, reports: usageReports, login: loginFlow, enrollment, listModels: catalogForEditors, analytics: createAnalyticsReader(ctx, adapter) })\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 (apiBase) => {\n const connection = options()\n if (apiBase !== undefined) connection.apiBase = apiBase\n const resolved = await scopedPool(connection).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 const settings = settingsCtx.settings\n enrollmentSettings = {\n get writable() { return settings.writable },\n read: () => {\n // 宿主读取完整值,再按字段修改,避免把被遮蔽的组合配置密钥覆盖掉。\n const descriptor = settings.describe().find((item) => item.ns === NS)\n if (!descriptor) throw new Error('账号设置不存在')\n return { value: descriptor.value as Config, revision: descriptor.revision, ...(descriptor.base ? { base: descriptor.base as Config } : {}) }\n },\n mutate: (ops, revision) => settings.mutate(NS, ops, revision),\n }\n settingsCtx.effect(() => () => { enrollmentSettings = undefined }, 'dsh-commandcode-provider: enrollment settings')\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","tokensOf","record","counts","counts","parseCatalog","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/analytics.ts","../src/wire-shared.ts","../src/analytics-wire.ts","../src/analytics-history.ts","../src/response-encoding.ts","../src/timeout-limits.ts","../src/model-visibility.ts","../src/transient-retry.ts","../src/accounts.ts","../src/provider-errors.ts","../src/stream-trace.ts","../src/stream-response.ts","../src/image-request.ts","../src/image-tokens.ts","../src/request-timing.ts","../src/gateway-facts.ts","../src/adapter.ts","../src/command-locales.ts","../src/display-format.ts","../src/commands.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/enrollment-wire.ts","../src/usage-remote.ts","../src/login.ts","../src/enrollment.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 * Token buckets contributed by summarization calls, already folded into\n * `groups` but deliberately NOT part of the harness's own `tokenUsage`\n * projection.\n *\n * Compaction issues its own `ctx.llm.stream()` call, so its cost is real\n * spend, but it produces no `assistant/message` or `assistant/attempt` event\n * — the only two the harness meter folds (see `token-meter/src/usage-projection.ts`).\n * The summary therefore lands in this projection alone, and the composer\n * readout subtracts this field before asserting that both projections\n * describe the same durable cut. Without the split the equality check fails\n * and the whole readout disappears whenever a session compacts.\n *\n * Always present: `parseState` backfills it to zero for state written before\n * this field existed.\n */\n summaryTokens: CostTokens\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.82.1) 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.82.1 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 //\n // `off` is NOT a strength: it is the DeepSeek family's \"do not think\" level\n // (command-code@1.73.3), and the official CLI sends it verbatim as\n // `reasoning_effort:\"off\"` rather than omitting the field. Its presence here\n // is what makes the adapter treat `off` as a real choice for these models\n // instead of the host's \"no effort requested\" signal - see the lookup in\n // `stream()`. No other family lists it: the Messages transport's\n // `output_config.effort` has no such value, so `off` stays dropped there.\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 // Still a three-level set at 1.74.3: unlike its V4 siblings, this one never\n // gained `off`, so thinking cannot be switched off on this variant.\n 'deepseek/deepseek-v4-flash-fast': ['low', 'high', 'max'],\n // command-code@1.53.0.\n 'deepseek/deepseek-v4.1-flash': ['off', 'low', 'high', 'max'],\n // command-code@1.67.0; the same four-level set as its `deepseek-v4.1-flash`\n // sibling, whose throughput-focused variant this is.\n 'deepseek/deepseek-v4.1-flash-fast': ['off', 'low', 'high', 'max'],\n // command-code@1.73.3 added `off` (\"Allow disabling thinking for DeepSeek\n // models\") to the DeepSeek V4 line and the 4.1 pair above - but NOT to\n // `deepseek-v4-flash-fast`, which the 1.74.3 table still ships at three.\n 'deepseek/deepseek-v4-flash': ['off', 'high', 'max'],\n 'deepseek/deepseek-v4-flash-vision-exp': ['off', 'high', 'max'],\n 'deepseek/deepseek-v4-pro': ['off', 'high', 'max'],\n // command-code@1.82.0 (\"Gemini Argon\") and the only registry addition in the\n // 1.81.0 -> 1.82.1 train. Three selectable levels, the same set the Gemini\n // Flash family carries.\n 'google/gemini-4-argon': ['low', 'medium', 'high'],\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.80.0 (\"Add Muse Wonder\"): the Muse family's newest member and\n // the only registry addition in the 1.79.2 -> 1.81.0 train. It carries the\n // same four-level set as Muse Spark 1.1/1.2 (no `max`).\n 'meta/muse-wonder-1.0': ['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 // `stealth/space-bunny-alpha` (command-code@1.65.0, `max` added by 1.73.4)\n // was RETIRED by command-code@1.74.3: the artifact drops its own four-level\n // effort list and ships the row as `hidden` instead, the official Desktop\n // changelog for 2026-10-06 says \"Remove Space Bunny Alpha from the model\n // picker\", and the model is gone from `/provider/v1/models` as well as the\n // pricing page.\n // `stealth/pixel-canary` (the second stealth preview, `xhigh` instead of\n // `high`) was RETIRED by command-code@1.73.1: the CLI hides it behind\n // `isPixelCanaryEnded()` (past 2026-10-01T06:00:00Z) and it is gone from\n // `/provider/v1/models` and the pricing page.\n // command-code@1.77.0 closed both out here as well: neither carries an effort\n // list any more, both sit in the CLI's non-selectable set (its\n // `listSelectableModelIds()` filters them out), and both left the ZDR\n // exclusion set — so no table in this file names either one any more.\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.82.2. The paid graduation of the `ling-3.1-flash:free`\n // promo this table used to carry: that row is retired in the same release\n // (the CLI ships it `hidden`, it lost its effort list, and it is gone from\n // both `/provider/v1/models` and the pricing page), so it is named nowhere in\n // this file any more. Three selectable levels, text-only input, Go tier —\n // like its `mistral-large-4` neighbour, and unlike the free stealth previews.\n 'inclusionai/ling-3.1-flash': ['low', 'medium', 'high'],\n // command-code@1.75.0 (\"Add Mistral Large 4\") — the only model the 1.74.3 ->\n // 1.77.0 train added. A three-level set; Vision per the official registry and\n // the CLI's inputModalities:[\"text\",\"image\"] (see `KNOWN_IMAGE_MODELS`), and\n // Go-tier availability (see `KNOWN_PLANS`).\n 'mistral/mistral-large-4': ['low', 'medium', 'high'],\n // command-code@1.78.0 (\"Add Claude Haiku 5.5 (Pro and above)\") and 1.79.0\n // (\"Add Glyph Cluster as a free model, 100 requests a day\") are the only\n // registry additions in the 1.77.0 -> 1.79.1 train. Both carry selectable\n // efforts, so neither belongs in KNOWN_THINKING_MODELS; Claude Haiku 5.5 takes\n // the Claude family's five-level set, while the free Glyph Cluster preview\n // stops at four and offers no `max`.\n 'claude-haiku-5-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'stealth/glyph-cluster:free': ['low', 'medium', 'high', '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 // command-code@1.78.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'claude-haiku-5-5',\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 // command-code@1.82.0; Vision per the official registry, the CLI's\n // inputModalities:[\"text\",\"image\"] and the docs page's \"Text input, Vision,\n // Reasoning\" capability label.\n 'google/gemini-4-argon',\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 // command-code@1.80.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\",\"file\"] — the only model in this catalog\n // that also declares the `file` modality.\n 'meta/muse-wonder-1.0',\n // command-code@1.75.0; Vision per the official registry and the CLI's\n // inputModalities:[\"text\",\"image\"].\n 'mistral/mistral-large-4',\n 'moonshotai/Kimi-K2.5',\n 'moonshotai/Kimi-K2.6',\n 'moonshotai/Kimi-K2.7-Code',\n 'moonshotai/Kimi-K2.7-Code-Highspeed',\n 'moonshotai/Kimi-K3',\n 'sakana/fugu-ultra',\n // command-code@1.65.0; Vision per the official registry and inputModalities.\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.82.1` `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 dropped\n * `meituan/LongCat-2.0`, which sat in `modelSupportsZdr` alone through\n * 1.73.0; the 1.74.3 table lists it in NEITHER set, so as of this snapshot it\n * is no longer excluded. The official docs (commandcode.ai/docs/resources/\n * zdr) put coverage 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), 1.67.0 added one\n * (`deepseek/deepseek-v4.1-flash-fast`), 1.68.0 changed nothing, and 1.74.1\n * removed one (`meituan/LongCat-2.0`). The 1.74.2/1.74.3 pair changed nothing\n * here either (22 members as of 2026-10-06); 1.77.0 dropped the two retired\n * stealth previews, back to 20 members as of 2026-10-07, and 1.79.0 added the\n * free `stealth/glyph-cluster:free` preview — 21 members as of 2026-10-08.\n *\n * 1.77.0 also settled the two retired stealth previews (see `KNOWN_EFFORTS`):\n * 1.74.3 still named both in the ZDR anchors, so they stayed listed here on\n * purpose — an id a stale session named still got a truthful answer. The 1.77.0\n * artifact names neither in its exclusion set and filters both out of\n * `listSelectableModelIds()`, so they are pruned along with the rest of the\n * tables and `supportsZeroDataRetention` now answers TRUE for them, matching\n * what the current CLI says.\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 retired stealth\n // previews, the pricing page carries no ZDR note for this row — the artifact\n // is the evidence, and the sibling `deepseek-v4.1-flash` stays ZDR-covered.\n 'deepseek/deepseek-v4.1-flash-fast',\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 // command-code@1.80.0. The CLI's exclusion set names it, so a ZDR request for\n // it is refused; the pricing page carries no ZDR note for this row, so the\n // artifact is the evidence. 22 members as of 1.82.1 — Gemini 4 Argon, the\n // only registry addition in the 1.81.0 -> 1.82.1 train, is NOT in the set.\n 'meta/muse-wonder-1.0',\n 'minimax/minimax-m3-free',\n 'poolside/laguna-s-2.1-free',\n 'sakana/fugu-ultra',\n // command-code@1.79.0. The free Glyph Cluster preview is the ONE entry here\n // whose exclusion the official pricing page states in prose rather than\n // leaving to the artifact: its tip reads \"Free while the preview lasts. Up to\n // 100 requests a day. Not routed under ZDR.\" The CLI's own exclusion set\n // carries the same membership.\n 'stealth/glyph-cluster:free',\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 89\n * catalog ids as of 2026-10-15. Each row carries a comment naming the entry it\n * came from.\n *\n * One of those 76 rests on more than a vendor lookup, hand-recorded in the\n * script's `MANUAL_CEILINGS`: `inclusionai/ling-3.0-flash-sante:free` (32768)\n * lost both its vendor row and its unanimous third-party vote (vercel files\n * 32000), and is pinned so a regeneration cannot drop a live model's ceiling\n * back to the default. (`gpt-6.1-sol` (128000) needs no pin — OpenAI's own row\n * carries it and every other provider carrying the id agrees.) All are still\n * correctable — a stricter gateway costs one refused request, and\n * `streamRequest()` remembers what the endpoint said.\n *\n * The 13 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-haiku-5-5', 128000],\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 // google\n ['google/gemini-4-argon', 32768],\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 // manual: no vendor row and no longer unanimous (vercel 32000); Ling family ceiling 32768, see MANUAL_CEILINGS\n ['inclusionai/ling-3.0-flash-sante: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 // meta\n ['meta/muse-wonder-1.0', 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 // 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.82.1 (2026-10-14): 89 catalog\n * ids at 54/64/79/87/89 cumulative, a strict superset chain. Mistral Large 4\n * (1.75.0) was the only addition at the 1.77.0 check; the 1.78.0/1.79.0 pair\n * added Claude Haiku 5.5 at Pro and the free Glyph Cluster preview at Go.\n * 1.79.2 lowers Haiku 5.5's minimum plan to GOAT; 1.80.0 adds Muse Wonder at\n * Max; 1.82.0 adds Gemini 4 Argon at Pro and nothing else moves. Every other\n * tier is unchanged.\n * The only removals since 1.49.0 are the two retired stealth previews (Pixel\n * Canary at 1.73.1, Space Bunny Alpha at 1.74.3). Per-entry tags below name the\n * releases that added or moved 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.82.2; the paid successor of the retired\n // `ling-3.1-flash:free` promo. The pricing page's embedded availability\n // grants every tier (individual-go through teams-pro) — the \"all\":true shape\n // shared with its `ling-3.0-flash-sante:free` predecessor.\n 'inclusionai/ling-3.1-flash': '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 // command-code@1.75.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 above.\n 'mistral/mistral-large-4': '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.79.0 (\"Add Glyph Cluster as a free model, 100 requests a\n // day\"); the pricing page's embedded availability grants every tier\n // (individual-go through teams-pro) — the \"all\":true shape shared by the Ling\n // free models above. Its zero-credit deal (see KNOWN_DEALS) also makes it lead\n // the picker.\n 'stealth/glyph-cluster:free': '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 (10 more) ---\n // command-code@1.79.2 lowers the 1.78.0 Pro gate to GOAT: individual-go\n // remains false, individual-goat and all higher tiers are true.\n 'claude-haiku-5-5': 'goat',\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 (15 more) ---\n 'claude-haiku-4-5-20251001': 'pro',\n 'claude-sonnet-4-6': 'pro',\n 'claude-sonnet-5': 'pro',\n // command-code@1.82.0; individual-go / go-v1 / goat all false, Pro and every\n // higher tier true — one tier above the Gemini Flash family above it.\n 'google/gemini-4-argon': '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 (2) ---\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 // command-code@1.80.0; the same Max-and-above availability as `gpt-6.1-sol`\n // (every lower tier false, only individual-max / individual-ultra /\n // teams-pro true) and the note \"Available on Max and above.\"\n 'meta/muse-wonder-1.0': '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 // `inclusionai/ling-3.1-flash:free` (command-code@1.70.0, 100% off \"Free\n // while it lasts\", the `ling-3.0-flash-sante:free` successor) left this map\n // on 2026-10-15: command-code@1.82.2 ships the row as `hidden`, drops its\n // selectable efforts, and the model is gone from both\n // `/provider/v1/models` and the pricing page — the same retirement path\n // `meituan/LongCat-2.0:free` and `stealth/space-bunny-alpha` took. Its paid\n // graduation `inclusionai/ling-3.1-flash` is priced normally and carries no\n // deal.\n // command-code@1.79.0 (\"Add Glyph Cluster as a free model, 100 requests a\n // day\"): 100% off \"Free while the preview lasts\", the same 100-requests-a-day\n // cap as its Ling predecessors and likewise no published end date, so no\n // `expiresAt`. The pricing page publishes it at a literal zero, which\n // `modelPriceTable()` serves from this deal, so it gets no row in the vendored\n // price table either. Unlike those free models it is NOT ZDR-routed — the\n // page's own tip says so outright (see `KNOWN_NON_ZDR_MODELS`).\n 'stealth/glyph-cluster:free': { label: 'FREE', free: true },\n // `stealth/space-bunny-alpha` (command-code@1.65.0, 100% off \"Free while the\n // stealth preview lasts\", auto-applied, no published end date) left this map\n // on 2026-10-06: command-code@1.74.3 hides the model, the catalog and the\n // pricing page dropped it, and the official Desktop changelog says \"Remove\n // Space Bunny Alpha from the model picker\". Its twin Pixel Canary left the\n // same way when command-code@1.73.1 retired it.\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-haiku-5-5', rates: [0.1, 0.5, 0.01, 0.125], allowance: { go: 6, goat: 20, pro: 30 }, contextTiers: [{\"maxContext\":100000,\"rates\":[0.1,0.5,0.01,0.125]},{\"rates\":[0.5,2.5,0.05,0.625]}] },\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.1, 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: 100, pro: 100 } },\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: 'gemini-4-argon', rates: [2, 10, 0.1], allowance: { go: 6, goat: 20, pro: 20 } },\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: 100, pro: 100 } },\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: 'ling-3.1-flash', rates: [0.3, 0.9, 0.06], allowance: { go: 6, 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: 'mistral-large-4', rates: [1.36, 4.18, 0.14], allowance: { go: 10, goat: 40, pro: 50 } },\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: 'muse-wonder-1.0', rates: [4, 20, 0.2], allowance: { go: 6, goat: 20, pro: 20 } },\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-max-prime', rates: [4, 12, 0.5, 5], allowance: { go: 6, 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\n/** 工具参数可为对象或完整 JSON 字符串;不把未完成的字符串片段当作完整参数。 */\n\nexport function 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","/** 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/** The four buckets of an already-parsed record, or undefined when one is missing. */\nfunction costTokensOf(value: unknown): CostTokens | undefined {\n const t = record(value)\n if (!t || !COST_TOKEN_KEYS.every(k => finite(t[k]))) return undefined\n return t as unknown as CostTokens\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)\n return !!g && typeof g.provider === 'string' && typeof g.model === 'string'\n && (g.at === null || finite(g.at)) && finite(g.contextTokens) && costTokensOf(g.tokens) !== undefined\n }\n const sel = record(s.selection), last = record(s.last)\n // `summaryTokens` arrived with the compaction-summary fold. State written\n // before it carries no such key, so backfill zero instead of rejecting:\n // refusing would make every already-persisted session lose its readout on\n // upgrade. A present-but-malformed value is still an error.\n const summaryTokens = facts.summaryTokens === undefined ? zeroCostTokens() : costTokensOf(facts.summaryTokens)\n if (summaryTokens === undefined\n || !(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), facts: { ...(facts as unknown as SessionCostFacts), summaryTokens } }\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 /** Groups that still carry tokens; a retry that replaced a group can drive one to zero. */\n const liveGroups = (groups: CostUsageGroup[]): CostUsageGroup[] =>\n groups.filter(g => COST_TOKEN_KEYS.some(k => g.tokens[k] > 0))\n /**\n * Fold one settled usage group into `groups`, first undoing the group a retry\n * supersedes. Shared by turn/step settlements and summary calls, which have\n * no turn/step of their own.\n */\n const foldGroup = (groups: CostUsageGroup[], previous: CostUsageGroup | undefined, group: CostUsageGroup, tokens: CostTokens): void => {\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 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(costGroupKey(group, table))\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 }\n return {\n key: 'commandCodeCost', stateVersion: version,\n stateSchema: { parse: parseState },\n init: (): CostState => ({ selection: null, at: null, last: null, facts: { pricingKey: version, groups: [], summaryTokens: zeroCostTokens() } }),\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 // A compaction summary is the compactor's own `ctx.llm.stream()` call. It\n // is real spend, but it settles on no turn/step and emits none of the\n // `assistant/*` events the harness meter folds, so its usage exists only\n // here. Price it into `groups` AND count it in `summaryTokens`: the\n // readout subtracts the latter before checking that this projection and\n // `tokenUsage` still describe the same durable cut.\n if (event.type === 'compaction/summary') {\n const summary = tokensOf(data.usage)\n if (summary === undefined) return state\n const group: CostUsageGroup = {\n provider: typeof data.provider === 'string' ? data.provider : '',\n model: typeof data.model === 'string' ? data.model : '',\n at: finite(event.time) ? event.time : null,\n contextTokens: summary.uncachedInputTokens + summary.cacheReadTokens + summary.cacheWriteTokens,\n tokens: summary,\n }\n const groups = state.facts.groups.map(g => ({ ...g, tokens: { ...g.tokens } }))\n foldGroup(groups, undefined, group, summary)\n const summaryTokens = { ...state.facts.summaryTokens }\n for (const k of COST_TOKEN_KEYS) summaryTokens[k] += summary[k]\n return { ...state, facts: { pricingKey: version, groups: liveGroups(groups), summaryTokens } }\n }\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 foldGroup(groups, previous, group, tokens)\n return { ...state, last: { turn: data.turn, step: data.step, group }, facts: { pricingKey: version, groups: liveGroups(groups), summaryTokens: state.facts.summaryTokens } }\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","/** 在宿主内折叠原始历史;每次请求保留计价时间和上下文,禁止使用已合并的会话成本桶。 */\nimport { assistantStreamFirstTokenTime } from '@deepseek-ai/dsh-llm'\nimport type { AssistantStreamRecord } from '@deepseek-ai/dsh-llm'\nimport { COST_TOKEN_KEYS, pricingKey, requestRates, zeroCostTokens, type CostTokens } from './cost-facts.ts'\nimport type { CommandCodeModelPrice, CommandCodePriceTable } from './usage-wire.ts'\nimport type { AnalyticsMetrics, AnalyticsQuery, AnalyticsReport, AnalyticsScenario } from './analytics-wire.ts'\nimport { isRecord } from './wire-guards.ts'\n\nexport interface AnalyticsEvent { seq: number; type: string; time: number; data: unknown }\nexport interface AnalyticsLog { inheritedEventCount: number; events: readonly AnalyticsEvent[] }\nexport interface RequestFact {\n session: string; model: string; at: number; retry: boolean; outcome: 'completed' | 'failed' | 'cancelled' | 'unknown'\n tokens?: CostTokens; latencyMs?: number; ttftMs?: number; decodeMs?: number\n}\nconst record = (v: unknown): Record<string, unknown> | undefined => isRecord(v) ? v : undefined\nconst number = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v >= 0\nfunction tokensOf(v: unknown): CostTokens | undefined {\n const u = record(v)\n if (!u || !number(u.inputTokens) || !number(u.outputTokens)) return undefined\n if (u.cacheReadTokens !== undefined && !number(u.cacheReadTokens) || u.cacheWriteTokens !== undefined && !number(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/** 同一次尝试的用量覆盖前值;重试开始才新建请求,继承前缀只恢复模型选择。 */\nexport function foldRequests(session: string, log: AnalyticsLog): RequestFact[] {\n const facts: RequestFact[] = []\n let provider = '', model = '', current: RequestFact | undefined, own = false, started = false, listed = false, turn = -1, step = -1\n const begin = (event: AnalyticsEvent, data: Record<string, unknown>, retry: boolean) => {\n turn = Number(data.turn); step = Number(data.step); own = event.seq >= log.inheritedEventCount; started = true\n current = { session, model, at: event.time, retry, outcome: 'unknown' }\n listed = own && provider === 'commandcode'\n if (listed) facts.push(current)\n }\n for (const event of log.events) {\n const d = record(event.data)\n if (!d) continue\n if (event.type === 'request/header') {\n const config = record(record(d.header)?.config)\n provider = typeof config?.provider === 'string' ? config.provider : ''\n model = typeof config?.model === 'string' ? config.model : ''\n if (current && current.outcome === 'unknown') {\n current.model = model\n if (own && provider === 'commandcode' && !listed) { facts.push(current); listed = true }\n // 当前尝试始终是最后一条;避免每次请求扫描全部历史。\n if (provider !== 'commandcode' && listed) { facts.pop(); listed = false }\n }\n continue\n }\n // 压缩摘要是压缩器自己发的一次 `ctx.llm.stream()`:它不落在任何 turn/step 上,\n // 也不产生 `request/header`,用量只出现在这个事件里。只登记本路由的摘要,并且\n // 不碰 current / listed / provider 状态 —— 摘要在两次请求之间发生,不属于它们。\n // provider 与 model 由事件自带(后端上报),不从上一个 header 继承。\n if (event.type === 'compaction/summary') {\n if (event.seq >= log.inheritedEventCount && d.provider === 'commandcode') {\n const tokens = tokensOf(d.usage)\n facts.push({\n session, model: typeof d.model === 'string' ? d.model : '', at: event.time, retry: false, outcome: 'completed',\n ...tokens === undefined ? {} : { tokens },\n })\n }\n continue\n }\n if (event.type === 'step/start' || event.type === 'llm/retry-started') { begin(event, d, event.type === 'llm/retry-started'); continue }\n if (!current && ['assistant/message', 'assistant/attempt', 'assistant/chunk'].includes(event.type)) {\n begin(event, d, false); started = false\n }\n if (!current) continue\n if (event.type === 'turn/end' && d.turn === turn) {\n const reason = record(d.reason)?.kind\n if (current.outcome === 'unknown') {\n if (reason === 'error') current.outcome = 'failed'\n else if (reason === 'aborted') current.outcome = 'cancelled'\n }\n current = undefined\n continue\n }\n if (d.turn !== turn || d.step !== step) continue\n if (event.type === 'llm/retry') { current.outcome = 'failed'; continue }\n if (!['assistant/message', 'assistant/attempt', 'assistant/chunk'].includes(event.type)) continue\n const chunk = record(d.chunk)\n let tokens = tokensOf(d.usage)\n if (event.type === 'assistant/chunk' && chunk?.type === 'usage') tokens = tokensOf(chunk.usage)\n if (tokens === undefined && Array.isArray(d.stream)) {\n for (let i = d.stream.length - 1; i >= 0; i--) {\n const item = record(d.stream[i]), c = item?.type === 'chunk' ? record(item.chunk) : undefined\n if (c?.type === 'usage') { tokens = tokensOf(c.usage); if (tokens) break }\n }\n }\n if (tokens) current.tokens = tokens\n if (event.type === 'assistant/message') current.outcome = d.interrupted === true ? 'cancelled' : 'completed'\n // 只有保存了定时流的结算才测速度。旧消息的落盘时间不能冒充模型耗时。\n if (started && Array.isArray(d.stream) && event.time >= current.at) {\n current.latencyMs = event.time - current.at\n const first = assistantStreamFirstTokenTime(d.stream as AssistantStreamRecord[])\n if (first !== undefined && first >= current.at && first <= event.time) {\n current.ttftMs = first - current.at\n if (current.tokens) current.decodeMs = event.time - first\n }\n }\n }\n return facts\n}\n\nexport const emptyMetrics = (): AnalyticsMetrics => ({ sessions: 0, requests: 0, completed: 0, failed: 0, cancelled: 0, unknown: 0, retries: 0, usageSamples: 0, pricedRequests: 0, cost: 0, tokens: zeroCostTokens(), latencySamples: 0, latencyMs: 0, ttftSamples: 0, ttftMs: 0, decodeSamples: 0, decodeMs: 0, decodeTokens: 0 })\nfunction priceRequest(f: RequestFact, id: string, table: CommandCodePriceTable, prices: ReadonlyMap<string, CommandCodeModelPrice>): number | undefined {\n if (!f.tokens) return undefined\n const price = prices.get(id)\n if (!price) return undefined\n if (price.free === true) return 0\n const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens\n const r = requestRates(price, f.at, context, table)\n if (f.tokens.cacheWriteTokens > 0 && r.cacheWriteCost === undefined) return undefined\n return (f.tokens.uncachedInputTokens * r.inputCost + f.tokens.outputTokens * r.outputCost + f.tokens.cacheReadTokens * r.cacheReadCost + f.tokens.cacheWriteTokens * (r.cacheWriteCost ?? 0)) / 1e6\n}\nfunction aggregate(facts: RequestFact[], table: CommandCodePriceTable, prices: ReadonlyMap<string, CommandCodeModelPrice>): AnalyticsMetrics {\n const m = emptyMetrics(); m.sessions = new Set(facts.map(f => f.session)).size\n for (const f of facts) {\n m.requests++; m[f.outcome]++; if (f.retry) m.retries++\n if (f.tokens) { m.usageSamples++; for (const k of COST_TOKEN_KEYS) m.tokens[k] += f.tokens[k] }\n const cost = priceRequest(f, f.model, table, prices)\n if (cost !== undefined) { m.pricedRequests++; m.cost += cost }\n if (f.latencyMs !== undefined) { m.latencySamples++; m.latencyMs += f.latencyMs }\n if (f.ttftMs !== undefined) { m.ttftSamples++; m.ttftMs += f.ttftMs }\n if (f.decodeMs !== undefined && f.decodeMs > 0 && f.tokens) { m.decodeSamples++; m.decodeMs += f.decodeMs; m.decodeTokens += f.tokens.outputTokens }\n }\n return m\n}\nexport interface ScenarioModel { id: string; name: string; contextWindow: number | null; images: boolean; efforts: string[] }\nexport function buildAnalytics(facts: RequestFact[], query: AnalyticsQuery, table: CommandCodePriceTable, catalog: ScenarioModel[], now = Date.now()): AnalyticsReport {\n const selected = query.mode === 'range' ? facts.filter(f => f.at >= query.from && f.at < query.to) : facts\n const prices = new Map<string, CommandCodeModelPrice>()\n for (const p of table.models) for (const id of [p.id, p.slug]) if (!prices.has(id)) prices.set(id, p)\n const totals = aggregate(selected, table, prices)\n const models = [...new Set(selected.map(f => f.model))].map(id => ({ id, ...aggregate(selected.filter(f => f.model === id), table, prices) })).sort((a, b) => b.cost - a.cost || a.id.localeCompare(b.id))\n const scenarios: AnalyticsScenario[] = catalog.map(model => {\n let cost = 0, pricedRequests = 0, excludedRequests = 0, unknownRequests = 0\n for (const f of selected) {\n if (!f.tokens) { unknownRequests++; continue }\n const context = f.tokens.uncachedInputTokens + f.tokens.cacheReadTokens + f.tokens.cacheWriteTokens\n // 输入和输出同时占据上下文;不适配的请求不得混进可比较的成本。\n if (model.contextWindow !== null && context + f.tokens.outputTokens > model.contextWindow) { excludedRequests++; continue }\n const priced = priceRequest(f, model.id, table, prices)\n if (priced === undefined) unknownRequests++\n else { cost += priced; pricedRequests++ }\n }\n return { ...model, cost, pricedRequests, excludedRequests, unknownRequests }\n })\n const elapsed = query.mode === 'range' ? Math.min(query.to, now) - query.from : 0\n const monthlyEstimate = elapsed >= 86400000 && totals.requests > 0 && totals.pricedRequests === totals.requests\n ? totals.cost * (30 * 86400000 / elapsed) : null\n return { generatedAt: now, pricingKey: pricingKey(table), query, status: 'ready', scannedSessions: 0, matchedSessions: totals.sessions, unreadableSessions: 0, skippedSessions: 0, truncated: false, catalogUnavailable: false, totals, models, scenarios, monthlyEstimate }\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","/** 模型分析的只读契约;只传数字和模型能力,不传会话正文、标题、路径或密钥。 */\nimport type { InvocationDescriptor, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'\nimport { makeBoundaryValidator, makeRemoteDescriptor, makeStrictCodec, REMOTE_PACKAGE } from './wire-shared.ts'\nimport type { CostTokens } from './cost-facts.ts'\n\nexport type AnalyticsQuery = { mode: 'recent'; limit: number } | { mode: 'range'; from: number; to: number }\nexport interface AnalyticsMetrics {\n sessions: number; requests: number; completed: number; failed: number; cancelled: number; unknown: number; retries: number\n usageSamples: number; pricedRequests: number; cost: number; tokens: CostTokens\n latencySamples: number; latencyMs: number; ttftSamples: number; ttftMs: number; decodeSamples: number; decodeMs: number; decodeTokens: number\n}\nexport interface AnalyticsModel extends AnalyticsMetrics { id: string }\nexport interface AnalyticsScenario {\n id: string; name: string; contextWindow: number | null; images: boolean; efforts: string[]\n cost: number; pricedRequests: number; excludedRequests: number; unknownRequests: number\n}\nexport interface AnalyticsReport {\n generatedAt: number; pricingKey: number; query: AnalyticsQuery\n status: 'ready' | 'unavailable'\n scannedSessions: number; matchedSessions: number; unreadableSessions: number; skippedSessions: number; truncated: boolean; catalogUnavailable: boolean\n totals: AnalyticsMetrics; models: AnalyticsModel[]; scenarios: AnalyticsScenario[]\n monthlyEstimate: number | null\n}\nconst g = makeBoundaryValidator('commandcode/analytics')\nconst nonnegative = (s: Record<string, unknown>, k: string): number => {\n const n = g.numberField(s, k, k)\n return n >= 0 ? n : g.reject(k)\n}\nconst count = (s: Record<string, unknown>, k: string): number => {\n const n = nonnegative(s, k)\n return Number.isSafeInteger(n) ? n : g.reject(k)\n}\nexport function parseAnalyticsQuery(value: unknown): AnalyticsQuery {\n const s = g.record(value, 'query')\n if (s.mode === 'recent') {\n const limit = count(s, 'limit')\n if (limit < 1 || limit > 100) return g.reject('limit')\n return { mode: 'recent', limit }\n }\n if (s.mode !== 'range') return g.reject('mode')\n const from = count(s, 'from'), to = count(s, 'to')\n if (to <= from || to - from > 366 * 86400000 || to > 8640000000000000) return g.reject('range')\n return { mode: 'range', from, to }\n}\nconst counts = ['sessions', 'requests', 'completed', 'failed', 'cancelled', 'unknown', 'retries', 'usageSamples', 'pricedRequests', 'latencySamples', 'ttftSamples', 'decodeSamples'] as const\nconst quantities = ['cost', 'latencyMs', 'ttftMs', 'decodeMs', 'decodeTokens'] as const\nconst tokenKeys = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\nfunction metrics(value: unknown): AnalyticsMetrics {\n const s = g.record(value, 'metrics'), result = {} as AnalyticsMetrics\n for (const k of counts) result[k] = count(s, k)\n for (const k of quantities) result[k] = nonnegative(s, k)\n const tokens = g.record(s.tokens, 'tokens')\n result.tokens = Object.fromEntries(tokenKeys.map(k => [k, nonnegative(tokens, k)])) as unknown as CostTokens\n if (result.completed + result.failed + result.cancelled + result.unknown !== result.requests\n || result.pricedRequests > result.usageSamples || result.usageSamples > result.requests\n || result.retries > result.requests || result.ttftSamples > result.requests || result.latencySamples > result.requests || result.decodeSamples > result.requests) return g.reject('coverage')\n return result\n}\nconst nullable = (s: Record<string, unknown>, k: string): number | null => s[k] === null ? null : nonnegative(s, k)\nexport function parseAnalyticsReport(value: unknown): AnalyticsReport {\n const s = g.record(value, 'report')\n if (s.status !== 'ready' && s.status !== 'unavailable') return g.reject('status')\n if (!Array.isArray(s.models) || !Array.isArray(s.scenarios) || s.models.length > 1000 || s.scenarios.length > 1000) return g.reject('models')\n return {\n generatedAt: count(s, 'generatedAt'), pricingKey: count(s, 'pricingKey'), query: parseAnalyticsQuery(s.query), status: s.status,\n scannedSessions: count(s, 'scannedSessions'), matchedSessions: count(s, 'matchedSessions'), unreadableSessions: count(s, 'unreadableSessions'), skippedSessions: count(s, 'skippedSessions'),\n truncated: g.booleanField(s, 'truncated', 'truncated'), catalogUnavailable: g.booleanField(s, 'catalogUnavailable', 'catalogUnavailable'),\n totals: metrics(s.totals), monthlyEstimate: nullable(s, 'monthlyEstimate'),\n models: s.models.map(value => { const m = g.record(value, 'model'); return { ...metrics(m), id: g.stringField(m, 'id', 'id') } }),\n scenarios: s.scenarios.map(value => {\n const m = g.record(value, 'scenario')\n if (!Array.isArray(m.efforts) || !m.efforts.every(v => typeof v === 'string')) return g.reject('efforts')\n return { id: g.stringField(m, 'id', 'id'), name: g.stringField(m, 'name', 'name'), contextWindow: nullable(m, 'contextWindow'), images: g.booleanField(m, 'images', 'images'), efforts: m.efforts as string[], cost: nonnegative(m, 'cost'), pricedRequests: count(m, 'pricedRequests'), excludedRequests: count(m, 'excludedRequests'), unknownRequests: count(m, 'unknownRequests') }\n }),\n }\n}\nexport const ANALYTICS_DESCRIPTOR: InvocationDescriptor = {\n ...makeRemoteDescriptor('commandcode/analytics', 'analytics', `${REMOTE_PACKAGE}#AnalyticsReport`, { parse: parseAnalyticsReport }),\n parameters: [{ name: 'query', wire: 'query', source: 'json' as const, codec: makeStrictCodec(`${REMOTE_PACKAGE}#AnalyticsQuery`, { parse: parseAnalyticsQuery }) }],\n}\nexport const ANALYTICS_REMOTE_CONTRIBUTION: TypertRemoteContribution = { package: REMOTE_PACKAGE, descriptors: [ANALYTICS_DESCRIPTOR] }\n","/** 可选宿主历史服务:读实时优先的完整语料库,绝不加载会话为实时或写回日志。 */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { CommandCodeAdapter } from './adapter.ts'\nimport { KNOWN_EFFORTS } from './capabilities.ts'\nimport { buildAnalytics, foldRequests, type AnalyticsLog, type RequestFact, type ScenarioModel } from './analytics.ts'\nimport { parseAnalyticsQuery, type AnalyticsQuery, type AnalyticsReport } from './analytics-wire.ts'\nimport { modelPriceTable } from './model-prices.ts'\n\nexport interface HistoryQuery {\n listSessions(signal?: AbortSignal): Promise<Array<{ header: { id: string } }>>\n readSession(id: string): Promise<AnalyticsLog>\n}\nexport const ANALYTICS_SESSION_LIMIT = 500\nexport const ANALYTICS_EVENT_LIMIT = 200000\n/** 逐会话失败隔离;上限和遗漏计数会返回界面,部分结果不能伪装成完整历史。 */\nexport async function readAnalyticsHistory(history: HistoryQuery | undefined, input: AnalyticsQuery, catalog: () => Promise<ScenarioModel[]>, signal?: AbortSignal): Promise<AnalyticsReport> {\n const query = parseAnalyticsQuery(input), table = modelPriceTable()\n if (!history) return { ...buildAnalytics([], query, table, []), status: 'unavailable' }\n const records = await history.listSessions(signal)\n const facts: RequestFact[] = []\n let scannedSessions = 0, unreadableSessions = 0, skippedSessions = 0, events = 0, truncated = records.length > ANALYTICS_SESSION_LIMIT\n for (const entry of records.slice(0, ANALYTICS_SESSION_LIMIT)) {\n if (signal?.aborted) throw new Error('模型分析已取消')\n if (events >= ANALYTICS_EVENT_LIMIT) { truncated = true; break }\n scannedSessions++\n try {\n const log = await history.readSession(entry.header.id)\n // 老宿主或第三方服务缺少精确继承边界时跳过,不能猜测分支切点。\n if (!Number.isSafeInteger(log.inheritedEventCount) || log.inheritedEventCount < 0 || log.inheritedEventCount > log.events.length) { skippedSessions++; continue }\n events += log.events.length\n if (events > ANALYTICS_EVENT_LIMIT) { skippedSessions++; truncated = true; break }\n facts.push(...foldRequests(entry.header.id, log))\n } catch { unreadableSessions++ }\n }\n let selected = facts\n if (query.mode === 'recent') {\n const latest = new Map<string, number>()\n for (const f of facts) latest.set(f.session, Math.max(latest.get(f.session) ?? 0, f.at))\n const ids = new Set([...latest].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, query.limit).map(([id]) => id))\n selected = facts.filter(f => ids.has(f.session))\n }\n let models: ScenarioModel[] = [], catalogUnavailable = false\n if (signal?.aborted) throw new Error('模型分析已取消')\n try { models = await catalog() } catch { catalogUnavailable = true }\n const report = buildAnalytics(selected, query, table, models)\n return { ...report, scannedSessions, unreadableSessions, skippedSessions, truncated, catalogUnavailable, monthlyEstimate: truncated || unreadableSessions > 0 || skippedSessions > 0 ? null : report.monthlyEstimate }\n}\n/** 用反射和可选 fiber 对接,保持未挂载历史服务的无界面/TUI 配置可用。 */\nexport function createAnalyticsReader(ctx: Context, adapter: Pick<CommandCodeAdapter, 'listModels' | 'resolveModel'>) {\n let history: HistoryQuery | undefined, busy = false\n ctx.inject(['sessionQuery'], c => {\n const service = c.get('sessionQuery') as HistoryQuery | undefined\n if (typeof service?.listSessions !== 'function' || typeof service.readSession !== 'function') return\n history = service\n c.effect(() => () => { if (history === service) history = undefined }, 'commandcode analytics history')\n })\n return async (query: AnalyticsQuery, signal?: AbortSignal): Promise<AnalyticsReport> => {\n if (busy) throw new Error('模型分析正在读取历史,请稍后刷新')\n busy = true\n try {\n return await readAnalyticsHistory(history, query, async () => {\n const available = await adapter.listModels('commandcode')\n return Promise.all(available.map(async m => {\n const resolved = await adapter.resolveModel('commandcode', m.id)\n return { id: m.id, name: m.name.replace(/ \\(CC\\)$/, ''), contextWindow: resolved.context?.contextWindow ?? null, images: resolved.inputModalities?.includes('image') ?? false, efforts: [...(KNOWN_EFFORTS[m.id] ?? [])] }\n }))\n }, signal)\n } finally { busy = false }\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/** 不包含解析秘密的账号定义;作用域独立复制列表及模型规则。 */\nexport interface CommandCodeAccountSelection {\n slots: readonly CommandCodeAccountSlot[]\n preferredId?: string | undefined\n modelAccountRules: readonly CommandCodeModelAccountRule[]\n}\n\n/** 仅复制账号定义;凭据服务的秘密仍在每次解析时读取。 */\nexport function captureAccountSelection(selection: CommandCodeAccountSelection): CommandCodeAccountSelection {\n return Object.freeze({\n slots: Object.freeze(selection.slots.map(slot => Object.freeze({ ...slot }))),\n preferredId: selection.preferredId,\n modelAccountRules: Object.freeze(selection.modelAccountRules.map(rule => {\n const models = [...rule.models]\n Object.freeze(models)\n return Object.freeze({ ...rule, models })\n })),\n })\n}\n\n/** 账号选择与展示共用恢复规则;宿主作用域内的状态按网关与密钥共享。 */\nexport class CommandCodeAccountPool {\n /** 当前作用域内按密钥共享的健康状态;不记录到日志。 */\n private states = new Map<string, CommandCodeAccountState>()\n /** 当前网关与密钥的显式探测时间,限制失败探测的频率。 */\n private explicitProbes = new Map<string, number>()\n private scopedStates = new Map<string, { states: Map<string, CommandCodeAccountState>; probes: Map<string, number> }>()\n constructor(private readonly deps: CommandCodeAccountPoolDeps) {}\n\n /** 每个调用持有自己的定义和探测,只有同网关的健康事实共享;不临时改写全局依赖。 */\n scope(context: CommandCodeAccountSelection & { apiBase: string; probeWindow: CommandCodeAccountPoolDeps['probeWindow'] }): CommandCodeAccountPool {\n const selection = captureAccountSelection(context)\n let shared = this.scopedStates.get(context.apiBase)\n if (shared === undefined) {\n shared = { states: new Map(), probes: new Map() }\n this.scopedStates.set(context.apiBase, shared)\n }\n const scoped = new CommandCodeAccountPool({\n ...this.deps,\n slots: () => selection.slots,\n preferredId: () => selection.preferredId,\n modelAccountRules: () => selection.modelAccountRules,\n probeWindow: context.probeWindow,\n })\n scoped.states = shared.states\n scoped.explicitProbes = shared.probes\n scoped.scopedStates = this.scopedStates\n return scoped\n }\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). Scoped rules stay fixed for the call; credential values re-resolve.\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","/** 连接拒绝与流内错误共享同一分类,避免错误恢复因响应载体不同而漂移。 */\nimport { CONTEXT_WINDOW_EXCEEDED_CODE, isContextWindowExceededError, LlmError, type LlmErrorOptions } from '@deepseek-ai/dsh-llm'\nimport { RETRY_MAX_DELAY_MS } from './accounts.ts'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport { booleanValue, isRecord, numberValue, stringValue } from './wire-guards.ts'\n\n/** Keep the two user-facing languages and error metadata together. */\nexport function bilingual(code: string, en: string, zh: string, options?: LlmErrorOptions): LlmError {\n return new LlmError(`${en};${zh}`, code, options)\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 */\nexport const 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 */\nexport function 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 * 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 */\nexport function 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\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\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. */\nexport function 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\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 *\n * The optional `priorRejection` records a refusal from an earlier transport\n * attempt in this same call (see {@link isMessagesPermissionRejection}), so a\n * failed CLI fallback still shows what the Messages surface said first. It is\n * presentation only: classification, retry budget and failure code all keep\n * reading the current attempt.\n */\nexport function generateHttpError(\n status: number,\n errText: string,\n retryAfterMs?: number,\n parsed: ParsedProviderError = parseProviderError(errText),\n // 本次调用此前失败过的有界标识(目前只有 messages 的 `permission_error`)。\n // 只进入最终文案,不参与分类、重试预算与失败码,否则展示层会反过来改变行为。\n priorRejection?: string,\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 safeIdentifier = (value: string | undefined): string | undefined =>\n value !== undefined && /^[A-Za-z0-9_.:-]{1,80}$/.test(value) ? value : undefined\n const diagnosticCode = safeIdentifier(parsed.code)\n ?? /^\\s*(MODEL_NOT_IN_PLAN|INSUFFICIENT_CREDITS|USAGE_EXCEEDED|PREMIUM_CREDITS_EXHAUSTED)\\b/i.exec(parsed.message ?? '')?.[1]\n // Messages 接口常只有 type;两个字段分别校验,非法 code 不能掩盖合法 type。\n const diagnosticType = safeIdentifier(parsed.type)\n const identifiers = [\n diagnosticCode === undefined ? undefined : `错误码:${diagnosticCode}`,\n diagnosticType === undefined ? undefined : `错误类型:${diagnosticType}`,\n ].filter((value): value is string => value !== undefined)\n const diagnostic = identifiers.length === 0 ? '' : `(${identifiers.join(';')})`\n // 以本次(回退后的 CLI 直连)结果为主,另附此前反代侧的拒绝标识:只报第二段\n // 链路,用户无从判断 messages 端点拒绝过什么。标识再过一次同样的有界校验,\n // 免得上游正文里的任意串经此进入展示文案。\n const priorIdentifier = priorRejection === undefined ? undefined : safeIdentifier(priorRejection)\n const priorNote = priorIdentifier === undefined\n ? ''\n : `此前 Messages 接口以 ${priorIdentifier} 拒绝,已回退 CLI 直连,仍未成功。`\n return new LlmError(\n `Command Code 请求失败(HTTP ${status})${diagnostic}:`\n + (status === 429 ? '请求受到用量或速率限制,请稍后重试并检查账户额度。'\n : status === 408 ? '服务端处理超时,请稍后重试。'\n : status >= 500 ? '上游服务暂时无法完成请求,请稍后重试。'\n : '服务端拒绝了本次请求,请检查模型、套餐和请求设置。')\n + priorNote,\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 * 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 */\nexport function 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 * 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\nexport function 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 */\nexport const 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 */\nexport function 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/**\n * True when the Messages surface (`/provider/v1/messages`) refused one request\n * with Anthropic's `permission_error` (issue #84).\n *\n * 职责:把「反代 Claude 链路对该账号不放行」这一种拒绝,从普通权限失败里\n * 单独认出来,交给适配器决定是否改用 CLI 直连(`/alpha/generate`)。\n *\n * 为什么边界如此窄:只认 HTTP 403 加上结构化的 `code`/`type` 等于\n * `permission_error`,不扫原始正文。正文可能回显输入或返回整页英文错误,\n * 扫文本会把无关失败也变成一次传输切换;而真正「模型不在套餐内」的拒绝\n * (`MODEL_NOT_IN_PLAN` 等其它标识)继续按原样上报,不被这条规则吞掉。\n */\nexport function isMessagesPermissionRejection(\n status: number,\n parsed: ParsedProviderError,\n): boolean {\n if (status !== 403) return false\n return (parsed.code ?? parsed.type)?.toLowerCase() === 'permission_error'\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 * 调度层只转交响应;三种线上事件的装配差异保留在本模块内部。 */\nimport { randomUUID } from 'node:crypto'\nimport { LlmError, ProviderRequestId, ToolCallId, errorChain, type FinishReason, type StreamChunk, type TokenUsage } from '@deepseek-ai/dsh-llm'\nimport { bilingual, streamErrorToLlmError } from './provider-errors.ts'\nimport { isRecord, numberValue, stringValue, recordOrEmpty } from './wire-guards.ts'\nimport { boundTraceText, STREAM_TRACE_ENV, type StreamTrace } from './stream-trace.ts'\nimport type { RequestTiming } from './request-timing.ts'\n\n/** 仅供本次消费生命周期使用,不作为服务商错误或用户取消向外传播。 */\nclass ConsumerStreamClosed extends Error {}\n\n/**\n * 读循环唤醒闸门的标记值:底层 read() 既不结算、取消也叫不醒时,由闸门结束这次等待。\n * 它不是错误,只在读循环内部出现,用来把「读取完成」与「读取卡住」区分开。\n */\nconst READ_STALLED = Symbol('readStalled')\n\n/**\n * 异步生成器的 return 会排在正在等待的 next 后面,因此必须先通过独立信号\n * 唤醒当前读取,再让生成器执行 finally。消费方已结束时不再交付用量或错误。\n */\nexport function ownedResponseStream(\n callerSignal: AbortSignal | undefined,\n run: (signal: AbortSignal) => AsyncIterable<StreamChunk>,\n): AsyncIterable<StreamChunk> {\n const consumer = new AbortController()\n const signal = callerSignal ? AbortSignal.any([callerSignal, consumer.signal]) : consumer.signal\n const source = run(signal)[Symbol.asyncIterator]()\n let closed = false\n const done = (): IteratorResult<StreamChunk> => ({ done: true, value: undefined })\n const iterator: AsyncIterableIterator<StreamChunk> = {\n [Symbol.asyncIterator]() { return this },\n async next() {\n if (closed) return done()\n try {\n const result = await source.next()\n return closed ? done() : result\n } catch (error) {\n if (closed) return done()\n throw error\n }\n },\n async return() {\n if (!closed) {\n closed = true\n consumer.abort(new ConsumerStreamClosed('消费方已结束读取'))\n }\n await source.return?.()\n return done()\n },\n }\n return iterator\n}\n\nexport interface StreamResponseContext {\n protocol: CommandCodeProtocol\n signal: AbortSignal | undefined\n maxTokens: number\n apiBase: string\n streamIdleTimeoutMs: number\n responseMetadata: ResponseMetadata\n trace: StreamTrace\n timing: RequestTiming\n /** 解除连接阶段转交的取消监听;任何退出路径均调用一次。 */\n cleanup(): void\n}\n\n/** 唯一过程入口;诊断或释放失败不能在成功结束后再制造第二个结束。 */\nexport async function* settleStreamResponse(response: Response, context: StreamResponseContext): AsyncIterable<StreamChunk> {\n try { yield* readResponse(response, context) }\n finally {\n try { context.cleanup() } catch { /* 本地连接监听释放失败不改变模型结果。 */ }\n context.trace.close()\n }\n}\n\nasync function* readResponse(response: Response, context: StreamResponseContext): AsyncIterable<StreamChunk> {\n const { protocol, signal, maxTokens, apiBase, streamIdleTimeoutMs, responseMetadata, trace, timing } = context\n if (!response.body) {\n trace.record('end', { outcome: 'empty', code: 'PROVIDER_PROTOCOL_ERROR' })\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 cancelReader = () => {\n try { void reader.cancel().catch(() => undefined) }\n catch { /* 已释放的读取器不影响已决定的终止结果。 */ }\n }\n // 读取唤醒闸门:空闲计时器与取消信号都先解开它,再尽力取消底层读取。合规流上\n // cancel() 自己就会以 done 结算挂起的 read();但被包装或被垫片替换的 body 可能\n // 既不给结果也不响应取消,只依赖 cancel() 会让空闲期限、调用者取消和消费方结束\n // 三条路径一起卡死。闸门让这三条路径始终有界,且不改变正常读取的顺序。\n let openGate: (() => void) | undefined\n const wakeRead = () => openGate?.()\n const onAbort = () => { wakeRead(); cancelReader() }\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. Firing opens the\n // read gate — so the loop ends even for a reader that ignores cancel() —\n // and best-effort cancels the underlying read; the loop turns that into a\n // TIMEOUT failure instead of hanging forever.\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n let idleFired = false\n const armIdle = () => {\n if (idleTimer !== undefined) clearTimeout(idleTimer)\n idleTimer = setTimeout(() => {\n idleFired = true\n wakeRead()\n cancelReader()\n }, streamIdleTimeoutMs)\n }\n const clearIdle = () => {\n if (idleTimer !== undefined) {\n clearTimeout(idleTimer)\n idleTimer = undefined\n }\n }\n /** 空闲期限结束读循环时的唯一错误文本;读取结算与读取卡住两条路径共用。 */\n const idleTimeoutError = () => bilingual(\n 'TIMEOUT',\n `Command Code API stream from ${apiBase} was idle for ${streamIdleTimeoutMs}ms`\n + ' (no events) and was treated as a dead connection',\n `Command Code API 流式响应已 ${streamIdleTimeoutMs} 毫秒无任何事件,被判定为死连接——长思考模型可在设置中调大流空闲超时`,\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 /** 读循环收束(读到 EOF 或读取卡住)共用的诊断事实,两处记录字段保持一致。 */\n const eofFacts = () => ({\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 // 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 (isRecord(event) && ((protocol === 'messages' && event.type === 'message_stop')\n || (protocol === 'cli' && event.type === 'finish'))) protocolStopped = true\n const chunks = handleEvent(asm, protocol, event)\n // 一个线上事件已经解析完毕后,先保存其结束与用量事实。消费者可在\n // 任意块片段处取消;取消只停止交付,不能丢掉此时已经解析到的用量。\n for (const chunk of chunks) {\n if (chunk.type === 'finish') finish = chunk\n else if (chunk.type === 'usage') usage = chunk.usage\n }\n for (const chunk of chunks) {\n if (chunk.type === 'finish' || chunk.type === 'usage') continue\n signal?.throwIfAborted()\n yield chunk\n }\n }\n function* handleLine(line: string): Generator<StreamChunk> {\n signal?.throwIfAborted()\n if (protocol === 'openai' && line.trim().replace(/^data:\\s*/, '') === '[DONE]') {\n protocolStopped = true\n return\n }\n yield* handle(parseStreamEventLine(line))\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n try {\n for (;;) {\n signal?.throwIfAborted()\n let read: ReadableStreamReadResult<Uint8Array> | typeof READ_STALLED\n // 每次读取换一个新闸门:上一轮的闸门一旦解开就不再代表这次等待。\n const gate = new Promise<typeof READ_STALLED>(resolve => { openGate = () => resolve(READ_STALLED) })\n armIdle()\n try {\n const pending = reader.read()\n // 闸门先到时这个读取会被放弃:它可能永不结算,也可能迟到以「读取器已释放」\n // 拒绝。结果已经不再需要,挂一个空 catch 免得它升级成未处理拒绝(Node 默认致命)。\n void pending.catch(() => undefined)\n read = await Promise.race([pending, gate])\n } catch (error: unknown) {\n // A mid-stream transport failure (connection reset, TLS teardown)\n // surfaces here. Caller cancellation propagates as-is.\n signal?.throwIfAborted()\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 ${apiBase} failed while reading: ${errorChain(error)}`,\n 'Command Code API 流式响应中途断开——网络波动所致,重试通常可恢复',\n { cause: error },\n )\n } finally {\n clearIdle()\n openGate = undefined\n }\n if (read === READ_STALLED) {\n // 期限或取消叫不醒底层读取:闸门自己结束等待。取消优先——调用者取消必须\n // 原样传播,不能被记成超时失败;只有在没有取消时才按空闲期限失败。\n trace.record('eof', { ...eofFacts(), readStalled: true })\n signal?.throwIfAborted()\n throw idleTimeoutError()\n }\n signal?.throwIfAborted()\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', eofFacts())\n if (idleFired) throw idleTimeoutError()\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 [index, line] of lines.entries()) {\n yield* handleLine(line)\n if (protocolStopped) {\n let ignoredLines = 0\n for (let rest = index + 1; rest < lines.length; rest++) if (lines[rest]?.trim()) ignoredLines++\n const buffered = buffer.trim().length\n if (ignoredLines > 0 || buffered > 0) trace.record('protocol-stop', { protocol, ignoredLines, buffered })\n break\n }\n }\n // OpenAI 的 finish_reason 之后还可能有独立用量包;Messages 在\n // message_stop 才结束。CLI 的 finish 则本身就是协议终止事件。\n if (protocolStopped) break\n }\n signal?.throwIfAborted()\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 signal?.throwIfAborted()\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 // 未收到生成结束原因的 EOF 不能伪造成功;正文或工具片段存在时\n // 按断流处理,纯思考或空白仍按空响应处理,保留既有重试分类。\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 ${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: signal?.aborted ? signal.reason instanceof ConsumerStreamClosed ? 'cancelled' : '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 endRecorded = true\n signal?.throwIfAborted()\n throw failureWithRequestId(error, responseMetadata)\n } finally {\n clearIdle()\n signal?.removeEventListener('abort', onAbort)\n // 消费者提前结束没有继续接收的能力,不能在 finally 强行交付用量。\n if (!endRecorded) trace.record('end', { outcome: signal?.aborted && !(signal.reason instanceof ConsumerStreamClosed) ? 'aborted' : 'cancelled',\n ...(usage === undefined ? {} : { usage }), chunks: chunkCount, bytes: totalBytes, responseMetadata })\n cancelReader()\n // 取消立即终止本地读取;不等底层 cancel 承诺,以免它拖住整个响应。\n try { reader.releaseLock() } catch { /* 本地清理失败不覆盖成功或原始错误。 */ }\n }\n}\n\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 */\nexport type CommandCodeProtocol = 'cli' | 'openai' | 'messages'\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\nexport function 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. */\nexport interface 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. */\nexport function 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\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 * 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 * 三种协议共享的块装配状态;正文与思考分别至多有一个正在输出的块。\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\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/**\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/** 三种协议的结束原因统一映射为宿主分类,保留线上名称用于诊断。 */\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/** 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 * 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","/** 请求耗时只记录阶段、计数和状态;不记录消息、凭据、请求头或错误正文。 */\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","/** 网关事实的唯一所有者:目录先校验再发布,调用快照与跨调用学习分别持有。 */\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport { LlmError } from '@deepseek-ai/dsh-llm'\nimport { DEFAULT_MESSAGES_MAX_TOKENS, MODEL_OUTPUT_TOKEN_LIMITS, requiresMessagesEndpoint } from './capabilities.ts'\nimport { isRecord, numberValue, stringValue } from './wire-guards.ts'\nimport { OUTPUT_LIMIT_REJECTION, parseOutputCeiling } from './provider-errors.ts'\n\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 131_072\nexport const MODEL_CATALOG_TTL_MS = 5 * 60_000\nconst MODEL_CATALOG_RETRY_MS = 10_000\nconst MODEL_CACHE_VERSION = 3\nexport interface GatewaySource { apiBase: string; modelsCachePath: string }\nexport interface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n /** 保留来源公布值,派生预算不能作为持久化的权威上限。 */\n publishedMaxTokens?: number\n supportedEndpoints: readonly string[]\n}\nconst learned = new Map<string, Map<string, number>>()\nconst published = new Map<string, Map<string, number>>()\n// 跨实例发布序号只按网关共享;刷新失败也不能把发布权交还旧响应。\nconst generations = new Map<string, number>()\nconst validLimit = (value: number | undefined): value is number => value !== undefined && Number.isSafeInteger(value) && value > 0\nconst fallbackLimit = (model: string) => MODEL_OUTPUT_TOKEN_LIMITS.get(model) ?? (requiresMessagesEndpoint(model) ? DEFAULT_MESSAGES_MAX_TOKENS : DEFAULT_MAX_OUTPUT_TOKENS)\nexport function learnedOutputLimit(apiBase: string, model: string): number {\n return learned.get(apiBase)?.get(model) ?? Infinity\n}\nexport function modelOutputTokenLimit(apiBase: string, model: string): number {\n return Math.min(published.get(apiBase)?.get(model) ?? fallbackLimit(model), learnedOutputLimit(apiBase, model))\n}\n\n/** 是否更新共享事实与是否值得重试是两个问题;以本次实发预算判断拒绝。 */\nexport function outputCeilingRefusal(apiBase: string, model: string, sent: number, error: unknown): number | undefined {\n if (!(error instanceof LlmError) || !OUTPUT_LIMIT_REJECTION.test(error.message)) return undefined\n const stated = parseOutputCeiling(error.message)\n if (!validLimit(stated) || stated >= sent) return undefined\n let limits = learned.get(apiBase)\n if (limits === undefined) learned.set(apiBase, limits = new Map())\n const next = Math.min(stated, learnedOutputLimit(apiBase, model))\n limits.set(model, next)\n return next\n}\n\nfunction normalizeModel(raw: unknown, apiBase: string, disk: boolean): CommandCodeModel | undefined {\n if (!isRecord(raw)) return undefined\n const id = stringValue(raw.id), name = stringValue(raw.name)\n const contextWindow = numberValue(disk ? raw.contextWindow : raw.context_length)\n if (!id || !name || contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) return undefined\n const limit = numberValue(disk ? raw.publishedMaxTokens : raw.max_output_tokens)\n const endpoints = disk ? raw.supportedEndpoints : raw.supported_endpoints\n return {\n id, name, contextWindow,\n maxTokens: Math.min(contextWindow, validLimit(limit) ? limit : fallbackLimit(id), learnedOutputLimit(apiBase, id)),\n ...(validLimit(limit) ? { publishedMaxTokens: limit } : {}),\n supportedEndpoints: Array.isArray(endpoints) ? endpoints.filter((item): item is string => typeof item === 'string') : [],\n }\n}\nfunction parseCatalog(value: unknown, apiBase: string): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n const rows = value.data.map(raw => normalizeModel(raw, apiBase, false)).filter((row): row is CommandCodeModel => row !== undefined)\n if (rows.length === 0) throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n return rows\n}\nasync function readCache(source: GatewaySource): Promise<CommandCodeModel[]> {\n const value: unknown = JSON.parse(await readFile(source.modelsCachePath, 'utf8'))\n if (!isRecord(value) || value.version !== MODEL_CACHE_VERSION || value.apiBase !== source.apiBase || !Array.isArray(value.models)) throw new Error('Invalid model cache source')\n const rows = value.models.map(raw => normalizeModel(raw, source.apiBase, true)).filter((row): row is CommandCodeModel => row !== undefined)\n if (rows.length === 0) throw new Error('Empty model cache')\n return rows\n}\nfunction publish(apiBase: string, rows: readonly CommandCodeModel[]): void {\n published.set(apiBase, new Map(rows.flatMap(row => row.publishedMaxTokens === undefined ? [] : [[row.id, row.publishedMaxTokens] as const])))\n}\nasync function writeCache(source: GatewaySource, rows: readonly CommandCodeModel[], mayCommit: () => boolean): Promise<void> {\n await mkdir(dirname(source.modelsCachePath), { recursive: true })\n const temp = `${source.modelsCachePath}.${process.pid}.${randomUUID()}.tmp`\n try {\n await writeFile(temp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, apiBase: source.apiBase, models: rows }, null, 2)}\\n`, { encoding: 'utf8', mode: 0o600 })\n if (mayCommit()) await rename(temp, source.modelsCachePath)\n } finally { await rm(temp, { force: true }).catch(() => undefined) }\n}\ninterface CatalogState {\n source: string\n rows: CommandCodeModel[]\n expiresAt: number\n disk?: Promise<CommandCodeModel[]>\n inflight?: Promise<CommandCodeModel[]>\n}\nfunction copyRows(rows: readonly CommandCodeModel[]): CommandCodeModel[] {\n return rows.map(row => ({ ...row, supportedEndpoints: [...row.supportedEndpoints] }))\n}\n\nexport class GatewayFacts {\n private state: CatalogState | undefined\n constructor(private readonly fetchCatalog: (source: GatewaySource) => Promise<unknown>) {}\n private forSource(source: GatewaySource): CatalogState {\n const identity = JSON.stringify([source.apiBase, source.modelsCachePath])\n if (this.state?.source !== identity) this.state = { source: identity, rows: [], expiresAt: 0 }\n return this.state\n }\n /** 模型解析保持原有热目录直读;不把生成的磁盘冷读取推广到其他入口。 */\n knownModel(source: GatewaySource, model: string): CommandCodeModel | undefined {\n const row = this.forSource(source).rows.find(candidate => candidate.id === model)\n return row === undefined ? undefined : copyRows([row])[0]\n }\n /** 生成只读取本地目录;捕获状态后不再转向实例的新来源。 */\n async snapshot(source: GatewaySource): Promise<CommandCodeModel[]> {\n const state = this.forSource(source)\n if (state.rows.length > 0 || state.expiresAt > 0) return copyRows(state.rows)\n state.disk ??= readCache(source).catch(() => [])\n const rows = await state.disk\n if (state.rows.length > 0 || state.expiresAt > 0) return copyRows(state.rows)\n if (state.inflight === undefined) state.rows = rows\n return copyRows(rows)\n }\n async refresh(source: GatewaySource, signal?: AbortSignal): Promise<CommandCodeModel[]> {\n signal?.throwIfAborted()\n const state = this.forSource(source)\n if (Date.now() < state.expiresAt) return copyRows(state.rows)\n if (state.inflight === undefined) {\n const generation = (generations.get(source.apiBase) ?? 0) + 1\n generations.set(source.apiBase, generation)\n const mayPublish = () => this.state === state && generations.get(source.apiBase) === generation\n state.inflight = (async () => {\n let rows: CommandCodeModel[], ttl = MODEL_CATALOG_TTL_MS\n try {\n rows = parseCatalog(await this.fetchCatalog(source), source.apiBase)\n if (mayPublish()) {\n publish(source.apiBase, rows)\n await writeCache(source, rows, mayPublish).catch(() => undefined)\n }\n } catch {\n ttl = MODEL_CATALOG_RETRY_MS\n rows = state.rows.length > 0 ? state.rows : await readCache(source).catch(() => [])\n // 磁盘只能在尚无联网刷新及共享有效事实的冷启动补充来源,不能倒灌。\n if (mayPublish() && !published.has(source.apiBase) && rows.length > 0) publish(source.apiBase, rows)\n }\n state.rows = rows\n state.expiresAt = Date.now() + ttl\n return rows\n })().finally(() => { delete state.inflight })\n }\n const inflight = state.inflight\n if (!signal) return copyRows(await inflight)\n const rows = await new Promise<CommandCodeModel[]>((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 return copyRows(rows)\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 and the pre-stream account rotation loop. 目录、发布与\n * 上限事实由 ./gateway-facts.ts 持有,本适配器只消费单次调用的独立快照。 已连接响应的读取与收束由 ./stream-response.ts 负责。\n * 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 { homedir } from 'node:os'\nimport { 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'\nimport { bilingual, MAX_TRUSTED_RESET_MS, parseProviderError, generateHttpError, parseRetryAfterMs, classifyAccountRejection, isUpgradeRequiredError, isMessagesPermissionRejection, type AccountRotationReason } from './provider-errors.ts'\nexport type { AccountRotationReason } from './provider-errors.ts'\nimport { ownedResponseStream, settleStreamResponse, responseIdentifiers, failureWithRequestId, type CommandCodeProtocol, type ResponseMetadata } from './stream-response.ts'\n\nimport type { AttachmentStore, ImageAttachmentRef, ImageRequestTarget, RequestImageAttachment } from '@deepseek-ai/dsh-attachment'\n\nimport {\n assertUsableApiKey,\n attributionHeaders,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\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 GenerateOptions,\n type LlmModelInfo,\n type LlmProviderInfo,\n type LlmResolvedModelInfo,\n type RequestMessage,\n type StreamChunk,\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 } from './stream-trace.ts'\nimport { openRequestTiming, type RequestTiming, type RequestTimingSink } from './request-timing.ts'\nimport { THROTTLED_CODE } from './transient-retry.ts'\nimport { isRecord, numberValue, stringValue, recordOrEmpty } 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\nimport { GatewayFacts, modelOutputTokenLimit, learnedOutputLimit, outputCeilingRefusal, type CommandCodeModel } from './gateway-facts.ts'\nexport { DEFAULT_MAX_OUTPUT_TOKENS, MODEL_CATALOG_TTL_MS } from './gateway-facts.ts'\n\n// ---------------------------------------------------------------------------\n// Request / connection defaults (protocol constants). The model/plan/deal\n// capability snapshot lives in ./capabilities.ts — the sync-only surface.\n// ---------------------------------------------------------------------------\nexport const COMMAND_CODE_CLI_VERSION = '1.82.2'\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`, retired by Command Code on\n * 2026-10-01 and named here only as the probe's subject) and a 1 000 000-window\n * one (`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\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\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. */\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/** Parse a billing-period timestamp (ISO string or millis) into millis; 0 when absent/invalid. */\nfunction periodTimestampValue(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 * 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// 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\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\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 * 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/** 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?: (connection: C) => 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 periodStart?: number\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 currentPeriodStart?: 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 const result: CommandCodeUsage = {\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 // 未上报统计口径不能默认写成账期,客户端必须明确显示周期未确认。\n periodBasis: stringValue(usage.periodBasis) ?? 'unreported',\n }\n const start = periodTimestampValue(usage.periodStart)\n if (start > 0 && Number.isFinite(new Date(start).getTime())) result.periodStart = start\n return result\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 * Read the account identity and organization scope from whoami. Every billing\n * and usage request must use this same organization, so getUsage reads it first.\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\n/** 仅在宿主内部区分阶段;报告继续通过既有 failures 文本传递,避免更改严格远端协议。 */\ntype JsonResponseFailure =\n | { stage: 'read'; identifiers: readonly string[]; timedOut: boolean }\n | { stage: 'parse' }\n | { stage: 'shape'; shape: string }\n\nconst JSON_READ_ERROR_NAMES = new Set(['Error', 'TypeError', 'SyntaxError', 'AbortError', 'TimeoutError'])\nconst JSON_READ_ERROR_CODES = new Set([\n 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'ERR_STREAM_PREMATURE_CLOSE', 'ERR_INVALID_STATE',\n 'UND_ERR_SOCKET', 'UND_ERR_BODY_TIMEOUT', 'UND_ERR_ABORTED', 'Z_DATA_ERROR', 'Z_BUF_ERROR',\n])\nconst JSON_CONTENT_TYPES = new Set([\n 'application/json', 'application/problem+json', 'text/html', 'text/plain', 'application/octet-stream',\n])\nconst JSON_CONTENT_ENCODINGS = new Set(['identity', 'gzip', 'x-gzip', 'deflate', 'br', 'zstd'])\n\n/** 原异常消息可能包含正文、账号或地址,只保留白名单标识,并有界读取 cause 链。 */\nfunction jsonReadErrorIdentifiers(error: unknown): string[] {\n const identifiers = new Set<string>()\n const seen = new Set<unknown>()\n let current = error\n for (let depth = 0; depth < 4 && isRecord(current) && !seen.has(current); depth++) {\n seen.add(current)\n if (typeof current.name === 'string' && JSON_READ_ERROR_NAMES.has(current.name)) identifiers.add(current.name)\n if (typeof current.code === 'string' && JSON_READ_ERROR_CODES.has(current.code)) identifiers.add(current.code)\n current = current.cause\n }\n return [...identifiers]\n}\n\n/** 响应头只作为线索:不据此拒绝可解析正文,也不把未经筛选的头值放入账号报告。 */\nfunction jsonResponseMetadata(response: Response): string[] {\n const metadata: string[] = []\n const contentType = response.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase()\n if (contentType) metadata.push(`内容类型:${JSON_CONTENT_TYPES.has(contentType) ? contentType : '其他'}`)\n const encoding = response.headers.get('content-encoding')?.trim().toLowerCase()\n if (encoding) metadata.push(`内容编码:${JSON_CONTENT_ENCODINGS.has(encoding) ? encoding : '其他'}`)\n return metadata\n}\n\nfunction jsonResponseFailureDetail(response: Response, failure: JsonResponseFailure): string {\n let detail: string\n if (failure.stage === 'read') {\n const reason = failure.timedOut ? '读取响应正文超时' : '响应正文读取中断'\n detail = `${reason}${failure.identifiers.length === 0 ? '' : `(${failure.identifiers.join(' / ')})`}`\n } else if (failure.stage === 'parse') {\n detail = '响应正文不是有效的 JSON(结构化数据解析失败;SyntaxError)'\n } else {\n detail = `响应 JSON 顶层应为对象,实际为${failure.shape}`\n }\n const metadata = jsonResponseMetadata(response)\n return `${detail}${metadata.length === 0 ? '' : `;${metadata.join(';')}`}`\n}\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\ninterface RequestFacts<C> {\n connection: C\n catalog: Promise<CommandCodeModel[]>\n fallbackLimit: number\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private readonly gatewayFacts = new GatewayFacts(async (source) => {\n const { status, record } = await this.fetchJson(\n `${source.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 return record\n })\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 * The dimensions and byte target this route actually puts on the wire.\n *\n * The base default answers with the NORMALIZED original (`image.width`,\n * `image.height`, `image.bytes`), which is right only for an adapter that\n * does not resize. This route always re-encodes through\n * `readImageRequest(ref, requestImageTarget(ref))` — long edge 1568, encoded\n * bytes capped at 1 MiB — so the default would over-report both dimensions\n * and bytes for every image, most visibly for Retina screenshots.\n *\n * `imageRequestPricing` above already prices at this same target; exposing it\n * here keeps the harness's own readers (the CUA screenshot path calls\n * `ctx.llm.imageRequestTarget`) consistent with what the gateway receives.\n * @param _provider - registered provider route; one route per adapter here.\n * @param _model - exact model id; the target is model-independent on this route.\n * @param image - normalized attachment whose request projection is resolved.\n * @returns the same target `readImageRequest` encodes to, before base64 expansion.\n */\n override imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): ImageRequestTarget {\n return requestImageTarget(image)\n }\n\n override async listModels(\n provider: string,\n opts?: { unfiltered?: boolean },\n ): Promise<readonly LlmModelInfo[]> {\n const connection = { ...this.deps.options() }\n const catalog = await this.gatewayFacts.refresh(connection)\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 = connection.filterModelsByPlan === false\n ? undefined\n : await this.loadPoolBillingAccess(connection)\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 = connection.visibleModels\n const allow = Array.isArray(visible) ? visible.filter((id) => typeof id === 'string' && id !== '') : []\n const overrides = connection.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 const connection = { ...this.deps.options() }\n const entry = this.gatewayFacts.knownModel(connection, model) ??\n (await this.gatewayFacts.refresh(connection, 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 unusable bodies come back without a record; only\n * a failure before receiving the response propagates to the caller.\n * 正文读取、JSON 解析与顶层结构分别诊断,不能把已收到响应后的断流当成格式错误。\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>; responseFailure?: string }> {\n const requestSignal = signal ?? AbortSignal.timeout(timeoutMs)\n const response = await this.fetchImpl(url, {\n headers,\n // A hung account endpoint must not stall the picker / usage card forever.\n signal: requestSignal,\n })\n if (!response.ok) return { status: response.status }\n let text: string\n try {\n text = await response.text()\n } catch (error: unknown) {\n const identifiers = jsonReadErrorIdentifiers(error)\n if (requestSignal.aborted) {\n for (const identifier of jsonReadErrorIdentifiers(requestSignal.reason)) {\n if (!identifiers.includes(identifier)) identifiers.push(identifier)\n }\n }\n const timedOut = identifiers.includes('TimeoutError') || identifiers.includes('ETIMEDOUT')\n || identifiers.includes('UND_ERR_BODY_TIMEOUT')\n return {\n status: response.status,\n responseFailure: jsonResponseFailureDetail(response, { stage: 'read', identifiers, timedOut }),\n }\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n return {\n status: response.status,\n // JSON.parse 的原异常会回显正文片段;只保留解析阶段与固定异常名。\n responseFailure: jsonResponseFailureDetail(response, { stage: 'parse' }),\n }\n }\n if (isRecord(parsed)) return { status: response.status, record: parsed }\n const shape = parsed === null ? '空值' : Array.isArray(parsed) ? '数组'\n : typeof parsed === 'string' ? '字符串' : typeof parsed === 'number' ? '数字' : '布尔值'\n return {\n status: response.status,\n responseFailure: jsonResponseFailureDetail(response, { stage: 'shape', shape }),\n }\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(connection: C = { ...this.deps.options() }): Promise<readonly (CommandCodeBillingAccess | undefined)[] | undefined> {\n const keys = await this.poolAccountKeys(connection)\n if (keys.length === 0) return undefined\n const apiBase = connection.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(connection: C): Promise<readonly string[]> {\n try {\n const keys = await this.deps.resolveAccountKeys?.(connection)\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(connection)]\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, entry?: CommandCodeModel): boolean {\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(connection: C, apiKey: string, model: string, entry?: CommandCodeModel): CommandCodeProtocol {\n const { apiBase, protocol: forced } = connection\n if (forced === 'cli') return forced\n if (this.routesToMessages(model, entry)) 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, capturedConnection?: C): Promise<CommandCodeUsageReport> {\n const connection = capturedConnection ?? { ...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, responseFailure } = await this.fetchJson(\n `${base}${path}`,\n headers,\n connection.requestTimeoutMs,\n )\n if (record === undefined) {\n failures.push(`${path}: HTTP ${status}${responseFailure ? `;${responseFailure}` : ''}`)\n failed.push(responseFailure ? { 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 // 与官方命令行一致:先固定组织,再并行读取余额和订阅;汇总必须等账期起点。\n // 不使用本地自然月作为替代,订阅失败时仍让汇总独立降级。\n const whoami = await getJson('/alpha/whoami')\n const { account, orgId } = parseAccountIdentity(whoami)\n if (account !== undefined) report.account = account\n const scopedPath = (path: string, since?: string): string => {\n const params = new URLSearchParams()\n if (orgId !== undefined) params.set('orgId', orgId)\n if (since !== undefined) params.set('since', since)\n const query = params.toString()\n return query ? `${path}?${query}` : path\n }\n const [credits, subscription] = await Promise.all([\n getJson(scopedPath('/alpha/billing/credits')),\n getJson(scopedPath('/alpha/billing/subscriptions')),\n ])\n const subData = subscription !== undefined && isRecord(subscription.data) ? subscription.data : undefined\n const rawStart = subData?.currentPeriodStart\n const periodStart = periodTimestampValue(rawStart)\n const validStart = periodStart > 0 && Number.isFinite(new Date(periodStart).getTime())\n // 保留上游时间的字符串/毫秒表示,仅编码查询值,不重算日期或时区。\n const since = validStart ? String(rawStart) : undefined\n const usage = await getJson(scopedPath('/alpha/usage/summary', since))\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 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: periodTimestampValue(subData?.currentPeriodEnd),\n }\n if (validStart) report.plan.currentPeriodStart = periodStart\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, connection: C = { ...this.deps.options() }): Promise<{ exceeded: boolean; resetAt: number } | undefined> {\n try {\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 stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n // 迭代器可能延后消费;调用返回时就固定连接,不能等第一次 next() 再读设置。\n const connection: C = Object.freeze({ ...this.deps.options() })\n const facts: RequestFacts<C> = {\n connection,\n // 同时捕获目录状态;旧迭代器消费不能重新绑定并撤销新来源的刷新。\n catalog: this.gatewayFacts.snapshot(connection),\n fallbackLimit: modelOutputTokenLimit(connection.apiBase, options.model),\n }\n return ownedResponseStream(options.signal, signal => this.streamWithTiming(options, signal, facts))\n }\n\n private async *streamWithTiming(options: GenerateOptions, signal: AbortSignal, facts: RequestFacts<C>): 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, signal }, timing, facts)) {\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' : signal.aborted ? 'cancelled' : 'error'\n if (outcome !== 'cancelled') 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, facts: RequestFacts<C>): AsyncIterable<StreamChunk> {\n options.signal?.throwIfAborted()\n const { connection } = facts\n const catalog = await facts.catalog\n options.signal?.throwIfAborted()\n const modelEntry = catalog.find(row => row.id === options.model)\n const initialMax = Math.min(options.maxTokens ?? Infinity, modelEntry?.maxTokens ?? facts.fallbackLimit, DEFAULT_GENERATE_MAX_TOKENS)\n const budget = { max: initialMax, sent: initialMax }\n for (let attempt = 0; ; attempt++) {\n let delivered = false\n try {\n for await (const chunk of this.streamAttempt(options, timing, connection, modelEntry, budget)) {\n delivered = true\n yield chunk\n }\n return\n } catch (error) {\n const ceiling = delivered ? undefined : outputCeilingRefusal(connection.apiBase, options.model, budget.sent, error)\n if (attempt > 0 || ceiling === undefined) throw error\n budget.max = Math.min(budget.max, ceiling)\n }\n }\n }\n\n private async *streamAttempt(\n options: GenerateOptions,\n timing: RequestTiming,\n connection: C,\n modelEntry: CommandCodeModel | undefined,\n budget: { max: number; sent: number },\n ): AsyncIterable<StreamChunk> {\n options.signal?.throwIfAborted()\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 options.signal?.throwIfAborted()\n let maxTokens = Math.min(budget.max, learnedOutputLimit(connection.apiBase, options.model))\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n // `off` carries two meanings, and only the snapshot tells them apart. The\n // host passes it as \"no reasoning strength requested\" — the Messages\n // transport's `output_config.effort` has no `none`, so it must send no\n // `output_config` at all (measured, see docs/agent-reference/\n // adapter-protocol.md). But since command-code@1.73.3 the DeepSeek V4 line\n // publishes `off` as a real level, and the official CLI sends it verbatim\n // as `reasoning_effort:\"off\"` (its body builder spreads the effort\n // whenever it is a non-empty string) instead of dropping the field. So a\n // model that LISTS `off` gets it on the wire; every other model keeps\n // dropping it, which is what the unsupported-effort path relies on.\n const declared = effort !== undefined && supported?.includes(effort) ? effort : undefined\n const reasoningEffort = effort === 'off' && declared === undefined ? undefined : declared\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, apiKey, options.model, modelEntry)\n // 反代 messages 端点对本次账号的权限拒绝(issue #84)。只活在一次 stream()\n // 调用里,并在最终错误文案中留痕:它描述的是这一条 Claude 链路,既不能\n // 缓存成整个网关的协议结论,也不该覆盖 CLI 直连自己的失败原因。\n let messagesPermissionRejection: string | undefined\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,\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 // 最后一次异步装配之后再收紧,指纹、正文及实发预算必须描述同一次连接。\n const lower = Math.min(maxTokens, learnedOutputLimit(connection.apiBase, options.model))\n if (lower < maxTokens) {\n maxTokens = lower\n budget.max = Math.min(budget.max, lower)\n if (protocol === 'cli') recordOrEmpty(body.params).max_tokens = lower\n else body.max_tokens = lower\n serializedBodies.delete(body)\n }\n budget.sent = maxTokens\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 // 第二类触发(issue #84):messages 端点用 `permission_error` 拒绝。\n // 反代转发 Claude 的那条链路可能单独对该账号失效,而同一把密钥的 CLI\n // 直连仍然可用(2026-10-14 实测:GOAT 账号请求 /alpha/generate +\n // claude-haiku-5-5 正常返回)。触发面由\n // `isMessagesPermissionRejection` 收紧到 403 加结构化 permission_error,\n // 其余权限失败继续原样上报,避免把真实限制伪装成传输问题。\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 const messagesPermissionDenied = protocol === 'messages'\n && isMessagesPermissionRejection(attempt.status, providerError)\n if (\n protocol !== 'cli'\n && (messagesPermissionDenied\n || isUpgradeRequiredError(attempt.status, attempt.errText, providerError))\n ) {\n const wasMessages = protocol === 'messages'\n if (messagesPermissionDenied) {\n messagesPermissionRejection = providerError.code ?? providerError.type\n }\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 // 权限拒绝同理:它属于刚被换下的那把密钥,不能跟着新账号继续报。\n messagesPermissionRejection = undefined\n const nextProtocol = this.resolveProtocol(connection, apiKey, options.model, modelEntry)\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(\n attempt.status, attempt.errText, attempt.retryAfterMs, providerError, messagesPermissionRejection,\n )\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 yield* settleStreamResponse(response, {\n protocol, signal: options.signal, maxTokens,\n apiBase: connection.apiBase, streamIdleTimeoutMs: connection.streamIdleTimeoutMs,\n cleanup, trace, timing, responseMetadata,\n })\n }\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 响应正文读取或解析失败,请根据下方详情排查并重试',\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 'Reading or parsing the Command Code response failed; check the details below and retry',\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/** 只有官方汇总与订阅共同确认同一起点,才展示完整账期;旧宿主和部分响应保持未知。 */\nexport function formatUsageBillingPeriod(usageStart: number | undefined, planStart: number | undefined, planEnd: number | undefined): string {\n if (usageStart === undefined || planStart !== usageStart || planEnd === undefined || usageStart <= 0 || planEnd <= usageStart) return ''\n const start = new Date(usageStart)\n const end = new Date(planEnd)\n if (!Number.isFinite(start.getTime()) || !Number.isFinite(end.getTime())) return ''\n return `${start.toLocaleDateString()} – ${end.toLocaleDateString()}`\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.totalCount))\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 * 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 if (usage.periodStart !== undefined) {\n report.usage.periodStart = numberField(usage, 'periodStart', 'usage.periodStart')\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 if (plan.currentPeriodStart !== undefined) {\n report.plan.currentPeriodStart = numberField(plan, 'currentPeriodStart', 'plan.currentPeriodStart')\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","/** 账号开通的双方使用契约。状态和恢复记录不携带密钥,密钥只出现在手动开通输入。 */\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport { makeBoundaryValidator, makeRemoteDescriptor, makeStrictCodec, REMOTE_PACKAGE } from './wire-shared.ts'\n\nexport interface EnrollmentInput {\n id: string\n pageId: string\n mode: 'browser' | 'manual'\n label: string\n /** 用户未填写名称时,允许使用浏览器登录返回的账号名。 */\n automaticName: boolean\n key?: string\n}\nexport type EnrollmentPhase = 'creating' | 'waiting' | 'writing' | 'naming' | 'finished' | 'cancelling' | 'cancelled' | 'failed' | 'cleanup-needed'\nexport interface EnrollmentState {\n id: string\n ref: string\n phase: EnrollmentPhase\n message: string\n authUrl?: string\n suggestedName?: string\n}\n/** 配置中的恢复日志:先登记,再写凭据;只保留引用与阶段,不保留密钥或连接身份。 */\nexport interface EnrollmentRecord {\n id: string\n ref: string\n phase: 'pending' | 'naming' | 'cleanup'\n label: string\n}\nconst guard = makeBoundaryValidator('commandcode/enrollment')\nconst phases: readonly EnrollmentPhase[] = ['creating', 'waiting', 'writing', 'naming', 'finished', 'cancelling', 'cancelled', 'failed', 'cleanup-needed']\nexport function parseEnrollmentState(value: unknown): EnrollmentState {\n const source = guard.record(value, 'state')\n const phase = source.phase\n if (!phases.includes(phase as EnrollmentPhase)) return guard.reject('phase')\n const state: EnrollmentState = {\n id: guard.stringField(source, 'id', 'id'), ref: guard.stringField(source, 'ref', 'ref'),\n phase: phase as EnrollmentPhase, message: guard.stringField(source, 'message', 'message'),\n }\n for (const field of ['authUrl', 'suggestedName'] as const) {\n if (source[field] !== undefined) state[field] = guard.stringField(source, field, field)\n }\n return state\n}\nexport function parseEnrollmentInput(value: unknown): EnrollmentInput {\n const source = guard.record(value, 'input')\n const id = guard.stringField(source, 'id', 'id')\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(id)) return guard.reject('id')\n if (source.mode !== 'browser' && source.mode !== 'manual') return guard.reject('mode')\n const input: EnrollmentInput = {\n id, pageId: parsePage(source).pageId, mode: source.mode, label: guard.stringField(source, 'label', 'label').trim(),\n automaticName: guard.booleanField(source, 'automaticName', 'automaticName'),\n }\n if (!input.label || input.label.length > 200) return guard.reject('label')\n if (input.mode === 'manual') {\n input.key = guard.stringField(source, 'key', 'key').trim()\n if (!input.key) return guard.reject('key')\n } else if (source.key !== undefined) return guard.reject('key')\n return input\n}\nexport interface EnrollmentPage { pageId: string }\nfunction parsePage(value: unknown): EnrollmentPage {\n const source = guard.record(value, 'page')\n const pageId = guard.stringField(source, 'pageId', 'pageId')\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(pageId)) return guard.reject('pageId')\n return { pageId }\n}\nexport interface EnrollmentAction extends EnrollmentPage { id: string; name?: string }\nconst actionSchema: TypertSchema<EnrollmentAction> = {\n parse(value) {\n const source = guard.record(value, 'action')\n const action: EnrollmentAction = { id: guard.stringField(source, 'id', 'id'), ...parsePage(source) }\n if (!/^[a-zA-Z0-9-]{16,80}$/.test(action.id)) return guard.reject('id')\n if (source.name !== undefined) action.name = guard.stringField(source, 'name', 'name').trim()\n if (action.name !== undefined && (!action.name || action.name.length > 200)) return guard.reject('name')\n return action\n },\n}\nconst stateSchema = { parse: parseEnrollmentState }\nconst listSchema: TypertSchema<EnrollmentState[]> = {\n parse(value) { return Array.isArray(value) ? value.map(parseEnrollmentState) : guard.reject('list') },\n}\nexport const ENROLLMENT_DESCRIPTORS: readonly InvocationDescriptor[] = [\n ...['enrollmentBegin', 'enrollmentStatus', 'enrollmentCancel', 'enrollmentName', 'enrollmentRetry'].map((method) => ({\n ...makeRemoteDescriptor(`commandcode/${method}`, method, `${REMOTE_PACKAGE}#EnrollmentState`, stateSchema),\n parameters: [{ name: 'input', wire: 'input', source: 'json' as const,\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#${method}Input`, method === 'enrollmentBegin' ? { parse: parseEnrollmentInput } : actionSchema) }],\n })),\n { ...makeRemoteDescriptor('commandcode/enrollmentPending', 'enrollmentPending', `${REMOTE_PACKAGE}#EnrollmentStateList`, listSchema),\n parameters: [{ name: 'input', wire: 'input', source: 'json', codec: makeStrictCodec(`${REMOTE_PACKAGE}#EnrollmentPage`, { parse: parsePage }) }] },\n { ...makeRemoteDescriptor('commandcode/enrollmentWatch', 'enrollmentWatch', `${REMOTE_PACKAGE}#EnrollmentReady`, {\n parse(value: unknown) { return value === true ? true : guard.reject('ready') },\n }), mode: 'stream',\n parameters: [{ name: 'input', wire: 'input', source: 'json', codec: makeStrictCodec(`${REMOTE_PACKAGE}#EnrollmentPage`, { parse: parsePage }) }] },\n]\nexport const ENROLLMENT_REMOTE_CONTRIBUTION: TypertRemoteContribution = { package: REMOTE_PACKAGE, descriptors: ENROLLMENT_DESCRIPTORS }\n","/**\n * Host half of the Command Code Remotes (`commandcode/report`,\n * `commandcode/models`, `commandcode/prices`, `commandcode/analytics`, `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'\nimport { ENROLLMENT_DESCRIPTORS, type EnrollmentAction, type EnrollmentInput, type EnrollmentPage, type EnrollmentState } from './enrollment-wire.ts'\nimport type { AccountEnrollmentManager } from './enrollment.ts'\nimport { ANALYTICS_DESCRIPTOR, type AnalyticsQuery, type AnalyticsReport } from './analytics-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 enrollment?: AccountEnrollmentManager\n analytics?: (query: AnalyticsQuery, signal?: AbortSignal) => Promise<AnalyticsReport>\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 async analytics(query: AnalyticsQuery): Promise<AnalyticsReport> {\n if (!this.deps.analytics) throw new Error('宿主不支持模型分析,请更新插件')\n return this.deps.analytics(query, this.ctx.invocation?.signal)\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 async enrollmentBegin(input: EnrollmentInput): Promise<EnrollmentState> {\n const manager = this.requireEnrollment()\n const owner = this.enrollmentOwner(input)\n if (!manager.hasPage(owner)) throw new Error('账号开通页面观察流未建立')\n return manager.begin(owner, input)\n }\n async enrollmentStatus(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().status(this.enrollmentOwner(input), input.id)\n }\n async enrollmentCancel(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().cancel(this.enrollmentOwner(input), input.id)\n }\n async enrollmentName(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().name(this.enrollmentOwner(input), input.id, input.name)\n }\n async enrollmentRetry(input: EnrollmentAction): Promise<EnrollmentState> {\n return this.requireEnrollment().retry(this.enrollmentOwner(input), input.id, input.name)\n }\n async enrollmentPending(input: EnrollmentPage): Promise<EnrollmentState[]> { return this.requireEnrollment().pending(this.enrollmentOwner(input)) }\n async *enrollmentWatch(input: EnrollmentPage): AsyncIterable<boolean> {\n const invocation = this.ctx.invocation\n if (!invocation) throw new Error('账号开通必须从已连接的页面调用')\n const manager = this.requireEnrollment()\n const release = manager.watch(this.enrollmentOwner(input))\n let abort: (() => void) | undefined\n try {\n const ended = new Promise<void>((resolve) => {\n abort = () => resolve()\n invocation.signal.addEventListener('abort', abort, { once: true })\n if (invocation.signal.aborted) resolve()\n })\n if (invocation.signal.aborted) return\n yield true\n await ended\n } finally {\n if (abort) invocation.signal.removeEventListener('abort', abort)\n release()\n }\n }\n private enrollmentOwner(input: EnrollmentPage): string { return `${this.enrollmentPeer().id}:${input.pageId}` }\n private enrollmentPeer() {\n const invocation = this.ctx.invocation\n if (!invocation) throw new Error('账号开通必须从已连接的页面调用')\n return invocation.peer\n }\n private requireEnrollment(): AccountEnrollmentManager {\n if (!this.deps.enrollment) throw new Error('宿主不支持账号开通,请更新插件')\n return this.deps.enrollment\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, ANALYTICS_DESCRIPTOR, ...LOGIN_HOST_CONTRIBUTION.invocations, ...ENROLLMENT_DESCRIPTORS],\n })\n // The registry's own effect would outlive this fiber; withdraw the\n // contribution when the plugin unloads.\n remoteCtx.effect(() => () => void unregister(), 'dsh-commandcode-provider: usage remote')\n })\n}\n","/**\n * Host half of the Command Code browser login (the loopback flow), 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 /** 取消只能阻止尚未发出的写入;补偿者须等这些实际存储任务结束。 */\n private readonly pendingStores = new Set<Promise<void>>()\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 /** 结束验证/监听并等待已开始的写入,供账号开通过程安全补偿。 */\n async cancelAndDrain(): Promise<void> {\n this.cancel()\n await this.starting?.catch(() => undefined)\n this.cancel()\n await Promise.allSettled([...this.pendingStores])\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 START a key write or publish a status. A write already\n * handed to storage is tracked separately: cancelAndDrain() lets the owning\n * enrollment wait for it before compensation, without pretending it can be\n * aborted halfway through.\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 const store = Promise.resolve().then(() => {\n // 微任务排队期间的取消仍应阻止副作用。\n if (this.ownsAttempt(attempt)) return this.deps.storeKey(credentials, targetRef)\n })\n this.pendingStores.add(store)\n try { await store } finally { this.pendingStores.delete(store) }\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","/** 宿主拥有账号开通的副作用;页面/连接只拥有取消权。恢复日志先于凭据写入落盘。 */\nimport type { EnrollmentInput, EnrollmentRecord, EnrollmentState } from './enrollment-wire.ts'\nimport type { CommandCodeLoginCredentials } from './login.ts'\nimport type { CommandCodeLoginStatus } from './login-wire.ts'\n\ninterface Account { label?: string; apiKeyEnv?: string; apiKey?: string }\nexport interface EnrollmentConfig {\n apiKeyEnv?: string\n accounts?: Account[]\n accountEnrollmentTasks?: EnrollmentRecord[]\n credentialCleanupRefs?: string[]\n modelAccountRules?: { models: string[]; account: string }[]\n activeAccount?: string\n}\nexport interface EnrollmentSettings {\n writable: boolean\n read(): { value: EnrollmentConfig; revision: number; base?: EnrollmentConfig }\n mutate(ops: { op: 'set'; path: string[]; value: unknown }[], revision: number): Promise<void>\n}\nexport interface EnrollmentLogin {\n begin(ref?: string): Promise<CommandCodeLoginStatus>\n status(): CommandCodeLoginStatus\n onChange(listener: () => void): () => void\n cancelAndDrain(): Promise<void>\n dispose(): void\n}\nexport interface EnrollmentDeps {\n settings(): EnrollmentSettings | undefined\n describe(ref: string): Promise<{ configured: boolean; writable: boolean }>\n set(ref: string, key: string): Promise<void>\n unset(ref: string): Promise<void>\n login(store: (credentials: CommandCodeLoginCredentials) => Promise<void>): EnrollmentLogin\n}\ninterface Task {\n owner: string\n state: EnrollmentState\n cancelled: boolean\n writeStarted?: boolean\n cleanupStarted?: boolean\n work?: Promise<void>\n flow?: EnrollmentLogin\n}\nconst terminal = (state: EnrollmentState) => ['finished', 'cancelled', 'failed', 'cleanup-needed', 'naming'].includes(state.phase)\n\nexport class AccountEnrollmentManager {\n private readonly tasks = new Map<string, Task>()\n private writes: Promise<unknown> = Promise.resolve()\n private closed = false\n private readonly pages = new Set<string>()\n constructor(private readonly deps: EnrollmentDeps) {}\n /** 每页独立的持续调用才代表页面生命期;宿主的 operator Peer 由所有浏览器共享。 */\n watch(owner: string): () => void {\n if (this.closed || this.pages.has(owner)) throw new Error('账号开通页面已关闭或重复连接')\n this.pages.add(owner)\n return () => { this.pages.delete(owner); this.disconnect(owner) }\n }\n hasPage(owner: string): boolean { return this.pages.has(owner) }\n\n /** begin 不等待整个过程;客户端预先生成的 id 让早到的取消也能生效。 */\n begin(owner: string, input: EnrollmentInput): EnrollmentState {\n this.prune()\n const existing = this.tasks.get(input.id)\n if (existing) return this.owned(owner, input.id).state\n if (this.closed) throw new Error('账号开通服务已关闭')\n if (this.records().some((record) => record.id === input.id)) throw new Error('已有未完成记录,请先处理')\n const task: Task = { owner, cancelled: false, state: { id: input.id, ref: '', phase: 'creating', message: '正在创建账号' } }\n this.tasks.set(input.id, task)\n task.work = this.run(task, input).catch(() => {\n task.state = { ...task.state, phase: 'cleanup-needed', message: '收尾未完成,请重试' }\n })\n return task.state\n }\n status(owner: string, id: string): EnrollmentState {\n const task = this.tasks.get(id)\n if (task) return this.owned(owner, id).state\n const record = this.records().find((record) => record.id === id)\n if (!record) throw new Error('账号开通过程不存在')\n return this.recovered(record)\n }\n pending(owner: string): EnrollmentState[] {\n return this.records().filter((record) => {\n const task = this.tasks.get(record.id)\n return !task || ((task.owner === '' || task.owner === owner) && terminal(task.state))\n })\n .map((record) => this.tasks.get(record.id)?.state ?? this.recovered(record))\n }\n /** 离开已登录的待命名过程等同接受已有名称,其余阶段等待写入结束再补偿。 */\n async cancel(owner: string, id: string): Promise<EnrollmentState> {\n this.prune()\n let task = this.tasks.get(id)\n if (!task) {\n if (this.records().some((record) => record.id === id)) return this.retry(owner, id)\n // 取消先于 begin 到达时留下墓碑,不能随后创建账号。\n task = { owner, cancelled: true, state: { id, ref: '', phase: 'cancelled', message: '已取消' } }\n this.tasks.set(id, task)\n return task.state\n }\n task = this.owned(owner, id)\n if (task.state.phase === 'naming') return this.name(owner, id)\n if (terminal(task.state)) return task.state\n task.cancelled = true\n task.state = { ...task.state, phase: 'cancelling', message: '正在等待写入结束并清理' }\n await task.flow?.cancelAndDrain()\n await task.work\n return task.state\n }\n disconnect(owner: string): void {\n for (const [id, task] of this.tasks) if (task.owner === owner) void this.cancel(owner, id).catch(() => {}).finally(() => { task.owner = '' })\n }\n dispose(): void { this.closed = true; for (const task of this.tasks.values()) this.disconnect(task.owner) }\n\n async name(owner: string, id: string, name?: string): Promise<EnrollmentState> {\n const task = this.tasks.get(id)\n if (task) this.owned(owner, id)\n const record = this.records().find((item) => item.id === id)\n if (!record && task?.state.phase === 'finished') return task.state\n if (!record || (record.phase !== 'naming' && task?.state.phase !== 'naming')) throw new Error('账号尚未进入待命名阶段')\n try {\n await this.change((value) => {\n const accounts = value.accounts ?? []\n if (!accounts.some((account) => account.apiKeyEnv === record.ref)) throw new Error('账号已被移除')\n return {\n ...(name?.trim() ? { accounts: accounts.map((account) => account.apiKeyEnv === record.ref ? { ...account, label: name.trim() } : account) } : {}),\n accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).filter((item) => item.id !== id),\n }\n })\n return this.publish(task, { id, ref: record.ref, phase: 'finished', message: '账号开通完成' })\n } catch {\n return this.publish(task, { id, ref: record.ref, phase: 'naming', message: '账号已登录,名称保存失败,请重试或接受已有名称', ...(name ? { suggestedName: name } : {}) })\n }\n }\n async retry(owner: string, id: string, name?: string): Promise<EnrollmentState> {\n const existing = this.tasks.get(id)\n if (existing) {\n this.owned(owner, id)\n await existing.work\n if (!terminal(existing.state)) throw new Error('账号开通仍在进行')\n }\n const record = this.records().find((item) => item.id === id)\n if (!record) return this.status(owner, id)\n if (record.phase === 'naming' || existing?.state.phase === 'naming') return this.name(owner, id, name)\n const task = existing ?? { owner, cancelled: true, writeStarted: true, state: this.recovered(record) }\n this.tasks.set(id, task)\n task.work = this.cleanup(task).catch(() => { task.state = { ...task.state, phase: 'cleanup-needed', message: '清理未完成,请重试' } })\n await task.work\n return task.state\n }\n private async run(task: Task, input: EnrollmentInput): Promise<void> {\n try {\n await this.change(async (value) => {\n const base = value.apiKeyEnv ?? 'COMMANDCODE_API_KEY'\n const occupied = new Set([base, ...(value.accounts ?? []).map((account) => account.apiKeyEnv), ...(value.credentialCleanupRefs ?? []), ...(value.accountEnrollmentTasks ?? []).map((item) => item.ref)])\n let n = 2\n let ref = ''\n // 配置未引用的环境/存储密钥也属于已占用引用,不能用新开通覆盖。\n for (let attempt = 0; attempt < 128; attempt++, n++) {\n if (occupied.has(`${base}_${n}`)) continue\n const candidate = `${base}_${n}`\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(candidate)) throw new Error('凭据引用无效')\n const info = await this.deps.describe(candidate)\n if (info.configured) continue\n if (!info.writable) throw new Error('凭据不可写')\n ref = candidate\n break\n }\n if (!ref) throw new Error('没有可用凭据引用')\n task.state = { ...task.state, ref }\n return {\n accounts: [...(value.accounts ?? []), { label: input.label, apiKeyEnv: ref }],\n accountEnrollmentTasks: [...(value.accountEnrollmentTasks ?? []), { id: input.id, ref, phase: 'pending', label: input.label }],\n }\n })\n if (task.cancelled) return await this.cleanup(task)\n const info = await this.deps.describe(task.state.ref)\n // 分配引用不应覆盖环境或其他凭据;真正写入仍由凭据服务执行权限检查。\n if (info.configured || !info.writable) throw new Error('凭据引用已占用或不可写')\n let suggested: string | undefined\n if (input.mode === 'manual') await this.store(task, input.key!)\n else {\n const flow = this.deps.login(async (credentials) => { await this.store(task, credentials.apiKey) })\n task.flow = flow\n const result = await new Promise<CommandCodeLoginStatus>((resolve, reject) => {\n const off = flow.onChange(() => {\n const status = flow.status()\n if (status.state === 'success' || status.state === 'failed') { off(); resolve(status) }\n })\n void flow.begin(task.state.ref).then((status) => {\n if (!task.cancelled && status.state === 'waiting') task.state = { ...task.state, phase: 'waiting', message: '等待浏览器登录', ...(status.authUrl ? { authUrl: status.authUrl } : {}) }\n if (task.cancelled) void flow.cancelAndDrain()\n }, (error: unknown) => { off(); reject(error) })\n })\n if (result.state !== 'success') throw new Error('浏览器登录未完成')\n suggested = input.automaticName ? result.userName?.trim() : undefined\n }\n if (task.cancelled) return await this.cleanup(task)\n // 先登记已登录事实,再尝试命名。命名失败绝不走删除凭据的补偿分支。\n task.state = { ...task.state, phase: 'naming', message: '账号已登录,正在保存名称', ...(suggested ? { suggestedName: suggested } : {}) }\n try {\n await this.change((value) => ({ accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).map((item) => item.id === input.id ? { ...item, phase: 'naming', label: suggested || item.label } : item) }))\n } catch {\n if (task.state.phase === 'finished') return\n task.state = { ...task.state, message: '账号已登录,名称保存失败,请重试或接受已有名称' }\n return\n }\n await this.name(task.owner, input.id, suggested)\n } catch {\n // 清理本身失败必须留待用户重试,不能被开通失败分支再次自动执行。\n if (task.cleanupStarted) throw new Error('账号清理未完成')\n await task.flow?.cancelAndDrain()\n if (task.state.ref && this.records().some((item) => item.id === task.state.id)) await this.cleanup(task)\n else task.state = { ...task.state, phase: task.cancelled ? 'cancelled' : 'failed', message: task.cancelled ? '已取消' : '账号开通失败,未创建账号' }\n } finally { task.flow?.dispose() }\n }\n private async store(task: Task, key: string): Promise<void> {\n if (task.cancelled) throw new Error('已取消')\n task.state = { ...task.state, phase: 'writing', message: '正在保存凭据' }\n task.writeStarted = true\n await this.deps.set(task.state.ref, key)\n if (!(await this.deps.describe(task.state.ref)).configured) throw new Error('凭据写入未确认')\n }\n private async cleanup(task: Task): Promise<void> {\n task.cleanupStarted = true\n const { id, ref } = task.state\n const snapshot = this.settings().read()\n if ((snapshot.value.apiKeyEnv ?? 'COMMANDCODE_API_KEY') === ref || snapshot.base?.accounts?.some((account) => account.apiKeyEnv === ref)) throw new Error('不能清理默认或继承账号')\n await this.change((value) => {\n const record = (value.accountEnrollmentTasks ?? []).find((item) => item.id === id)\n if (!record || record.phase === 'naming') throw new Error('不能清理已登录账号')\n return {\n accounts: (value.accounts ?? []).filter((account) => account.apiKeyEnv !== ref),\n modelAccountRules: (value.modelAccountRules ?? []).filter((rule) => rule.account !== ref),\n ...(value.activeAccount === ref ? { activeAccount: '' } : {}),\n credentialCleanupRefs: [...new Set([...(value.credentialCleanupRefs ?? []), ref])],\n accountEnrollmentTasks: (value.accountEnrollmentTasks ?? []).map((item) => item.id === id ? { ...item, phase: 'cleanup' } : item),\n }\n })\n const value = this.settings().read().value\n if ((value.apiKeyEnv ?? 'COMMANDCODE_API_KEY') === ref || (value.accounts ?? []).some((account) => account.apiKeyEnv === ref) || (value.modelAccountRules ?? []).some((rule) => rule.account === ref) || value.activeAccount === ref) throw new Error('引用仍被使用,不能清理')\n const info = await this.deps.describe(ref)\n if (info.configured && task.writeStarted) {\n if (!info.writable) throw new Error('凭据不可清理')\n await this.deps.unset(ref)\n if ((await this.deps.describe(ref)).configured) throw new Error('凭据删除未确认')\n }\n await this.change((current) => ({\n accountEnrollmentTasks: (current.accountEnrollmentTasks ?? []).filter((item) => item.id !== id),\n credentialCleanupRefs: (current.credentialCleanupRefs ?? []).filter((item) => item !== ref),\n }))\n task.state = { id, ref, phase: task.cancelled ? 'cancelled' : 'failed', message: task.cancelled ? '已取消并清理' : '开通失败,已清理临时账号' }\n }\n private settings(): EnrollmentSettings {\n const settings = this.deps.settings()\n if (!settings?.writable) throw new Error('设置服务不可写')\n return settings\n }\n private records(): EnrollmentRecord[] { return this.deps.settings()?.read().value.accountEnrollmentTasks ?? [] }\n private change(patch: (value: EnrollmentConfig) => Record<string, unknown> | Promise<Record<string, unknown>>): Promise<void> {\n const work = this.writes.catch(() => {}).then(async () => {\n const settings = this.settings()\n const { value, revision } = settings.read()\n const fields = await patch(value)\n await settings.mutate(Object.entries(fields).map(([key, item]) => ({ op: 'set', path: [key], value: item })), revision)\n })\n this.writes = work\n return work\n }\n private owned(owner: string, id: string): Task {\n const task = this.tasks.get(id)\n if (!task || (task.owner !== '' && task.owner !== owner)) throw new Error('不能操作其他连接的开通过程')\n if (task.owner === '') task.owner = owner\n return task\n }\n private publish(task: Task | undefined, state: EnrollmentState): EnrollmentState { if (task) task.state = state; return state }\n /** 只淘汰已完成且没有恢复日志的旧状态,活跃过程和未收尾事实始终保留。 */\n private prune(): void {\n if (this.tasks.size < 256) return\n const recorded = new Set(this.records().map((record) => record.id))\n for (const [id, task] of this.tasks) {\n if (this.tasks.size < 256) break\n if (terminal(task.state) && !recorded.has(id) && !this.pages.has(task.owner)) this.tasks.delete(id)\n }\n }\n private recovered(record: EnrollmentRecord): EnrollmentState {\n return { id: record.id, ref: record.ref, phase: record.phase === 'naming' ? 'naming' : 'cleanup-needed', message: record.phase === 'naming' ? '已登录账号等待确认名称' : '账号开通收尾未完成,请重试', ...(record.phase === 'naming' ? { suggestedName: record.label } : {}) }\n }\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 /** 使用搜索已捕获的网关解析账号,探测不能在等待后转到另一个网关。 */\n resolveKey(apiBase?: string): 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, apiBase)\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, apiBase: string): Promise<string> {\n let key: string | undefined\n try {\n key = await this.deps.resolveKey(apiBase)\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 every\n * supported engine ships `~3.18.4` or `~3.18.5-alpha.1`, so the\n * method is 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 { createAnalyticsReader } from './analytics-history.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, captureAccountSelection, type CommandCodeAccountSelection } 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 { AccountEnrollmentManager, type EnrollmentSettings } from './enrollment.ts'\nimport type { EnrollmentRecord } from './enrollment-wire.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 accountEnrollmentTasks?: EnrollmentRecord[]\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 accountEnrollmentTasks: z.array(z.object({\n id: z.string(), ref: z.string().role('credential-ref'),\n phase: z.union(['pending', 'naming', 'cleanup']), label: z.string(),\n })),\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 accountSelection?: CommandCodeAccountSelection\n}\n\n/** 宿主入口总是携带账号定义;程序化连接解析仍兼容既有返回形状。 */\ntype HostCommandCodeOptions = ResolvedCommandCodeOptions & { accountSelection: CommandCodeAccountSelection }\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 = (): HostCommandCodeOptions => {\n const raw = current()\n return { ...resolveAdapterOptions(raw), accountSelection: captureAccountSelection({\n slots: slots(raw), preferredId: preferredId(raw), modelAccountRules: raw.modelAccountRules ?? [],\n }) }\n }\n\n // 账号定义与连接同步捕获;本次内部轮换固定定义,新调用读取新配置。\n const slots = (raw: Config = current()): CommandCodeAccountSlot[] => {\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 // 临时账号即使已写入密钥,也不能在开通完成前进入轮转池。\n if (raw.accountEnrollmentTasks?.some((task) => task.ref === refName && task.phase !== 'naming')) continue\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 // 固定账号与账号列表来自同一次配置读取,避免等待后拼接不同版本。\n const preferredId = (config: Config = current()): string | undefined => {\n const raw = config.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 seam owns the layer order, and that order is engine-dependent: the\n // provider-managed store wins over the inherited environment from\n // 0.2.1-alpha.3 on, where the environment used to win. This call does not\n // care which — it asks for the resolved value — but a miss here is\n // genuinely unconfigured, not \"absent from the store\".\n const hit = await credentials.resolve(ref)\n return hit?.value\n }\n // No service means the headless profile, which disables the credentials\n // line on purpose: only the launch environment (process, project `.env`,\n // `$DSH_HOME/.env`) is left, so a key saved only in the product store is\n // deliberately invisible to a one-shot run.\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 // 所有调用者显式持有连接;恢复探测与健康状态不能使用等待后才读取的新网关。\n const scopedPool = (connection: HostCommandCodeOptions): CommandCodeAccountPool => pool.scope({\n apiBase: connection.apiBase,\n ...connection.accountSelection,\n probeWindow: (key) => adapter.probeWindowLimits(key, connection),\n })\n\n const resolveApiKey = async (connection: HostCommandCodeOptions, model?: string): Promise<string> => {\n const resolved = await scopedPool(connection).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. The headless profile mounts no credentials service, so a'\n + ' key saved only in the store never reaches it: export the variable or put it in a'\n + ' .env file for those runs.',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter: CommandCodeAdapter<HostCommandCodeOptions> = 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: HostCommandCodeOptions,\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 const accounts = scopedPool(connection)\n if (rejection !== 'unavailable') accounts.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 accounts.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 (connection): Promise<readonly string[]> => {\n const accounts = await scopedPool(connection).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 const connection = options()\n const accounts = scopedPool(connection)\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 // 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 accounts.activeAccount()\n // 先完成共享恢复,再读健康事实;不能用探测前的标记展示已恢复账号。\n const described = await accounts.describeAccounts()\n const byId = new Map(described.map((account) => [account.slot.id, account]))\n const entries = await Promise.all(connection.accountSelection.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, connection)\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 let enrollmentSettings: EnrollmentSettings | undefined\n const enrollment = new AccountEnrollmentManager({\n settings: () => enrollmentSettings,\n describe: async (ref) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n return credentials.describe(credentialRef(ref))\n },\n set: async (ref, key) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n await credentials.set(credentialRef(ref), key)\n },\n unset: async (ref) => {\n const credentials = ctx.get('credentials')\n if (!credentials) throw new Error('凭据服务不可用')\n await credentials.unset(credentialRef(ref))\n },\n login: (storeKey) => new CommandCodeLoginFlow({ apiBase: () => options().apiBase, storeKey }),\n })\n ctx.effect(() => () => enrollment.dispose(), 'dsh-commandcode-provider: account enrollment')\n applyUsageRemote(ctx, { adapter, reports: usageReports, login: loginFlow, enrollment, listModels: catalogForEditors, analytics: createAnalyticsReader(ctx, adapter) })\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 (apiBase) => {\n const connection = options()\n if (apiBase !== undefined) connection.apiBase = apiBase\n const resolved = await scopedPool(connection).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 const settings = settingsCtx.settings\n enrollmentSettings = {\n get writable() { return settings.writable },\n read: () => {\n // 宿主读取完整值,再按字段修改,避免把被遮蔽的组合配置密钥覆盖掉。\n const descriptor = settings.describe().find((item) => item.ns === NS)\n if (!descriptor) throw new Error('账号设置不存在')\n return { value: descriptor.value as Config, revision: descriptor.revision, ...(descriptor.base ? { base: descriptor.base as Config } : {}) }\n },\n mutate: (ops, revision) => settings.mutate(NS, ops, revision),\n }\n settingsCtx.effect(() => () => { enrollmentSettings = undefined }, 'dsh-commandcode-provider: enrollment settings')\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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"}