@mars-sea/dsh-commandcode-provider 0.12.1 → 0.12.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.d.ts CHANGED
@@ -1,11 +1,26 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
- import { GenerateOptions, LlmAdapter, LlmImageRequestPricing, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, ResolvedRetryPolicy, StreamChunk, projectOffloadedImages, requiredImageOffload } from "@deepseek-ai/dsh-llm";
2
+ import { GenerateOptions, LlmAdapter, LlmError, LlmImageRequestPricing, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, ResolvedRetryPolicy, StreamChunk, projectOffloadedImages, requiredImageOffload } from "@deepseek-ai/dsh-llm";
3
3
  import { CredentialRef } from "@deepseek-ai/dsh-credentials";
4
4
  import { TypertRemoteService, TypertSchema } from "@deepseek-ai/dsh-typert-protocol";
5
5
  import { WebRuntime, WebSearchProvider, WebSearchRequest, WebSearchResult } from "@deepseek-ai/dsh-web";
6
6
  import { Context } from "@deepseek-ai/cordis";
7
7
  import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
8
8
  import { CommandDefinition } from "@deepseek-ai/dsh-commands";
9
+ //#region src/provider-errors.d.ts
10
+ /**
11
+ * Why a pre-stream rejection rotates to another account. `rate-limit` (a usage
12
+ * window the provider NAMED), `throttled` (a 429 that named no window) and
13
+ * `invalid-credential` are the three the pool records as marks; `unavailable`
14
+ * is an account-scoped rejection that must NOT become a mark — the account's
15
+ * key is valid and its windows may be open, the ACCOUNT just cannot serve THIS
16
+ * request — so the pool moves on without remembering anything.
17
+ *
18
+ * The window/throttle split decides what the pool may CLAIM, never whether it
19
+ * rotates (issue #54); the evidence that separates them is in
20
+ * {@link classifyAccountRejection}.
21
+ */
22
+ type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable';
23
+ //#endregion
9
24
  //#region src/request-timing.d.ts
10
25
  type Phase = 'credentials' | 'images' | 'body' | 'serialization' | 'headers';
11
26
  type Outcome = 'finished' | 'error' | 'aborted' | 'cancelled';
@@ -28,8 +43,25 @@ interface RequestTimingSummary {
28
43
  }
29
44
  type RequestTimingSink = (summary: RequestTimingSummary) => void | Promise<void>;
30
45
  //#endregion
46
+ //#region src/stream-response.d.ts
47
+ /**
48
+ * Endpoint protocol selected for one generate call.
49
+ *
50
+ * `messages` is the Anthropic Messages surface at
51
+ * `{apiBase}/provider/v1/messages`, the only Provider API route the Claude
52
+ * family answers (posted to `/chat/completions` they refuse with `400 Model
53
+ * "<id>" must be called via /provider/v1/messages`). `openai` is the
54
+ * documented Chat Completions surface; `cli` is Command Code's private
55
+ * `/alpha/generate` transport, kept for Go-plan keys (the one plan without
56
+ * Provider API access) and as the `upgrade_required` fallback.
57
+ */
58
+ type CommandCodeProtocol = 'cli' | 'openai' | 'messages';
59
+ //#endregion
60
+ //#region src/gateway-facts.d.ts
61
+ declare const DEFAULT_MAX_OUTPUT_TOKENS = 131072;
62
+ //#endregion
31
63
  //#region src/adapter.d.ts
32
- declare const COMMAND_CODE_CLI_VERSION = "1.72.1";
64
+ declare const COMMAND_CODE_CLI_VERSION = "1.74.1";
33
65
  declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
34
66
  /**
35
67
  * The output budget this bundle asks for, and the ceiling it will never exceed.
@@ -38,8 +70,9 @@ declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
38
70
  * Probing `/alpha/generate` directly on 2026-09-28: 64 000 → 200, 131 072 → 200,
39
71
  * 196 608 → 200, **200 000 → 200, 200 704 → 400**, 1 000 000 → 400. The server
40
72
  * therefore caps `max_tokens` at 200 000, and it does so identically for a
41
- * 262 144-window model (`stealth/pixel-canary`) and a 1 000 000-window one
42
- * (`stealth/space-bunny-alpha`) — the cap is global, not per model. 131 072
73
+ * 262 144-window model (`stealth/pixel-canary`, retired by Command Code on
74
+ * 2026-10-01 and named here only as the probe's subject) and a 1 000 000-window
75
+ * one (`stealth/space-bunny-alpha`) — the cap is global, not per model. 131 072
43
76
  * keeps a 35 % margin under it while covering the real output ceiling of the
44
77
  * models that have one (Claude 64 K, Gemini 64 K, several at 128 K).
45
78
  *
@@ -47,35 +80,20 @@ declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
47
80
  * (a 64 000 request answered headers in 1.28 s against 1.57 s for 131 072) but
48
81
  * it did cap what a model could ever say in one turn.
49
82
  *
50
- * This is only an UPPER bound. `requestContextBudget` lowers it per request
51
- * from the prompt actually being sent, so raising the ceiling cannot push a
52
- * large session over its window.
83
+ * No client-side clamp is applied on top of this: an earlier version pre-shrank
84
+ * `max_tokens` from an estimate of the prompt already sent (`requestContextBudget()`,
85
+ * issue #67), but that estimate over-corrected on ordinary long conversations —
86
+ * exactly the "output gets cut short as the conversation grows" symptom issue #74
87
+ * reported — while a live A/B probe (2026-09-30, `stealth/space-bunny-alpha`,
88
+ * ~19.6% over its 1,000,000-token window with no client-side shrink) showed the
89
+ * endpoint answers a genuine overflow with an unambiguous `400 … exceeds the
90
+ * model's context window`, which `isContextOverflowDetail()` below already
91
+ * classifies as `CONTEXT_WINDOW_EXCEEDED` independently of this constant. See
92
+ * [决策记录](../docs/决策记录.md).
53
93
  */
54
94
  declare const DEFAULT_GENERATE_MAX_TOKENS = 131072;
55
- /**
56
- * The fallback when the catalog carries no output ceiling for a model.
57
- *
58
- * `/provider/v1/models` publishes only `context_length` — no output limit — so
59
- * the catalog cannot learn one per model and derives a stand-in from the
60
- * window instead. Kept equal to {@link DEFAULT_GENERATE_MAX_TOKENS} on purpose:
61
- * a lower value here would silently re-cap every request through
62
- * `Math.min(contextLength, this)` before the ceiling above is ever consulted.
63
- */
64
- declare const DEFAULT_MAX_OUTPUT_TOKENS = 131072;
65
95
  /** How long the picker's plan-filter billing facts stay cached before refetching. */
66
96
  declare const BILLING_ACCESS_TTL_MS: number;
67
- /**
68
- * Endpoint protocol selected for one generate call.
69
- *
70
- * `messages` is the Anthropic Messages surface at
71
- * `{apiBase}/provider/v1/messages`, the only Provider API route the Claude
72
- * family answers (posted to `/chat/completions` they refuse with `400 Model
73
- * "<id>" must be called via /provider/v1/messages`). `openai` is the
74
- * documented Chat Completions surface; `cli` is Command Code's private
75
- * `/alpha/generate` transport, kept for Go-plan keys (the one plan without
76
- * Provider API access) and as the `upgrade_required` fallback.
77
- */
78
- type CommandCodeProtocol = 'cli' | 'openai' | 'messages';
79
97
  /**
80
98
  * Head-of-request timeout: how long to wait for the first response byte.
81
99
  *
@@ -191,19 +209,6 @@ interface CommandCodeConnectionOptions {
191
209
  * text-only request never depends on the attachment seam.
192
210
  */
193
211
  type ResolveAttachments = () => AttachmentStore | undefined;
194
- /**
195
- * Why a pre-stream rejection rotates to another account. `rate-limit` (a usage
196
- * window the provider NAMED), `throttled` (a 429 that named no window) and
197
- * `invalid-credential` are the three the pool records as marks; `unavailable`
198
- * is an account-scoped rejection that must NOT become a mark — the account's
199
- * key is valid and its windows may be open, the ACCOUNT just cannot serve THIS
200
- * request — so the pool moves on without remembering anything.
201
- *
202
- * The window/throttle split decides what the pool may CLAIM, never whether it
203
- * rotates (issue #54); the evidence that separates them is in
204
- * {@link classifyAccountRejection}.
205
- */
206
- type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable';
207
212
  /** What the rotation hook knows about the request it is rotating within. */
208
213
  interface AccountRotationContext {
209
214
  /** Every API key this request has already used, just-rejected key included. */
@@ -250,7 +255,7 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
250
255
  * a host without a pool omits this seam and the filter falls back to the key
251
256
  * that would serve the current request.
252
257
  */
253
- resolveAccountKeys?: () => Promise<readonly string[]>;
258
+ resolveAccountKeys?: (connection: C) => Promise<readonly string[]>;
254
259
  /** HTTP transport override (tests); defaults to the global `fetch`. */
255
260
  fetchImpl?: typeof fetch;
256
261
  /** Resolve the optional durable attachment service for image input (tests); defaults to none. */
@@ -359,8 +364,7 @@ interface CommandCodeUsageReport {
359
364
  }
360
365
  declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {
361
366
  private readonly deps;
362
- private catalog;
363
- private catalogState;
367
+ private readonly gatewayFacts;
364
368
  private readonly fetchImpl;
365
369
  private readonly resolveAttachments;
366
370
  /**
@@ -439,10 +443,6 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
439
443
  * requirement — the meter throws when the counts differ.
440
444
  */
441
445
  imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined;
442
- /** 地址或缓存文件变化时丢弃旧目录,防止旧网关的路由声明影响新请求。 */
443
- private currentCatalogState;
444
- /** 共享一次刷新;调用者取消只结束自己的等待,不取消其他调用者的请求。 */
445
- private loadCatalog;
446
446
  listModels(provider: string, opts?: {
447
447
  unfiltered?: boolean;
448
448
  }): Promise<readonly LlmModelInfo[]>;
@@ -450,9 +450,8 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
450
450
  * The per-model allowance bracket this account POOL falls into, or undefined
451
451
  * when there is nothing honest to show.
452
452
  *
453
- * The pricing page publishes a per-model monthly allowance for GOAT and Pro
454
- * only — its own words are "the boost is a per-model allowance, so it lives on
455
- * the plans that have them" — so a pool whose highest plan is Go, Provider,
453
+ * The pricing page publishes per-model monthly allowances for Go, GOAT and
454
+ * Pro. A pool whose highest plan is Provider,
456
455
  * Max or Ultra gets undefined rather than a neighbouring tier's figure. Taking
457
456
  * the HIGHEST tier matches the question the picker already answers for a pool
458
457
  * (see `modelVisibleForAnyAccount`): what the user can reach, not what the one
@@ -460,7 +459,7 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
460
459
  * too — an unreachable billing endpoint yields undefined, which hides the
461
460
  * allowance instead of inventing one.
462
461
  */
463
- allowanceTier(): Promise<'goat' | 'pro' | undefined>;
462
+ allowanceTier(): Promise<'go' | 'goat' | 'pro' | undefined>;
464
463
  resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
465
464
  /** The headers every authenticated account endpoint shares. */
466
465
  private accountHeaders;
@@ -562,7 +561,7 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
562
561
  * 60 s), not the catalog's 10 s probe budget, because on a slow link a 10 s
563
562
  * cap made every account query time out while chat kept working.
564
563
  */
565
- getUsage(apiKey?: string): Promise<CommandCodeUsageReport>;
564
+ getUsage(apiKey?: string, capturedConnection?: C): Promise<CommandCodeUsageReport>;
566
565
  /**
567
566
  * Probe one account's real usage windows from `/alpha/billing/credits`. The
568
567
  * multi-account pool calls this when every account is marked exhausted: an
@@ -585,11 +584,12 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
585
584
  * state. The credit balances are deliberately NOT part of this answer: they
586
585
  * carry no reset time, and the server remains the final gate on them.
587
586
  */
588
- probeWindowLimits(apiKey: string): Promise<{
587
+ probeWindowLimits(apiKey: string, connection?: C): Promise<{
589
588
  exceeded: boolean;
590
589
  resetAt: number;
591
590
  } | undefined>;
592
591
  stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
592
+ private streamWithTiming;
593
593
  /**
594
594
  * One turn, with at most one output-ceiling downshift.
595
595
  *
@@ -757,18 +757,26 @@ declare function matchModelRule(model: string, rules: readonly CommandCodeModelA
757
757
  * the normal preferred/rotation selection).
758
758
  */
759
759
  declare function selectAccountForModel(accounts: readonly ResolvedAccount[], model: string, rules: readonly CommandCodeModelAccountRule[] | undefined): ResolvedAccount | undefined;
760
- /**
761
- * The account pool. Rotation state is keyed by API key (never logged), so two
762
- * slots resolving to the same credential share one mark, and a key changed in
763
- * the credentials service starts with a clean slate.
764
- */
760
+ /** 不包含解析秘密的账号定义;作用域独立复制列表及模型规则。 */
761
+ interface CommandCodeAccountSelection {
762
+ slots: readonly CommandCodeAccountSlot[];
763
+ preferredId?: string | undefined;
764
+ modelAccountRules: readonly CommandCodeModelAccountRule[];
765
+ }
766
+ /** 账号选择与展示共用恢复规则;宿主作用域内的状态按网关与密钥共享。 */
765
767
  declare class CommandCodeAccountPool {
766
768
  private readonly deps;
767
- /** Rotation state by API key. */
768
- private readonly states;
769
- /** Last explicit-revival probe attempt by API key (throttles a failing probe). */
770
- private readonly explicitProbes;
769
+ /** 当前作用域内按密钥共享的健康状态;不记录到日志。 */
770
+ private states;
771
+ /** 当前网关与密钥的显式探测时间,限制失败探测的频率。 */
772
+ private explicitProbes;
773
+ private scopedStates;
771
774
  constructor(deps: CommandCodeAccountPoolDeps);
775
+ /** 每个调用持有自己的定义和探测,只有同网关的健康事实共享;不临时改写全局依赖。 */
776
+ scope(context: CommandCodeAccountSelection & {
777
+ apiBase: string;
778
+ probeWindow: CommandCodeAccountPoolDeps['probeWindow'];
779
+ }): CommandCodeAccountPool;
772
780
  /**
773
781
  * Resolve every slot's key, deduplicated by key (first slot wins). Slots
774
782
  * without any resolvable key are omitted — they still appear in the
@@ -794,7 +802,7 @@ declare class CommandCodeAccountPool {
794
802
  * from the resolution entirely, which is what lets one request walk a
795
803
  * four-account pool. An explicit selection (pin or model rule) that a
796
804
  * rate-limit mark would demote is probed first, so a fallback never becomes
797
- * permanent (issue #51). Rules re-read per resolution, so settings apply live.
805
+ * permanent (issue #51). Scoped rules stay fixed for the call; credential values re-resolve.
798
806
  */
799
807
  resolveKey(options?: {
800
808
  tried?: readonly string[];
@@ -803,6 +811,26 @@ declare class CommandCodeAccountPool {
803
811
  key: string;
804
812
  slot: CommandCodeAccountSlot;
805
813
  } | undefined>;
814
+ /**
815
+ * Which account is serving right now, for display (the settings page's
816
+ * account card, the sidebar usage stats) — without consuming a request's
817
+ * `tried` budget and without throwing when nothing can serve.
818
+ *
819
+ * Reads and self-heals exactly like {@link resolveKey} would: an `unknown`
820
+ * mark on the pinned account is re-probed (throttled the same way, sharing
821
+ * the same per-key timestamp), and a pool where nothing currently resolves
822
+ * gets one batch probe pass too. Without this, the badge read a possibly
823
+ * stale mark forever — nothing but an actual generate request ever cleared
824
+ * an `unknown` mark, so a page left open with no chat activity kept
825
+ * showing "switched to the fallback account" long after a real request
826
+ * would have quietly recovered (issue #51's follow-up report: the account
827
+ * card and the sidebar stats both stuck on the wrong account).
828
+ *
829
+ * No `model` parameter: the badge describes the pool as a whole, not one
830
+ * request, so model-routing rules are deliberately not consulted here —
831
+ * matching what the direct `selectActiveAccount` call this replaces did.
832
+ */
833
+ activeAccount(): Promise<ResolvedAccount | undefined>;
806
834
  /**
807
835
  * Record a rejection against one key. A `throttled` rejection (the plain 429
808
836
  * that named no window) marks the key with the `throttle` cause, leaving
@@ -868,10 +896,64 @@ declare class CommandCodeAccountPool {
868
896
  * read as "never usable again" to {@link accountUsable}, so `unknown` it is.
869
897
  */
870
898
  private stampWindowMark;
899
+ /**
900
+ * The explicit-account fallback re-check: when `chosen` (what rotation
901
+ * would currently serve) is not the account the user actually asked for,
902
+ * re-probe that explicit account's mark before accepting the fallback —
903
+ * so a rate-limit mark never demotes the user's own selection for good
904
+ * (issue #51). Returns the revived account, or `undefined` when there is
905
+ * nothing to revive (explicit account already serving, not due for a
906
+ * probe, or the probe found it still exceeded). Shared by {@link resolveKey}
907
+ * (the request path) and {@link activeAccount} (the display path), so both
908
+ * agree on what "currently usable" means instead of drifting apart.
909
+ */
910
+ private reviveExplicit;
911
+ /**
912
+ * Probe every marked account's real usage window when nothing currently
913
+ * resolves. Disabled (401) keys are not probed — an invalid key stays
914
+ * invalid. A throwing probe counts as "unknown" (like a failed one): it
915
+ * must not turn the all-exhausted path into a raw rejection instead of
916
+ * RATE_LIMIT. Shared by {@link resolveKey} and {@link activeAccount}.
917
+ */
918
+ private probeAllMarked;
871
919
  /** Hand out the chosen account's key. */
872
920
  private pick;
873
921
  }
874
922
  //#endregion
923
+ //#region src/enrollment-wire.d.ts
924
+ interface EnrollmentInput {
925
+ id: string;
926
+ pageId: string;
927
+ mode: 'browser' | 'manual';
928
+ label: string;
929
+ /** 用户未填写名称时,允许使用浏览器登录返回的账号名。 */
930
+ automaticName: boolean;
931
+ key?: string;
932
+ }
933
+ type EnrollmentPhase = 'creating' | 'waiting' | 'writing' | 'naming' | 'finished' | 'cancelling' | 'cancelled' | 'failed' | 'cleanup-needed';
934
+ interface EnrollmentState {
935
+ id: string;
936
+ ref: string;
937
+ phase: EnrollmentPhase;
938
+ message: string;
939
+ authUrl?: string;
940
+ suggestedName?: string;
941
+ }
942
+ /** 配置中的恢复日志:先登记,再写凭据;只保留引用与阶段,不保留密钥或连接身份。 */
943
+ interface EnrollmentRecord {
944
+ id: string;
945
+ ref: string;
946
+ phase: 'pending' | 'naming' | 'cleanup';
947
+ label: string;
948
+ }
949
+ interface EnrollmentPage {
950
+ pageId: string;
951
+ }
952
+ interface EnrollmentAction extends EnrollmentPage {
953
+ id: string;
954
+ name?: string;
955
+ }
956
+ //#endregion
875
957
  //#region src/plan-tiers.d.ts
876
958
  declare const PLAN_LABELS: Readonly<Record<string, string>>;
877
959
  declare const PLAN_ORDER: Readonly<Record<string, number>>;
@@ -896,14 +978,14 @@ declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
896
978
  declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
897
979
  /**
898
980
  * Models WITHOUT a zero-data-retention upstream, per the official CLI's own
899
- * registry (`command-code@1.72.1` `dist/cli.mjs`): `modelSupportsZdr(id)` is
981
+ * registry (`command-code@1.74.1` `dist/cli.mjs`): `modelSupportsZdr(id)` is
900
982
  * exactly `!nonZdrSet.has(canonicalize(id))`, and `knownModelSupportsZdr`
901
983
  * carries the same membership in the sibling route table — the UNION of both
902
- * is this set. Reading only the sibling route table would drop `meituan/
903
- * LongCat-2.0`, which appears in `modelSupportsZdr` alone (re-read from the
904
- * 1.66.0 / 1.67.0 / 1.68.0 artifacts on 2026-09-29: the two stealth-preview
905
- * rows sit in BOTH sets, so LongCat is the only divergence). The official docs (commandcode.ai/docs/resources/
906
- * zdr) put it in prose — "99% of our models have ZDR-capable upstreams … only
984
+ * is this set. Reading only the sibling route table dropped
985
+ * `meituan/LongCat-2.0`, which sat in `modelSupportsZdr` alone through
986
+ * 1.73.0; the 1.74.1 table lists it in NEITHER set, so as of this snapshot it
987
+ * is no longer excluded. The official docs (commandcode.ai/docs/resources/
988
+ * zdr) put coverage in prose — "99% of our models have ZDR-capable upstreams … only
907
989
  * a small handful of models are affected" — so the CLI's exclusion list is
908
990
  * the only per-model evidence there is; a ZDR request naming one of these
909
991
  * fails with HTTP 422 `cmd_zdr_no_providers` instead of routing through a
@@ -926,8 +1008,14 @@ declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
926
1008
  * is the snapshot of the exclusion set and nothing more. It is a rare change:
927
1009
  * 20 members held across 1.62.0 → 1.64.0, 1.65.0 and 1.66.0 each added exactly
928
1010
  * one (the two stealth-preview models below), 1.67.0 added one
929
- * (`deepseek/deepseek-v4.1-flash-fast`), and 1.68.0 changed nothing — 23
930
- * members as of 2026-09-29.
1011
+ * (`deepseek/deepseek-v4.1-flash-fast`), 1.68.0 changed nothing, and 1.74.1
1012
+ * removed one (`meituan/LongCat-2.0`) — 22 members as of 2026-10-03.
1013
+ *
1014
+ * `stealth/pixel-canary` is the one member whose model itself is retired (see
1015
+ * `KNOWN_EFFORTS`): the CLI keeps naming it in the ZDR anchors even though it
1016
+ * hides the row and dropped it from the catalog, so it stays listed here rather
1017
+ * than being pruned with the rest of the tables — `supportsZeroDataRetention`
1018
+ * stays truthful for any id a stale session still names.
931
1019
  */
932
1020
  declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
933
1021
  /**
@@ -957,7 +1045,7 @@ declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
957
1045
  * `/docs/plans/max` and `/docs/resources/pricing-limits`). Each plan's model
958
1046
  * list is a superset of the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.
959
1047
  * Models absent from every plan list (Claude Opus/Fable, Fugu Ultra) are
960
- * Provider-tier. Re-verified at command-code@1.72.1 (2026-09-30): 86 catalog
1048
+ * Provider-tier. Re-verified at command-code@1.73.0 (2026-10-01): 86 catalog
961
1049
  * ids at 53/62/76/84 cumulative, a strict superset chain — every release since
962
1050
  * 1.49.0 has been additive with no tier move, and per-entry tags below name the
963
1051
  * release that added each row.
@@ -986,7 +1074,7 @@ declare function compareByPlan(a: {
986
1074
  /**
987
1075
  * Subscription plan table, synced from the official CLI bundle's plan maps
988
1076
  * (located by the `"individual-go"` key in `dist/cli.mjs`, re-verified unchanged
989
- * through command-code@1.72.1): subscription `planId` prefix → display name and
1077
+ * through command-code@1.73.0): subscription `planId` prefix → display name and
990
1078
  * the plan's monthly credit total. This is the account's own subscription
991
1079
  * (from `/alpha/billing/subscriptions`) — distinct from {@link KNOWN_PLANS},
992
1080
  * which maps catalog models to their minimum tier.
@@ -1182,11 +1270,11 @@ interface CommandCodeCatalogModel {
1182
1270
  * Per-model MONTHLY allowance in USD: how much of the plan's monthly credit
1183
1271
  * pool this one model may draw, already resolved by the Host against the
1184
1272
  * account pool's highest plan (the pricing page publishes an allowance for
1185
- * GOAT and Pro only). Undefined when that plan has no published allowance
1273
+ * Go, GOAT and Pro). Undefined when that plan has no published allowance
1186
1274
  * (Go, Provider, Max, Ultra) or when billing could not be read — the browser
1187
1275
  * shows nothing rather than guessing a neighbouring tier's figure.
1188
1276
  *
1189
- * Deliberately a plain number and not the `{ goat, pro }` pair: the bracket is
1277
+ * Deliberately a plain number and not the `{ go, goat, pro }` map: the bracket is
1190
1278
  * a Host decision that already depends on facts the browser does not hold, and
1191
1279
  * shipping both figures would invite a second, divergent rule here. Note this
1192
1280
  * is dollars per MONTH, unlike every rate in `CommandCodePriceTable`.
@@ -1347,100 +1435,8 @@ declare function parseLoginStatus(value: unknown): CommandCodeLoginStatus;
1347
1435
  /** The strict result codec shared by all three login endpoints. */
1348
1436
  declare const loginStatusSchema: TypertSchema<CommandCodeLoginStatus>;
1349
1437
  //#endregion
1350
- //#region src/usage-remote.d.ts
1351
- /**
1352
- * The browser-login face the usage service exposes (`commandcode/login*`).
1353
- * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry
1354
- * wired one; absent, `status`/`cancel` degrade to the idle status and `begin`
1355
- * rejects with a plain message, so the page's manual paste path stays the
1356
- * fallback instead of hanging.
1357
- */
1358
- interface LoginFlowFacade {
1359
- /** Start (or rejoin) an attempt; rejects when it cannot start at all. */
1360
- begin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1361
- /** The current attempt's status. */
1362
- status(): CommandCodeLoginStatus;
1363
- /** Cancel a waiting attempt. */
1364
- cancel(): void;
1365
- }
1366
- /** Everything the usage service needs beyond its Cordis context. */
1367
- interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {
1368
- /** The registered adapter (for getUsage). */
1369
- adapter: CommandCodeAdapter<C>;
1370
- /**
1371
- * Multi-account report source (wired by the plugin entry). Absent in
1372
- * programmatic setups, the service falls back to a single default-account
1373
- * entry around `adapter.getUsage()`.
1374
- */
1375
- reports?: () => Promise<CommandCodeAccountsReport>;
1376
- /**
1377
- * Model-catalog source for the settings page's model editors. Absent, the
1378
- * `models` endpoint answers an empty list — the page's editors degrade to
1379
- * the empty state.
1380
- */
1381
- listModels?: () => Promise<CommandCodeCatalog>;
1382
- /**
1383
- * Price-table source for the composer's session-cost figure. Defaults to the
1384
- * vendored snapshot, so the endpoint can never silently serve an empty table
1385
- * — an unpriced cost is the failure this feature is meant to remove. Override
1386
- * only to stub it in a test.
1387
- */
1388
- prices?: () => CommandCodePriceTable;
1389
- /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */
1390
- login?: LoginFlowFacade;
1391
- }
1392
- /**
1393
- * The Remote receiver: a Cordis service the Gateway resolves by key
1394
- * (`commandcodeUsage`) and binds to the wire namespace (`commandcode`). The
1395
- * base class stamps the `typertRemote` binding the Gateway validates on every
1396
- * dispatch; no decorators are needed because the descriptor is registered
1397
- * explicitly (strict path) rather than discovered from source markers.
1398
- */
1399
- declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends TypertRemoteService {
1400
- private readonly deps;
1401
- constructor(ctx: Context, deps: CommandCodeUsageDeps<C>);
1402
- /**
1403
- * Account, usage, and credit state for the settings page's account card.
1404
- * Degrades per endpoint like the `/commandcode` command (failures land in
1405
- * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which
1406
- * the Gateway folds into the failure branch the page renders as a hint.
1407
- */
1408
- report(): Promise<CommandCodeAccountsReport>;
1409
- /**
1410
- * The full model catalog for the settings page's model editors. The browser
1411
- * never calls the Command Code API directly — the Host serves the catalog
1412
- * (already fetched/cached by the adapter) so models can be picked from the
1413
- * live list instead of typed by hand.
1414
- */
1415
- models(): Promise<CommandCodeCatalog>;
1416
- /**
1417
- * The model price table the composer prices an in-progress session with.
1418
- * Static vendored data, served Host-side so the browser bundle never carries
1419
- * a copy that could drift from the snapshot, and so a price update reaches an
1420
- * open page without a rebuild.
1421
- */
1422
- prices(): Promise<CommandCodePriceTable>;
1423
- /**
1424
- * Start (or rejoin) a browser-login attempt and return its fresh status —
1425
- * `waiting` carrying the Studio URL. Rejects when the flow cannot start
1426
- * (no free loopback port, disposed plugin).
1427
- */
1428
- loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1429
- /** Poll a login attempt's status. */
1430
- loginStatus(): Promise<CommandCodeLoginStatus>;
1431
- /** Cancel a waiting attempt; returns the post-cancel status. */
1432
- loginCancel(): Promise<CommandCodeLoginStatus>;
1433
- private requireLogin;
1434
- }
1435
- /**
1436
- * Provide the usage service and register its Remote descriptor. The registry
1437
- * contribution is tied to this fiber's lifetime: the registry's own
1438
- * `register()` effect would otherwise outlive the plugin.
1439
- */
1440
- declare function applyUsageRemote<C extends CommandCodeConnectionOptions>(ctx: Context, deps: CommandCodeUsageDeps<C>): void;
1441
- //#endregion
1442
1438
  //#region src/login.d.ts
1443
- /** Give up on the browser after this long without a callback (mirrors the CLI). */
1439
+ /** 登录总期限包含浏览器回调、密钥验证与存储,不能在收到回调后撤掉保护。 */
1444
1440
  declare const LOGIN_TIMEOUT_MS = 120000;
1445
1441
  /** First local port the flow tries (mirrors the CLI). */
1446
1442
  declare const LOGIN_START_PORT = 5959;
@@ -1503,7 +1499,7 @@ declare function studioBaseForApiBase(apiBase: string): string;
1503
1499
  * tests). Mirrors the CLI's verdicts: 401 → invalid_key, other non-OK →
1504
1500
  * server_error, transport failure → network_error.
1505
1501
  */
1506
- declare function validateCommandApiKey(fetchImpl: typeof fetch, apiBase: string, apiKey: string): Promise<ApiKeyValidation>;
1502
+ declare function validateCommandApiKey(fetchImpl: typeof fetch, apiBase: string, apiKey: string, signal?: AbortSignal): Promise<ApiKeyValidation>;
1507
1503
  /**
1508
1504
  * One browser-login attempt machine. Single-flight by design: `begin()` while
1509
1505
  * waiting returns the live attempt's status instead of starting a second one;
@@ -1518,6 +1514,7 @@ declare class CommandCodeLoginFlow {
1518
1514
  private statusValue;
1519
1515
  private server;
1520
1516
  private timer;
1517
+ private attemptAbort;
1521
1518
  /** Settle hooks of the live attempt's callback promise. */
1522
1519
  private settle;
1523
1520
  /**
@@ -1540,6 +1537,8 @@ declare class CommandCodeLoginFlow {
1540
1537
  private targetRef;
1541
1538
  /** A `cancel()` that arrived while a start was still binding (see {@link CommandCodeLoginFlow.cancel}). */
1542
1539
  private cancelPending;
1540
+ /** 取消只能阻止尚未发出的写入;补偿者须等这些实际存储任务结束。 */
1541
+ private readonly pendingStores;
1543
1542
  private disposed;
1544
1543
  constructor(deps: CommandCodeLoginFlowDeps);
1545
1544
  /** Subscribe to state transitions. @returns the disposer. */
@@ -1565,6 +1564,8 @@ declare class CommandCodeLoginFlow {
1565
1564
  * the flag once the bind settles and retires it.
1566
1565
  */
1567
1566
  cancel(): void;
1567
+ /** 结束验证/监听并等待已开始的写入,供账号开通过程安全补偿。 */
1568
+ cancelAndDrain(): Promise<void>;
1568
1569
  /** Stop everything; a waiting attempt ends cancelled. Idempotent. */
1569
1570
  dispose(): void;
1570
1571
  private readApiBase;
@@ -1587,9 +1588,10 @@ declare class CommandCodeLoginFlow {
1587
1588
  * Every step re-checks {@link ownsAttempt} first: the whoami round-trip and
1588
1589
  * the credential write are awaits, and the user may cancel (or start another
1589
1590
  * attempt) while one is in flight. A completion that no longer owns the
1590
- * attempt must not write the key or publish a status — otherwise cancel
1591
- * would report "cancelled" while the credential landed anyway, and the page
1592
- * would silently flip to success.
1591
+ * attempt must not START a key write or publish a status. A write already
1592
+ * handed to storage is tracked separately: cancelAndDrain() lets the owning
1593
+ * enrollment wait for it before compensation, without pretending it can be
1594
+ * aborted halfway through.
1593
1595
  */
1594
1596
  private complete;
1595
1597
  /** Whether one attempt still owns the status face (not cancelled, replaced, or disposed). */
@@ -1597,10 +1599,195 @@ declare class CommandCodeLoginFlow {
1597
1599
  /** Map a tagged settle rejection onto the status face. */
1598
1600
  private failFrom;
1599
1601
  private clearTimer;
1600
- /** Close the server and watchdog without touching the published status. */
1602
+ /** 消费一次回调后关闭监听;保留总期限以约束后续验证。 */
1603
+ private closeCallback;
1604
+ /** 结束整个尝试,同时中止验证请求,迟到结果由所有权检查拦截。 */
1601
1605
  private teardown;
1602
1606
  }
1603
1607
  //#endregion
1608
+ //#region src/enrollment.d.ts
1609
+ interface Account {
1610
+ label?: string;
1611
+ apiKeyEnv?: string;
1612
+ apiKey?: string;
1613
+ }
1614
+ interface EnrollmentConfig {
1615
+ apiKeyEnv?: string;
1616
+ accounts?: Account[];
1617
+ accountEnrollmentTasks?: EnrollmentRecord[];
1618
+ credentialCleanupRefs?: string[];
1619
+ modelAccountRules?: {
1620
+ models: string[];
1621
+ account: string;
1622
+ }[];
1623
+ activeAccount?: string;
1624
+ }
1625
+ interface EnrollmentSettings {
1626
+ writable: boolean;
1627
+ read(): {
1628
+ value: EnrollmentConfig;
1629
+ revision: number;
1630
+ base?: EnrollmentConfig;
1631
+ };
1632
+ mutate(ops: {
1633
+ op: 'set';
1634
+ path: string[];
1635
+ value: unknown;
1636
+ }[], revision: number): Promise<void>;
1637
+ }
1638
+ interface EnrollmentLogin {
1639
+ begin(ref?: string): Promise<CommandCodeLoginStatus>;
1640
+ status(): CommandCodeLoginStatus;
1641
+ onChange(listener: () => void): () => void;
1642
+ cancelAndDrain(): Promise<void>;
1643
+ dispose(): void;
1644
+ }
1645
+ interface EnrollmentDeps {
1646
+ settings(): EnrollmentSettings | undefined;
1647
+ describe(ref: string): Promise<{
1648
+ configured: boolean;
1649
+ writable: boolean;
1650
+ }>;
1651
+ set(ref: string, key: string): Promise<void>;
1652
+ unset(ref: string): Promise<void>;
1653
+ login(store: (credentials: CommandCodeLoginCredentials) => Promise<void>): EnrollmentLogin;
1654
+ }
1655
+ declare class AccountEnrollmentManager {
1656
+ private readonly deps;
1657
+ private readonly tasks;
1658
+ private writes;
1659
+ private closed;
1660
+ private readonly pages;
1661
+ constructor(deps: EnrollmentDeps);
1662
+ /** 每页独立的持续调用才代表页面生命期;宿主的 operator Peer 由所有浏览器共享。 */
1663
+ watch(owner: string): () => void;
1664
+ hasPage(owner: string): boolean;
1665
+ /** begin 不等待整个过程;客户端预先生成的 id 让早到的取消也能生效。 */
1666
+ begin(owner: string, input: EnrollmentInput): EnrollmentState;
1667
+ status(owner: string, id: string): EnrollmentState;
1668
+ pending(owner: string): EnrollmentState[];
1669
+ /** 离开已登录的待命名过程等同接受已有名称,其余阶段等待写入结束再补偿。 */
1670
+ cancel(owner: string, id: string): Promise<EnrollmentState>;
1671
+ disconnect(owner: string): void;
1672
+ dispose(): void;
1673
+ name(owner: string, id: string, name?: string): Promise<EnrollmentState>;
1674
+ retry(owner: string, id: string, name?: string): Promise<EnrollmentState>;
1675
+ private run;
1676
+ private store;
1677
+ private cleanup;
1678
+ private settings;
1679
+ private records;
1680
+ private change;
1681
+ private owned;
1682
+ private publish;
1683
+ /** 只淘汰已完成且没有恢复日志的旧状态,活跃过程和未收尾事实始终保留。 */
1684
+ private prune;
1685
+ private recovered;
1686
+ }
1687
+ //#endregion
1688
+ //#region src/usage-remote.d.ts
1689
+ /**
1690
+ * The browser-login face the usage service exposes (`commandcode/login*`).
1691
+ * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry
1692
+ * wired one; absent, `status`/`cancel` degrade to the idle status and `begin`
1693
+ * rejects with a plain message, so the page's manual paste path stays the
1694
+ * fallback instead of hanging.
1695
+ */
1696
+ interface LoginFlowFacade {
1697
+ /** Start (or rejoin) an attempt; rejects when it cannot start at all. */
1698
+ begin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1699
+ /** The current attempt's status. */
1700
+ status(): CommandCodeLoginStatus;
1701
+ /** Cancel a waiting attempt. */
1702
+ cancel(): void;
1703
+ }
1704
+ /** Everything the usage service needs beyond its Cordis context. */
1705
+ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {
1706
+ /** The registered adapter (for getUsage). */
1707
+ adapter: CommandCodeAdapter<C>;
1708
+ /**
1709
+ * Multi-account report source (wired by the plugin entry). Absent in
1710
+ * programmatic setups, the service falls back to a single default-account
1711
+ * entry around `adapter.getUsage()`.
1712
+ */
1713
+ reports?: () => Promise<CommandCodeAccountsReport>;
1714
+ /**
1715
+ * Model-catalog source for the settings page's model editors. Absent, the
1716
+ * `models` endpoint answers an empty list — the page's editors degrade to
1717
+ * the empty state.
1718
+ */
1719
+ listModels?: () => Promise<CommandCodeCatalog>;
1720
+ /**
1721
+ * Price-table source for the composer's session-cost figure. Defaults to the
1722
+ * vendored snapshot, so the endpoint can never silently serve an empty table
1723
+ * — an unpriced cost is the failure this feature is meant to remove. Override
1724
+ * only to stub it in a test.
1725
+ */
1726
+ prices?: () => CommandCodePriceTable;
1727
+ /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */
1728
+ login?: LoginFlowFacade;
1729
+ enrollment?: AccountEnrollmentManager;
1730
+ }
1731
+ /**
1732
+ * The Remote receiver: a Cordis service the Gateway resolves by key
1733
+ * (`commandcodeUsage`) and binds to the wire namespace (`commandcode`). The
1734
+ * base class stamps the `typertRemote` binding the Gateway validates on every
1735
+ * dispatch; no decorators are needed because the descriptor is registered
1736
+ * explicitly (strict path) rather than discovered from source markers.
1737
+ */
1738
+ declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends TypertRemoteService {
1739
+ private readonly deps;
1740
+ constructor(ctx: Context, deps: CommandCodeUsageDeps<C>);
1741
+ /**
1742
+ * Account, usage, and credit state for the settings page's account card.
1743
+ * Degrades per endpoint like the `/commandcode` command (failures land in
1744
+ * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which
1745
+ * the Gateway folds into the failure branch the page renders as a hint.
1746
+ */
1747
+ report(): Promise<CommandCodeAccountsReport>;
1748
+ /**
1749
+ * The full model catalog for the settings page's model editors. The browser
1750
+ * never calls the Command Code API directly — the Host serves the catalog
1751
+ * (already fetched/cached by the adapter) so models can be picked from the
1752
+ * live list instead of typed by hand.
1753
+ */
1754
+ models(): Promise<CommandCodeCatalog>;
1755
+ /**
1756
+ * The model price table the composer prices an in-progress session with.
1757
+ * Static vendored data, served Host-side so the browser bundle never carries
1758
+ * a copy that could drift from the snapshot, and so a price update reaches an
1759
+ * open page without a rebuild.
1760
+ */
1761
+ prices(): Promise<CommandCodePriceTable>;
1762
+ /**
1763
+ * Start (or rejoin) a browser-login attempt and return its fresh status —
1764
+ * `waiting` carrying the Studio URL. Rejects when the flow cannot start
1765
+ * (no free loopback port, disposed plugin).
1766
+ */
1767
+ loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1768
+ /** Poll a login attempt's status. */
1769
+ loginStatus(): Promise<CommandCodeLoginStatus>;
1770
+ /** Cancel a waiting attempt; returns the post-cancel status. */
1771
+ loginCancel(): Promise<CommandCodeLoginStatus>;
1772
+ enrollmentBegin(input: EnrollmentInput): Promise<EnrollmentState>;
1773
+ enrollmentStatus(input: EnrollmentAction): Promise<EnrollmentState>;
1774
+ enrollmentCancel(input: EnrollmentAction): Promise<EnrollmentState>;
1775
+ enrollmentName(input: EnrollmentAction): Promise<EnrollmentState>;
1776
+ enrollmentRetry(input: EnrollmentAction): Promise<EnrollmentState>;
1777
+ enrollmentPending(input: EnrollmentPage): Promise<EnrollmentState[]>;
1778
+ enrollmentWatch(input: EnrollmentPage): AsyncIterable<boolean>;
1779
+ private enrollmentOwner;
1780
+ private enrollmentPeer;
1781
+ private requireEnrollment;
1782
+ private requireLogin;
1783
+ }
1784
+ /**
1785
+ * Provide the usage service and register its Remote descriptor. The registry
1786
+ * contribution is tied to this fiber's lifetime: the registry's own
1787
+ * `register()` effect would otherwise outlive the plugin.
1788
+ */
1789
+ declare function applyUsageRemote<C extends CommandCodeConnectionOptions>(ctx: Context, deps: CommandCodeUsageDeps<C>): void;
1790
+ //#endregion
1604
1791
  //#region src/web-search.d.ts
1605
1792
  /** Stable id this provider registers under in `ctx.web`. */
1606
1793
  declare const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
@@ -1655,8 +1842,8 @@ declare function commandCodeSearchSelection(): CommandCodeSearchSelection;
1655
1842
  declare function applyCommandCodeSearchSelection(web: WebRuntime, state: CommandCodeSearchSelection, enable: boolean): void;
1656
1843
  /** Per-request facts the provider needs, all injected so the class stays cordis-free and testable. */
1657
1844
  interface CommandCodeSearchProviderDeps {
1658
- /** Resolve one usable Command Code key (credential seam → env → auth file), or undefined when none. */
1659
- resolveKey(): Promise<string | undefined>;
1845
+ /** 使用搜索已捕获的网关解析账号,探测不能在等待后转到另一个网关。 */
1846
+ resolveKey(apiBase?: string): Promise<string | undefined>;
1660
1847
  /** The API base host (defaults to `https://api.commandcode.ai`). */
1661
1848
  apiBase(): string;
1662
1849
  /** Injectable fetch for tests; defaults to the global fetch. */
@@ -1908,6 +2095,8 @@ interface Config {
1908
2095
  * the key and the next account's key is retried transparently.
1909
2096
  */
1910
2097
  accounts?: CommandCodeAccountConfig[];
2098
+ /** 账号开通恢复日志,只保留引用与阶段。 */
2099
+ accountEnrollmentTasks?: EnrollmentRecord[];
1911
2100
  /**
1912
2101
  * Manually selected active account: a slot id — `default`, or an extra
1913
2102
  * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). It serves
@@ -1978,6 +2167,8 @@ declare const Config: z<Config>;
1978
2167
  /** One resolution's complete request facts: connection plus credential reference. */
1979
2168
  interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {
1980
2169
  apiKeyEnv: CredentialRef;
2170
+ /** 本次调用的账号定义,与连接从同一次易变配置读取。 */
2171
+ accountSelection?: CommandCodeAccountSelection;
1981
2172
  }
1982
2173
  /**
1983
2174
  * The one explicit resolve step from raw config to validated connection