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

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
@@ -7,7 +7,7 @@ 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
9
  //#region src/adapter.d.ts
10
- declare const COMMAND_CODE_CLI_VERSION = "1.65.0";
10
+ declare const COMMAND_CODE_CLI_VERSION = "1.66.0";
11
11
  declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
12
12
  declare const DEFAULT_GENERATE_MAX_TOKENS = 64000;
13
13
  declare const DEFAULT_MAX_OUTPUT_TOKENS = 65536;
@@ -93,8 +93,6 @@ interface CommandCodeConnectionOptions {
93
93
  * `CMD_ZDR=1`). Default false. Every chat request carries the header when
94
94
  * enabled. The provider refuses a model without a ZDR-capable upstream with
95
95
  * 422 `cmd_zdr_no_providers`; never retry that request without the header.
96
- * The decision endpoint (`/provider/v1/systemone`) is deliberately never
97
- * reached through this connection option — see `./systemone.ts`.
98
96
  */
99
97
  zdr?: boolean;
100
98
  }
@@ -110,12 +108,11 @@ type ResolveAttachments = () => AttachmentStore | undefined;
110
108
  * `invalid-credential` are the three the pool records as marks; `unavailable`
111
109
  * is an account-scoped rejection that must NOT become a mark — the account's
112
110
  * key is valid and its windows may be open, the ACCOUNT just cannot serve THIS
113
- * request (no credits, a model outside its plan) — so the pool moves on
114
- * without remembering anything.
111
+ * request — so the pool moves on without remembering anything.
115
112
  *
116
113
  * The window/throttle split decides what the pool may CLAIM, never whether it
117
- * rotates: both leave rotation and mark the key, but only a named window lets
118
- * the pool report an exhausted usage window (issue #54).
114
+ * rotates (issue #54); the evidence that separates them is in
115
+ * {@link classifyAccountRejection}.
119
116
  */
120
117
  type AccountRotationReason = 'rate-limit' | 'throttled' | 'invalid-credential' | 'unavailable';
121
118
  /** What the rotation hook knows about the request it is rotating within. */
@@ -149,11 +146,10 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
149
146
  * with several accounts a rejection that does not mark the key (a plan or
150
147
  * balance rejection is model-specific, not account-fatal) would otherwise
151
148
  * re-offer the same account on every attempt and the pool could never reach
152
- * the accounts behind it.
153
- *
154
- * `rotation.resetAtMs` carries the provider's own reset time when the
155
- * rejection body published one, so the host can hold the key out until then
156
- * instead of waiting for a billing probe to learn the same fact.
149
+ * the accounts behind it. `rotation.resetAtMs` carries the provider's own
150
+ * reset time when the rejection body published one, so the host can hold the
151
+ * key out until then instead of waiting for a billing probe to learn the
152
+ * same fact.
157
153
  */
158
154
  rotateApiKey?: (rejectedKey: string, rejection: AccountRotationReason, connection: C, model?: string, rotation?: AccountRotationContext) => Promise<string | undefined>;
159
155
  /**
@@ -298,13 +294,13 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
298
294
  * unbounded loop): `RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`/
299
295
  * `EMPTY_RESPONSE` retry up to 1000 times with waits doubling from 500 ms
300
296
  * and capping at 15 minutes (±10% jitter), so an exhausted 5-hour window
301
- * recovers in-session instead of failing after two tries. Permanent
302
- * failures (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`,
303
- * plan rejections) are absent from the whitelist and surface immediately
304
- * instead of looping. Waits the pool/adapter attach as
305
- * `providerRetryAfterMs` are honored verbatim at or below the 15-minute
306
- * cap and never attached above it (in normal mode a longer attached wait
307
- * makes the executor abandon the retry outright — see RETRY_MAX_DELAY_MS).
297
+ * recovers in-session instead of failing after two tries. Permanent failures
298
+ * (an invalid key's `INVALID_CREDENTIAL`, `UNSUPPORTED_CONTENT`, plan
299
+ * rejections) are absent from the whitelist and surface immediately instead
300
+ * of looping. Waits the pool/adapter attach as `providerRetryAfterMs` are
301
+ * honored verbatim at or below the 15-minute cap and never attached above it
302
+ * (in normal mode a longer attached wait makes the executor abandon the
303
+ * retry outright — see RETRY_MAX_DELAY_MS).
308
304
  *
309
305
  * Captured once at route registration (dsh-llm snapshots this value), so a
310
306
  * future config knob for it would apply on profile restart, not per request.
@@ -318,12 +314,8 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
318
314
  * session reports far less context than it is actually carrying. The price is
319
315
  * computed at the dimensions this route would send (the same request target
320
316
  * `readImageRequest` encodes to), so the estimate tracks the wire rather than
321
- * the stored original.
322
- *
323
- * Both payload generations are handled, because they disagree: ≤0.1.5 hands
324
- * over bare `ImageAttachmentRef`s, ≥0.1.6 hands over `ImageBlock`s that also
325
- * carry the surface's `offloaded` mark. Returning a price per occurrence, in
326
- * order, is a hard requirement — the meter throws when the counts differ.
317
+ * the stored original. One price per occurrence, in order, is a hard
318
+ * requirement — the meter throws when the counts differ.
327
319
  */
328
320
  imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined;
329
321
  /** Refresh the catalog (live fetch, cache fallback) and return it. */
@@ -336,10 +328,10 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
336
328
  private accountHeaders;
337
329
  /**
338
330
  * Fetch one account endpoint and parse its JSON body. Returns the HTTP
339
- * status alongside the parsed record so each caller applies its own
340
- * failure accounting: the billing probe fails open silently, the usage
341
- * report books failures per endpoint. Non-2xx and invalid JSON bodies come
342
- * back without a record; only a fetch failure propagates to the caller.
331
+ * status alongside the parsed record so each caller applies its own failure
332
+ * accounting: the billing probe fails open silently, the usage report books
333
+ * failures per endpoint. Non-2xx and invalid JSON bodies come back without a
334
+ * record; only a fetch failure propagates to the caller.
343
335
  *
344
336
  * `timeoutMs` is the caller's budget for this one request. The default is the
345
337
  * CATALOG probe's short cap, which fits the picker's fail-open reads; the
@@ -354,9 +346,6 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
354
346
  * per picker load). `undefined` means the filter cannot be evaluated at all
355
347
  * — no key resolved — which {@link modelVisibleForAnyAccount} reads as
356
348
  * "show everything".
357
- *
358
- * The serving account is only the first entry: with several accounts the
359
- * model list must not depend on which of them rotation happens to be using.
360
349
  */
361
350
  private loadPoolBillingAccess;
362
351
  /**
@@ -401,10 +390,9 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
401
390
  * but a hard refusal. `/alpha/generate` routes every one of them, so this
402
391
  * costs nothing.
403
392
  *
404
- * That decision is deliberately NOT written to `protocolCache`. The cache is
405
- * keyed by API key alone, so remembering it would pin the whole ACCOUNT to
406
- * the CLI transport and drag every other model — DeepSeek, GLM, Qwen, all of
407
- * which the Provider API serves correctly — off it until the entry expired.
393
+ * That decision is deliberately NOT written to `protocolCache`, which is
394
+ * keyed by API key alone: remembering it would pin the whole ACCOUNT to the
395
+ * CLI transport and drag every other model off it until the entry expired.
408
396
  */
409
397
  private resolveProtocol;
410
398
  /**
@@ -418,18 +406,14 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
418
406
  * the default resolves the currently active account.
419
407
  *
420
408
  * Two failure modes are NOT "the network is down", and the report must say
421
- * so rather than let {@link classifyTotalFailure} blame the connection:
422
- *
423
- * - A key that no HTTP header can carry (a stray newline from a paste, a
424
- * full-width character) makes `fetch` throw a `TypeError` **before any
425
- * I/O**, for every endpoint at once. The chat path refuses such a key
426
- * through `assertUsableApiKey`; this path must too, and it answers
427
- * `blocked: 'invalid-key'` instead of four phantom transport failures.
428
- * - The four endpoints get the SAME per-request budget as a chat call
429
- * (`connection.requestTimeoutMs`, default 60 s), not the catalog's 10 s
430
- * probe budget: on a slow link a 10 s cap made every account query time
431
- * out while chat kept working, which is exactly a "check your network"
432
- * banner that never clears.
409
+ * so rather than let {@link classifyTotalFailure} blame the connection: a
410
+ * key that no HTTP header can carry (a stray newline from a paste, a
411
+ * full-width character) makes `fetch` throw a `TypeError` before any I/O,
412
+ * for every endpoint at once, so this path runs `assertUsableApiKey` too and
413
+ * answers `blocked: 'invalid-key'`; and the four endpoints get the SAME
414
+ * per-request budget as a chat call (`connection.requestTimeoutMs`, default
415
+ * 60 s), not the catalog's 10 s probe budget, because on a slow link a 10 s
416
+ * cap made every account query time out while chat kept working.
433
417
  */
434
418
  getUsage(apiKey?: string): Promise<CommandCodeUsageReport>;
435
419
  /**
@@ -443,17 +427,16 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
443
427
  * the same time (the two are metered separately), and reading only the
444
428
  * shorter one revived such an account as "usable" — the pool then handed it
445
429
  * out, the provider rejected the request again, and the next all-marked pass
446
- * revived it once more, so a used-up account kept coming back (issue #51's
447
- * follow-up: "切到一个不可用账号"). `exceeded` is therefore true when ANY
448
- * published window is exceeded, and `resetAt` is the LATEST reset among the
449
- * exceeded ones — the binding constraint, because a clear five-hour window
450
- * buys nothing while the weekly quota is spent.
430
+ * revived it once more (issue #51's follow-up: "切到一个不可用账号").
431
+ * `exceeded` is therefore true when ANY published window is exceeded, and
432
+ * `resetAt` is the LATEST reset among the exceeded ones — the binding
433
+ * constraint, because a clear five-hour window buys nothing while the weekly
434
+ * quota is spent.
451
435
  *
452
436
  * Returns `undefined` when the probe itself failed (transport, non-200, or a
453
437
  * payload with no window limits at all) — a failed probe never changes pool
454
- * state. The monthly/purchased/free credit balances are deliberately NOT part
455
- * of this answer: they are balances rather than windows, they carry no reset
456
- * time, and the server remains the final gate on them.
438
+ * state. The credit balances are deliberately NOT part of this answer: they
439
+ * carry no reset time, and the server remains the final gate on them.
457
440
  */
458
441
  probeWindowLimits(apiKey: string): Promise<{
459
442
  exceeded: boolean;
@@ -486,18 +469,17 @@ interface CommandCodeAccountSlot {
486
469
  allowAuthFile: boolean;
487
470
  }
488
471
  /**
489
- * Why a key stopped serving requests.
472
+ * Why a key stopped serving requests, split by EVIDENCE — what the pool may
473
+ * claim about it — rather than by what it does.
490
474
  *
491
475
  * `rate-limit` is a USAGE-WINDOW rejection: the provider named one of its
492
476
  * metered windows (`error.rateLimit.window`, or a message saying the plan's
493
477
  * usage limit was reached — the only two shapes the official CLI's own
494
- * `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the
495
- * plain 429: the provider refused the request without saying anything about a
496
- * window, so the key leaves rotation for now but the pool must not describe it
497
- * as an exhausted window. Collapsing the two is issue #54: the reporter's
498
- * account panel showed the five-hour window at 2% and the weekly one at 10%
499
- * while the turn failed with "all 1 Command Code account(s) have exhausted
500
- * their usage window".
478
+ * `parseWindowLimitError`/`resolveWindowLabel` accept). `throttled` is the plain
479
+ * 429: the key leaves rotation for now, but the provider said nothing about a
480
+ * window, so the pool must not describe one as exhausted. Collapsing the two is
481
+ * issue #54: a bare 429 was reported as a spent window while the account card
482
+ * showed both windows barely used.
501
483
  */
502
484
  type AccountRejection = 'rate-limit' | 'throttled' | 'invalid-credential';
503
485
  /** One key's rotation state. */
@@ -510,11 +492,11 @@ interface CommandCodeAccountState {
510
492
  /** Marked by a 401: skipped until the stored credential changes. */
511
493
  'disabled';
512
494
  /**
513
- * The evidence behind the mark — what the pool may CLAIM when it reports
514
- * that no account can serve. `window`: the provider named a usage window, or
515
- * a `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429
516
- * that said nothing about a window (a burst limiter, or a model- or
517
- * spend-level limit the billing endpoint cannot show). `auth`: a 401.
495
+ * The evidence behind the mark — what the pool may CLAIM when it reports that
496
+ * no account can serve. `window`: the provider named a usage window, or a
497
+ * `/alpha/billing/credits` probe read one as exceeded. `throttle`: a 429 that
498
+ * said nothing about a window (a burst limiter, or a model-/spend-level limit
499
+ * the billing endpoint cannot show). `auth`: a 401.
518
500
  */
519
501
  cause: 'window' | 'throttle' | 'auth';
520
502
  /** Human-readable reason for the mark (e.g. `rate limited (429)`). */
@@ -547,43 +529,34 @@ interface CommandCodeAccountPoolDeps {
547
529
  resolveRef(ref: CredentialRef): Promise<string | undefined>;
548
530
  /** The official CLI auth-file key (`~/.commandcode/auth.json`); default slot only. */
549
531
  authFileKey(): string | undefined;
550
- /**
551
- * Probe one key's usage windows — BOTH windows the endpoint publishes (the
552
- * five-hour and the weekly one), not just the five-hour one; see
553
- * {@link AccountWindowProbe}. Undefined when the probe itself failed.
554
- */
532
+ /** Probe one key's usage windows (BOTH windows the endpoint publishes); undefined when it failed. */
555
533
  probeWindow(apiKey: string): Promise<AccountWindowProbe | undefined>;
556
534
  /**
557
- * The manually selected account (a slot id, e.g. `default` or an extra's
558
- * credential reference), re-read per resolution. The preferred account
559
- * serves whenever it is usable; an unknown id or an exhausted preferred
560
- * account falls back to the first usable slot — and an exhausted one is
561
- * re-probed on the way (see {@link CommandCodeAccountPool.resolveKey}), so
562
- * the fallback lasts only as long as the window really is exceeded.
535
+ * The manually selected account slot id, re-read per resolution. It serves
536
+ * whenever it is usable; an unknown id or an exhausted preferred account falls
537
+ * back to the first usable slot — and an exhausted one is re-probed on the way
538
+ * (see {@link CommandCodeAccountPool.resolveKey}), so the fallback lasts only
539
+ * as long as the window really is exceeded.
563
540
  */
564
541
  preferredId?(): string | undefined;
565
542
  /**
566
543
  * Model → account routing rules, re-read per resolution so settings changes
567
- * apply live. Each rule lists catalog model ids (see
568
- * {@link CommandCodeModelAccountRule}) to an account slot id. When the
569
- * request's model matches a rule and that account is usable, it serves
570
- * before the preferred/rotation selection; an unusable routed account falls
571
- * back to the normal selection (the router is a hint, never a hard gate).
544
+ * apply live. A matching, usable routed account serves before the
545
+ * preferred/rotation selection; an unusable one falls back to the normal
546
+ * selection — the router is a hint, never a hard gate.
572
547
  */
573
548
  modelAccountRules?(): readonly CommandCodeModelAccountRule[];
574
549
  /**
575
- * Clock seam for the explicit-account probe throttle. Tests drive it so the
576
- * "the interval elapsed, probe again" half of
577
- * {@link CommandCodeAccountPool.canProbeExplicit} is reachable without
578
- * waiting a real minute; production reads `Date.now()`.
550
+ * Clock seam for the explicit-account probe throttle, so the "the interval
551
+ * elapsed" half of {@link CommandCodeAccountPool.canProbeExplicit} is testable
552
+ * without waiting a real minute. Production reads `Date.now()`.
579
553
  */
580
554
  now?(): number;
581
555
  }
582
556
  /**
583
557
  * One "route these models to that account" rule. `models` lists catalog ids
584
- * (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an
585
- * extra account's credential reference). A request whose model id is in the
586
- * list routes to that account. The first matching rule in list order wins.
558
+ * (`deepseek/deepseek-v4-pro`, …); `account` is a slot id (`default` or an extra
559
+ * account's credential reference). The first matching rule in list order wins.
587
560
  */
588
561
  interface CommandCodeModelAccountRule {
589
562
  /** Catalog model ids to match against the request's model. */
@@ -599,10 +572,10 @@ interface CommandCodeModelAccountRule {
599
572
  */
600
573
  declare function accountUsable(state: CommandCodeAccountState | undefined): boolean;
601
574
  /**
602
- * Pick the account that should serve now: the manually preferred slot when it
603
- * is usable, otherwise the first usable account in rotation order; undefined
604
- * when no account is usable. Shared by the pool (request path) and the plugin
605
- * entry (the usage view's active badge) so both always agree.
575
+ * Pick the account that should serve now: the manually preferred slot when it is
576
+ * usable, otherwise the first usable account in rotation order; undefined when
577
+ * no account is usable. Shared by the pool (request path) and the plugin entry
578
+ * (the usage view's active badge) so both always agree.
606
579
  */
607
580
  declare function selectActiveAccount(accounts: readonly ResolvedAccount[], preferredId: string | undefined): ResolvedAccount | undefined;
608
581
  /**
@@ -643,27 +616,26 @@ declare class CommandCodeAccountPool {
643
616
  */
644
617
  describeAccounts(): Promise<ResolvedAccount[]>;
645
618
  /**
646
- * Hand out the key for a request: the model-routed account when the
647
- * request's model matches a rule (and that account is usable), else the
648
- * manually preferred account when usable, else the first usable account in
649
- * rotation order. Returns `undefined` when no account resolves any key at
650
- * all (the caller then reports the missing credential). Throws
651
- * `RATE_LIMIT` — naming the earliest window reset — or
652
- * `INVALID_CREDENTIAL` when accounts exist but none can serve.
619
+ * Hand out the key for a request: the model-routed account when the request's
620
+ * model matches a rule (and that account is usable), else the manually
621
+ * preferred account when usable, else the first usable account in rotation
622
+ * order. Returns `undefined` when no account resolves any key at all, or when
623
+ * an account this request already used is still UNMARKED — that rejection is
624
+ * the honest answer, so the caller's own rejection surfaces as itself. Throws
625
+ * `RATE_LIMIT` (naming the earliest window reset) or `INVALID_CREDENTIAL`
626
+ * when accounts exist but every one of them is marked.
653
627
  *
654
628
  * `options.model` is the request's model id; routing rules re-read per
655
- * resolution, so a settings change applies live.
656
- *
657
- * `options.tried` lists the keys this request has already used — the
658
- * just-rejected one included. They are removed from the resolution entirely,
659
- * which is what lets one request walk a four-account pool: an account-scoped
660
- * rejection that does not mark the key (no credits, a model outside the
661
- * account's plan) would otherwise be offered again on every attempt, and the
662
- * accounts behind it would never be reached.
629
+ * resolution, so a settings change applies live. `options.tried` lists the
630
+ * keys this request has already used — the just-rejected one included — and
631
+ * they are removed from the resolution entirely, which is what lets one
632
+ * request walk a four-account pool: a rejection that does not mark the key
633
+ * (no credits, a model outside the account's plan) would otherwise be offered
634
+ * again on every attempt and the accounts behind it never reached.
663
635
  *
664
- * An explicit selection (the pin or a model rule) that a rate-limit mark
665
- * would demote is probed before the fallback serves, so "falls back while
666
- * exhausted" never becomes "stays demoted until the process restarts".
636
+ * An explicit selection (the pin or a model rule) that a rate-limit mark would
637
+ * demote is probed before the fallback serves, so "falls back while exhausted"
638
+ * never becomes "stays demoted until the process restarts" (issue #51).
667
639
  */
668
640
  resolveKey(options?: {
669
641
  tried?: readonly string[];
@@ -673,53 +645,46 @@ declare class CommandCodeAccountPool {
673
645
  slot: CommandCodeAccountSlot;
674
646
  } | undefined>;
675
647
  /**
676
- * Record a rejection against one key. `rate-limit` marks the key's usage
677
- * WINDOW exhausted — as a `cooldown` until `resetAtMs` when the rejection
678
- * body named the provider's own reset time, otherwise as an `unknown` mark
679
- * whose window is probed lazily. `throttled` (the plain 429 that named no
680
- * window) marks the key with the `throttle` cause instead: it leaves rotation
681
- * exactly like a window mark does, but the pool's own diagnosis keeps saying
682
- * "rate limited" rather than inventing an exhausted window. A 401
683
- * (`invalid-credential`) disables the key until the stored credential
648
+ * Record a rejection against one key. A `throttled` rejection (the plain 429
649
+ * that named no window) marks the key with the `throttle` cause, leaving
650
+ * rotation exactly like a window mark but keeping the pool's own diagnosis at
651
+ * "rate limited" rather than inventing an exhausted window. `rate-limit`
652
+ * marks a `cooldown` until `resetAtMs` when the body named the provider's own
653
+ * reset, otherwise an `unknown` mark whose window is probed lazily.
654
+ * `invalid-credential` (401) disables the key until the stored credential
684
655
  * changes.
685
656
  *
686
- * `resetAtMs` is seconds-to-millis converted by the adapter from the
687
- * provider's `error.rateLimit.reset`: knowing the real reset immediately is
688
- * what keeps an exhausted account out of rotation for exactly as long as the
689
- * provider said. It only applies to a window mark; a plain throttle keeps the
690
- * window unknown on purpose, so a probe can still find out.
657
+ * `resetAtMs` is seconds-to-millis converted by the adapter from
658
+ * `error.rateLimit.reset`; it applies to a window mark only. A plain throttle
659
+ * keeps its window unknown on purpose, so a probe can still find out.
691
660
  */
692
661
  markRejected(apiKey: string, rejection: AccountRejection, resetAtMs?: number): void;
693
662
  /**
694
663
  * One account's key: literal → credential seam → auth file (default slot).
695
664
  *
696
665
  * Every source is normalized here, at the single point where a slot's key
697
- * enters the pool. The adapter sends the key through the harness's
698
- * `assertUsableApiKey()`, which trims it — a stored key from the credentials
699
- * seam, a `.env` line, or a shell export all pick up surrounding whitespace
700
- * — and reports that trimmed form back to `markRejected()`. Returning the
701
- * raw value would file every 429/401 mark under a key no later lookup can
702
- * find: rotation would re-offer the same account, the account card would show
703
- * no mark, and the usage endpoints would 401 while chat kept working.
704
- * Normalizing once makes resolution, probing, marking, and the request path
705
- * agree on one string.
666
+ * enters the pool. The adapter sends the key through
667
+ * `assertUsableApiKey()`, which trims it, and reports that trimmed form back
668
+ * to {@link markRejected}: returning the raw value would file every 429/401
669
+ * mark under a key no later lookup can find — rotation would re-offer the same
670
+ * account, the account card would show no mark, and the usage endpoints would
671
+ * 401 while chat kept working.
706
672
  */
707
673
  private resolveSlotKey;
708
674
  /**
709
- * The account the user explicitly asked for: the slot a model rule routes
710
- * the request to when that id exists among the resolved slots, else the
711
- * manually pinned slot. Consulted only on the fallback path — a usable
712
- * routed account already returned above — so unlike
713
- * {@link selectAccountForModel} it does NOT require the account to be
714
- * usable, which is exactly what {@link resolveKey} re-probes.
675
+ * The account the user explicitly asked for: the slot a model rule routes the
676
+ * request to when that id exists among the resolved slots, else the manually
677
+ * pinned slot. Consulted only on the fallback path, so — unlike
678
+ * {@link selectAccountForModel} — it does NOT require the account to be usable,
679
+ * which is exactly what {@link resolveKey} re-probes.
715
680
  */
716
681
  private explicitAccount;
717
682
  /**
718
683
  * Whether an explicitly selected account's mark is due for a window probe.
719
684
  * Only an `unknown` mark (a 429 whose reset was never learned) is worth
720
- * re-probing: a `cooldown` already carries its reset time and expires by
721
- * itself, and a `disabled` (401) key stays out until the stored credential
722
- * changes. The interval bounds a probe endpoint that keeps failing.
685
+ * re-probing: a `cooldown` carries its reset and expires by itself, and a
686
+ * `disabled` (401) key stays out until the stored credential changes. The
687
+ * interval bounds a probe endpoint that keeps failing.
723
688
  */
724
689
  private canProbeExplicit;
725
690
  /** The clock the probe throttle reads; injected so a test can travel in time. */
@@ -727,8 +692,8 @@ declare class CommandCodeAccountPool {
727
692
  /**
728
693
  * Probe one explicitly selected account's window and apply the answer. A
729
694
  * window that is no longer exceeded drops the mark, so the user's own
730
- * selection serves again on this very request. An exceeded one is stamped
731
- * as a cooldown carrying the provider's reset time, after which
695
+ * selection serves again on this very request; an exceeded one is stamped as
696
+ * a cooldown carrying the provider's reset time, after which
732
697
  * {@link accountUsable} lets the account back in with no further probe. A
733
698
  * probe that fails changes nothing: the mark stays `unknown` and the next
734
699
  * attempt waits out the interval.
@@ -738,34 +703,18 @@ declare class CommandCodeAccountPool {
738
703
  private pick;
739
704
  }
740
705
  //#endregion
741
- //#region src/command-guard.d.ts
742
- /**
743
- * The auto-approve strictness a user picks (`Config.commandGuardLevel`). Each
744
- * level is the probability every verdict must reach before the guard grants
745
- * `allowed-once`; a higher level approves less, on stronger evidence. Three
746
- * presets replace a free-form probability because the useful range is narrow
747
- * and a hand-typed 0.6 silently turns the guard into a rubber stamp.
748
- */
749
- type CommandGuardLevel = 'high' | 'medium' | 'low';
750
- //#endregion
751
706
  //#region src/capabilities.d.ts
752
707
  /**
753
708
  * Static capability snapshot for the Command Code provider: model →
754
709
  * reasoning-effort levels, vision/thinking flags, model → minimum plan tier,
755
710
  * subscription-plan labels, deals, and hourly (peak/off-peak) pricing.
756
711
  *
757
- * Everything in this module is synced from official sources (the command-code
758
- * CLI bundle's model table and the official plan/pricing/model docs — see the
759
- * dsh-commandcode-upstream skill for the exact extraction procedures), and
760
- * changes whenever an upstream CLI release reshuffles models/plans/prices.
761
- * Keeping the snapshot in its own module confines those frequent sync diffs
762
- * here: src/adapter.ts holds only the stable wire/runtime logic and imports
763
- * these tables + read helpers.
764
- *
765
- * Snapshot read helpers (planLabel, dealLabel, formatContext,
766
- * capabilityDescription, peakPricing*, compareByPlan, modelVisibleInPlan,
767
- * subscriptionPlanInfo, isFreeModel) live here too — they exist only to read
768
- * the tables, so a sync never has to touch src/adapter.ts.
712
+ * Everything here is synced from official sources — the command-code CLI
713
+ * bundle's model table (`dist/cli.mjs`, re-verified at command-code@1.66.0) and
714
+ * the official plan/pricing/model docs; see the dsh-commandcode-upstream skill
715
+ * for the extraction procedures. Keeping the snapshot in its own module
716
+ * confines those frequent sync diffs here: src/adapter.ts holds only the stable
717
+ * wire/runtime logic. The read helpers live here too, for the same reason.
769
718
  *
770
719
  * Ported from pi-commandcode-provider (MIT); originally part of src/adapter.ts
771
720
  * and split out so upstream syncs stay reviewable.
@@ -789,19 +738,22 @@ declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
789
738
  declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
790
739
  /**
791
740
  * Models WITHOUT a zero-data-retention upstream, per the official CLI's own
792
- * registry (`command-code@1.65.0` `dist/cli.mjs`: `modelSupportsZdr(id)` is
741
+ * registry (`command-code@1.66.0` `dist/cli.mjs`): `modelSupportsZdr(id)` is
793
742
  * exactly `!nonZdrSet.has(canonicalize(id))`, and `knownModelSupportsZdr`
794
- * carries the same membership in the sibling route table — the union is this
795
- * set). The official docs (commandcode.ai/docs/resources/zdr) put it in prose
796
- * — "99% of our models have ZDR-capable upstreams … only a small handful of
797
- * models are affected" — so the CLI's exclusion list is the only per-model
798
- * evidence there is; a ZDR request naming one of these fails with HTTP 422
799
- * `cmd_zdr_no_providers` instead of routing through a provider that retains.
743
+ * carries the same membership in the sibling route table — the UNION of both
744
+ * is this set. Reading only the sibling route table would drop `meituan/
745
+ * LongCat-2.0` and `stealth/pixel-canary`, which each appear in
746
+ * `modelSupportsZdr` alone. The official docs (commandcode.ai/docs/resources/
747
+ * zdr) put it in prose — "99% of our models have ZDR-capable upstreams … only
748
+ * a small handful of models are affected" — so the CLI's exclusion list is
749
+ * the only per-model evidence there is; a ZDR request naming one of these
750
+ * fails with HTTP 422 `cmd_zdr_no_providers` instead of routing through a
751
+ * provider that retains.
800
752
  *
801
753
  * Why a NEGATIVE set, and why "not listed" answers TRUE: 99% of the catalog is
802
754
  * covered, so the maintained difference is the exception list. This helper is
803
755
  * informational; the adapter sends the ZDR header for EVERY request when the
804
- * switch is on. The provider remains the routing authority and refuses an
756
+ * switch is on — the provider remains the routing authority and refuses an
805
757
  * unsupported model rather than silently dropping the privacy guarantee.
806
758
  *
807
759
  * `minimax/minimax-m3-free` is the one entry the public catalog
@@ -812,16 +764,9 @@ declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
812
764
  * Keep in sync via the dsh-commandcode-upstream skill: the CLI's registry data
813
765
  * (its `zdr:{only:[…]}` provider routes and the per-provider `zdr`/`noTraining`
814
766
  * flags) is upstream-internal routing, not a per-model contract, so this table
815
- * is the snapshot of the exclusion set and nothing more. The 1.62.0 → 1.64.0
816
- * diff of that union is EMPTY: both anchors were extracted from both bundles
817
- * during the 2026-09-23 check and each carries the same 20 members — which is
818
- * how rare a change here is expected to be. The 1.64.0 → 1.65.0 diff (2026-09-24)
819
- * is the counterexample that proves the check still runs: exactly one member
820
- * joins (`stealth/space-bunny-alpha`), and it is in both anchors. `meituan/
821
- * LongCat-2.0` is the one member the two anchors disagree about (it is in
822
- * `modelSupportsZdr`'s set in both releases and in neither `knownModelSupportsZdr`
823
- * set), so the union is
824
- * what this table follows; reading only the sibling route table would drop it.
767
+ * is the snapshot of the exclusion set and nothing more. It is a rare change:
768
+ * 20 members held across 1.62.0 → 1.64.0, and 1.65.0 and 1.66.0 each added
769
+ * exactly one (the two stealth-preview models below).
825
770
  */
826
771
  declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
827
772
  /**
@@ -831,65 +776,30 @@ declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
831
776
  */
832
777
  declare function supportsZeroDataRetention(modelId: string): boolean;
833
778
  /**
834
- * Models the official CLI's model table (command-code@1.53.0) marks
835
- * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
836
- * think automatically, with Command Code driving the depth. This is the
837
- * authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
838
- * mirrors the CLI's effort map exactly) stays the sole source for selectable
839
- * effort levels, and this snapshot is not surfaced in the picker's compact
840
- * description — it exists for programmatic consumers.
779
+ * Models the official CLI's model table marks `reasoning:!0` but defines no
780
+ * selectable `reasoning_effort` levels — they think automatically, with
781
+ * Command Code driving the depth. `KNOWN_EFFORTS` (which mirrors the CLI's
782
+ * effort map exactly) stays the sole source for selectable effort levels, and
783
+ * this snapshot is not surfaced in the picker's compact description — it exists
784
+ * for programmatic consumers.
841
785
  *
842
- * Source: the command-code@1.53.0 bundled model table (dist/cli.mjs),
843
- * cross-checked with https://commandcode.ai/docs/reference/cli/models.
844
- * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it
845
- * selectable `['low', 'high', 'max']` efforts; the preview then ended in
846
- * 1.34.0, removing the model from the catalog entirely. `tencent/hy4-preview`
847
- * joined this set in command-code@1.37.0 — reasoning:!0, no efforts, 1M
848
- * context, routed through OpenRouter — then gained selectable
849
- * `['low', 'medium', 'high']` efforts in command-code@1.38.0 and moved to
850
- * `KNOWN_EFFORTS`. `moonshotai/Kimi-K3` followed the same path in
851
- * command-code@1.39.3 — it gained `['low', 'high', 'max']` efforts and moved
852
- * to `KNOWN_EFFORTS`. command-code@1.42.0 added LongCat 2.0 (then
853
- * `meituan/LongCat-2.0:free`, now the paid `meituan/LongCat-2.0`; reasoning:!0,
854
- * no efforts). command-code@1.45.0 gave the Muse Spark family
855
- * (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor) selectable
856
- * `['low', 'medium', 'high', 'xhigh']` efforts — they moved to `KNOWN_EFFORTS`.
857
- * command-code@1.51.3 gave `MiniMaxAI/MiniMax-M3` selectable
858
- * `['low', 'medium', 'high']` efforts — it moved to `KNOWN_EFFORTS` too.
859
- * command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free`
860
- * (reasoning:!0, no efforts).)
861
- * command-code@1.53.0 added `deepseek/deepseek-v4.1-flash` with selectable
862
- * ['low', 'high', 'max'] efforts, so it lives in `KNOWN_EFFORTS`, not here.)
863
- * Keep in sync via the dsh-commandcode-upstream skill.
786
+ * Source: the bundled model table (dist/cli.mjs), cross-checked with
787
+ * https://commandcode.ai/docs/reference/cli/models. Keep in sync via the
788
+ * dsh-commandcode-upstream skill; a model that GAINS selectable efforts leaves
789
+ * this set for `KNOWN_EFFORTS` (Tencent Hy4 Preview, Kimi K3, the Muse Spark
790
+ * family and MiniMax M3 all took that path).
864
791
  */
865
792
  declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
866
793
  /**
867
794
  * The minimum subscription plan a model is included in, per the official plan
868
- * pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`, `/docs/plans/max`
869
- * and `/docs/resources/pricing-limits`). Each plan's model list is a superset of
870
- * the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max. Models absent from every
871
- * plan list (Claude Opus/Fable, Fugu Ultra) are Provider-tier.
872
- * `claude-fable-5-1` (Claude Fable 5.1, added in command-code@1.40.0) is
873
- * Provider/Max-tier exactly like `claude-fable-5` — its availability matrix on
874
- * the official plan/pricing pages grants individual-provider/max/ultra and
875
- * teams-pro only, and the CLI's plan-access map blocks it on Go/GOAT/Pro.
876
- * command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` (Go) and 1.42.0 added
877
- * LongCat 2.0 (Go — a free promo until 2026-09-19, when the backend renamed
878
- * `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`); 1.43.0 added
879
- * `google/gemini-3.8-flash` (GOAT) and 1.44.0 added `meta/muse-spark-1.3`
880
- * (GOAT) plus its Contributor sibling (Go); command-code@1.52.0 added the
881
- * free `inclusionai/ling-3.0-flash-sante:free` (Go); command-code@1.53.0
882
- * added `deepseek/deepseek-v4.1-flash` (Go); command-code@1.56.0 added
883
- * `Qwen/Qwen3.8-Omni-Flash` (Go); command-code@1.57.0 added
884
- * `z-ai/glm-5.3-flashx` (Go); command-code@1.59.0 added `xai/grok-4.7` (GOAT)
885
- * and 1.60.0 added `stepfun/Step-5-Preview` (Go); command-code@1.62.0 added the
886
- * MiMo V2.6 family — `xiaomi/mimo-v2.6-flash` + `xiaomi/mimo-v2.6-pro` (Go) and
887
- * `xiaomi/mimo-v2.6-pro-ultraspeed` (GOAT) — so the 1.58.0 -> 1.62.0 window's
888
- * only tier changes are additions and the superset chain still holds. The
889
- * 1.62.0 -> 1.65.0 window continues the pattern: 1.64.0 added
890
- * `claude-opus-5-5` (Provider/Max), `gpt-6-sol` (Pro) and `gpt-6-luna` (Go),
891
- * and 1.65.0 added `stealth/space-bunny-alpha` (Go, every tier) — additions
892
- * only, no tier moves.
795
+ * pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`,
796
+ * `/docs/plans/max` and `/docs/resources/pricing-limits`). Each plan's model
797
+ * list is a superset of the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max.
798
+ * Models absent from every plan list (Claude Opus/Fable, Fugu Ultra) are
799
+ * Provider-tier. Re-verified at command-code@1.66.0 (2026-09-27): 82 catalog
800
+ * ids at 52/60/74/82 cumulative, a strict superset chain — every release since
801
+ * 1.49.0 has been additive with no tier move, and per-entry tags below name the
802
+ * release that added each row.
893
803
  *
894
804
  * The Provider API exposes no plan metadata, so this snapshot is the source of
895
805
  * truth for the picker's plan annotation — it answers "which plan do I need to
@@ -921,11 +831,11 @@ declare function compareByPlan(a: {
921
831
  }): number;
922
832
  /**
923
833
  * Subscription plan table, synced from the official CLI bundle's plan maps
924
- * (located by the `"individual-go"` key in command-code@1.53.0 `dist/cli.mjs`,
925
- * re-verified unchanged through 1.53.0): subscription `planId`
926
- * prefix → display name and the plan's monthly credit total. This is the
927
- * account's own subscription (from `/alpha/billing/subscriptions`) — distinct
928
- * from {@link KNOWN_PLANS}, which maps catalog models to their minimum tier.
834
+ * (located by the `"individual-go"` key in `dist/cli.mjs`, re-verified unchanged
835
+ * through command-code@1.66.0): subscription `planId` prefix → display name and
836
+ * the plan's monthly credit total. This is the account's own subscription
837
+ * (from `/alpha/billing/subscriptions`) — distinct from {@link KNOWN_PLANS},
838
+ * which maps catalog models to their minimum tier.
929
839
  *
930
840
  * `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on
931
841
  * the {@link PLAN_ORDER} scale, used by the picker's plan filter
@@ -981,8 +891,13 @@ declare function modelVisibleInPlan(modelId: string, access: CommandCodeBillingA
981
891
  * render time against `Date.now()`), the deal label is hidden until the
982
892
  * snapshot is refreshed from the official page. `undefined` means
983
893
  * "no expiry" (permanent).
984
- * - `free` marks models whose requests cost no credits (Laguna S 2.1), shown
985
- * as a `FREE` badge; it degrades to a plain discount once the deal lapses.
894
+ * - `free` marks models whose requests cost no credits, shown as a `FREE`
895
+ * badge; it degrades to a plain discount once the deal lapses.
896
+ *
897
+ * A deal whose promo ENDS is removed here rather than left to lapse on
898
+ * `expiresAt`: the pricing page drops the entry, so a lapsed row would badge a
899
+ * model the catalog now serves at full price (Grok 4.7 reverts to $2.00 in /
900
+ * $6.00 out after its 2026-09-27 window).
986
901
  *
987
902
  * Keep in sync with the official pricing page when deals change (see the
988
903
  * dsh-commandcode-upstream skill).
@@ -1002,24 +917,11 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
1002
917
  * charges by the hour: peak hours are 01:00–04:00 and 06:00–10:00 UTC (7h per
1003
918
  * weekday, full price) **Monday to Friday only**; the other 17 hours of a
1004
919
  * weekday and every hour of Saturday/Sunday (UTC) are off-peak at half price.
1005
- * The V4 Flash Vision (exp) variant (command-code@1.32.0) shares the V4 Flash
1006
- * rates exactly — $0.15/$0.60 off-peak and $0.30/$1.20 peak, per the page's own
1007
- * `timeOfDay` block, not merely 2× its own off-peak figures: a rate that is
1008
- * internally consistent can still be the wrong row, which is why the vendored
1009
- * price table (`./model-prices.ts`) is synced from the page and not hand-kept.
1010
- * The picker shows the
1011
- * *current* state as a compact
1012
- * label (`Peak`/`Half`) matching the English noun style of the other markers
1013
- * (`Image`, `FREE`), so a developer can tell at a glance whether calling the
1014
- * model right now is cheap or expensive.
1015
- *
1016
- * Authoritative extraction: the pricing page embeds a model JSON array whose
1017
- * hourly-priced entries carry a `timeOfDay` block
1018
- * (`{ windows: "01–04 & 06–10 UTC, Mon–Fri", peakHoursPerDay: 7,
1019
- * offPeakHoursPerDay: 17, peak: {...}, offPeak: {...} }`). Exactly four models
1020
- * carry it: V4 Pro, V4 Flash, V4 Flash Vision (exp), and V4.1 Flash (added in
1021
- * command-code@1.53.0 at $0.15/$0.60 off-peak, $0.30/$1.20 peak — the same
1022
- * schedule as the other three).
920
+ * Exactly four models carry the page's `timeOfDay` block (the four rows below).
921
+ * The picker shows the *current* state as a compact label (`Peak`/`Half`)
922
+ * matching the English noun style of the other markers (`Image`, `FREE`), so a
923
+ * developer can tell at a glance whether calling the model right now is cheap
924
+ * or expensive.
1023
925
  *
1024
926
  * Extraction caution: the rendered HTML rows are a trap. Each annotation div
1025
927
  * sits inside its OWN row's container, immediately before the NEXT row starts,
@@ -1027,18 +929,19 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
1027
929
  * to the model printed after it — that is how `deepseek/deepseek-v4-flash-fast`
1028
930
  * was wrongly added here (its row is flat-priced at $0.28/$0.56/$0.07 and has
1029
931
  * no `timeOfDay` block). Trust the embedded JSON's `timeOfDay` membership and
1030
- * the 2× price relation, never the flat-text neighbor.
932
+ * the 2× price relation, never the flat-text neighbor. A rate that is
933
+ * internally consistent can still be the wrong row (the V4 Flash Vision (exp)
934
+ * variant is priced from the page's own `timeOfDay` block, not from 2× its own
935
+ * off-peak figures), which is why the vendored price table
936
+ * (`./model-prices.ts`) is synced from the page and not hand-kept.
1031
937
  *
1032
938
  * Keep in sync with the official pricing page when the model set, the peak
1033
939
  * windows, or the weekday rule change (see the dsh-commandcode-upstream skill).
1034
940
  */
1035
941
  declare const KNOWN_PEAK_PRICING: ReadonlySet<string>;
1036
942
  /**
1037
- * Whether `now` (defaults to `Date.now()`) falls in a peak-pricing window for
1038
- * time-of-day-priced models. Peak rates apply Monday–Friday (UTC) only: the
1039
- * official rule charges Saturday and Sunday completely off-peak for all 24
1040
- * hours, so a weekend timestamp is off-peak even inside `PEAK_HOUR_RANGES`.
1041
- * `undefined` for models outside the snapshot.
943
+ * As {@link isPeakPricingHour}, plus the {@link KNOWN_PEAK_PRICING} membership
944
+ * test; `undefined` for models outside the snapshot.
1042
945
  */
1043
946
  declare function peakPricingState(modelId: string, now?: number): 'peak' | 'off-peak' | undefined;
1044
947
  /**
@@ -1192,19 +1095,16 @@ interface CommandCodePriceTable {
1192
1095
  //#endregion
1193
1096
  //#region src/command-locales.d.ts
1194
1097
  /**
1195
- * Locale copy for the `/commandcode` usage command and the friendly
1196
- * image-gate error rewrite. Distinct from `./client/locales.ts` (the
1197
- * settings-page namespace `settings.commandcode`): the command runs on the
1198
- * Host and has no access to the client's `ctx.locale`, so the dictionaries
1199
- * are exposed as plain constants for direct lookup; the resolver lives in
1200
- * `pickCommandLocale()`. The image-gate wrapper also lives on the client
1201
- * but is reached from a non-React path that has no `t` in scope, so the
1202
- * same dictionaries serve both surfaces.
1098
+ * zh/en copy for the Host-side `/commandcode` usage command, as plain
1099
+ * constants: the command runs on the Host and has no access to the client's
1100
+ * `ctx.locale`, so the active locale is resolved by `pickCommandLocale()` and
1101
+ * the dictionaries are read by direct lookup. Distinct from
1102
+ * `./client/locales.ts` (the settings-page `settings.commandcode` namespace).
1203
1103
  *
1204
- * zh is the source of truth for the key set; en must carry the exact same
1205
- * keys — a mismatch is a compile error at the lookup site.
1104
+ * zh is the source of truth for the key set; `en` must carry exactly the same
1105
+ * keys, which the `Record` type makes a compile error.
1206
1106
  */
1207
- /** Active locale id recognized by the command and the image-gate wrapper. */
1107
+ /** Active locale id for the `/commandcode` command. */
1208
1108
  type LocaleId = 'zh' | 'en';
1209
1109
  //#endregion
1210
1110
  //#region src/commands.d.ts
@@ -1219,11 +1119,9 @@ interface CommandCodeCommandDeps<C extends CommandCodeConnectionOptions = Comman
1219
1119
  */
1220
1120
  reports?: () => Promise<CommandCodeAccountsReport>;
1221
1121
  /**
1222
- * Resolve the active locale for one command run. The plugin entry wires
1223
- * this from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent in
1224
- * programmatic setups (notably the existing test), the command renders
1225
- * with the default locale (`'zh'`) — historically the only language the
1226
- * command ever shipped in.
1122
+ * Resolve the active locale for one command run; the plugin entry wires it
1123
+ * from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent (notably in
1124
+ * tests), the command renders with the default locale `'zh'`.
1227
1125
  */
1228
1126
  getLocale?: () => LocaleId;
1229
1127
  }
@@ -1285,9 +1183,9 @@ declare const loginStatusSchema: TypertSchema<CommandCodeLoginStatus>;
1285
1183
  /**
1286
1184
  * The browser-login face the usage service exposes (`commandcode/login*`).
1287
1185
  * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry
1288
- * wired one; absent, `status`/`cancel` degrade to the idle status while
1289
- * `begin` rejects with a plain message (so the page's manual paste path
1290
- * stays the fallback instead of hanging).
1186
+ * wired one; absent, `status`/`cancel` degrade to the idle status and `begin`
1187
+ * rejects with a plain message, so the page's manual paste path stays the
1188
+ * fallback instead of hanging.
1291
1189
  */
1292
1190
  interface LoginFlowFacade {
1293
1191
  /** Start (or rejoin) an attempt; rejects when it cannot start at all. */
@@ -1308,10 +1206,9 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
1308
1206
  */
1309
1207
  reports?: () => Promise<CommandCodeAccountsReport>;
1310
1208
  /**
1311
- * Model-catalog source for the settings page's model editors (the
1312
- * routing-rule editor and the visible-models filter; wired by the plugin
1313
- * entry). Absent, the `models` endpoint answers an empty list — the page's
1314
- * editors degrade to the empty state.
1209
+ * Model-catalog source for the settings page's model editors. Absent, the
1210
+ * `models` endpoint answers an empty list — the page's editors degrade to
1211
+ * the empty state.
1315
1212
  */
1316
1213
  listModels?: () => Promise<CommandCodeCatalog>;
1317
1214
  /**
@@ -1321,11 +1218,7 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
1321
1218
  * only to stub it in a test.
1322
1219
  */
1323
1220
  prices?: () => CommandCodePriceTable;
1324
- /**
1325
- * The browser-login flow (wired by the plugin entry). Absent means the
1326
- * login endpoints answer `idle` / reject with a plain message — the page's
1327
- * manual paste path stays the fallback.
1328
- */
1221
+ /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */
1329
1222
  login?: LoginFlowFacade;
1330
1223
  }
1331
1224
  /**
@@ -1339,34 +1232,30 @@ declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = C
1339
1232
  private readonly deps;
1340
1233
  constructor(ctx: Context, deps: CommandCodeUsageDeps<C>);
1341
1234
  /**
1342
- * Account, usage, and credit state for the settings page's account card —
1343
- * one entry per pool account when the plugin entry wired `reports`, a
1344
- * single default-account entry otherwise. Degrades per endpoint like the
1345
- * `/commandcode` command (failures land in `report.failures`); throws
1346
- * `MISSING_CREDENTIAL` when no key resolves, which the Gateway folds into
1347
- * the failure branch the page renders as a hint.
1235
+ * Account, usage, and credit state for the settings page's account card.
1236
+ * Degrades per endpoint like the `/commandcode` command (failures land in
1237
+ * `report.failures`); throws `MISSING_CREDENTIAL` when no key resolves, which
1238
+ * the Gateway folds into the failure branch the page renders as a hint.
1348
1239
  */
1349
1240
  report(): Promise<CommandCodeAccountsReport>;
1350
1241
  /**
1351
- * The full model catalog for the settings page's model editors (the
1352
- * routing-rule editor and the visible-models filter). The browser never
1353
- * calls the Command Code API directly — the Host serves the catalog
1354
- * (already fetched/cached by the adapter) so models can be picked from
1355
- * the live list instead of typed by hand.
1242
+ * The full model catalog for the settings page's model editors. The browser
1243
+ * never calls the Command Code API directly — the Host serves the catalog
1244
+ * (already fetched/cached by the adapter) so models can be picked from the
1245
+ * live list instead of typed by hand.
1356
1246
  */
1357
1247
  models(): Promise<CommandCodeCatalog>;
1358
1248
  /**
1359
1249
  * The model price table the composer prices an in-progress session with.
1360
- * Static vendored data (the official pricing page's rates), served Host-side
1361
- * so the browser bundle never carries a copy that could drift from the
1362
- * snapshot, and so a price update reaches an open page without a rebuild.
1250
+ * Static vendored data, served Host-side so the browser bundle never carries
1251
+ * a copy that could drift from the snapshot, and so a price update reaches an
1252
+ * open page without a rebuild.
1363
1253
  */
1364
1254
  prices(): Promise<CommandCodePriceTable>;
1365
1255
  /**
1366
1256
  * Start (or rejoin) a browser-login attempt and return its fresh status —
1367
1257
  * `waiting` carrying the Studio URL. Rejects when the flow cannot start
1368
- * (no free loopback port, disposed plugin); the Gateway folds the throw
1369
- * into the failure branch the page renders.
1258
+ * (no free loopback port, disposed plugin).
1370
1259
  */
1371
1260
  loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1372
1261
  /** Poll a login attempt's status. */
@@ -1468,16 +1357,15 @@ declare class CommandCodeLoginFlow {
1468
1357
  * asynchronously (`complete()`), and that window is open to a cancel or a
1469
1358
  * fresh `begin()`; the generation lets a late completion recognize that it
1470
1359
  * no longer owns the status face and stop instead of storing a credential
1471
- * the user cancelled and flipping the page back to success.
1360
+ * the user cancelled.
1472
1361
  */
1473
1362
  private attemptSeq;
1474
1363
  /**
1475
- * The start currently binding a port, if any. Every `begin()` that arrives
1476
- * before it settles joins it: two independent starts would each bind their
1477
- * own loopback server, and only the LAST one is reachable by
1478
- * {@link CommandCodeLoginFlow.teardown} — the orphan keeps listening and
1479
- * answering `/callback` for the process's lifetime, and ten of them exhaust
1480
- * the port window so browser login dies until the Host restarts.
1364
+ * The start currently binding a port, if any. Every `begin()` arriving before
1365
+ * it settles joins it: two independent starts would each bind a loopback
1366
+ * server, and only the LAST one is reachable by `teardown()` — the orphan
1367
+ * keeps answering `/callback` for the process's lifetime, and ten of them
1368
+ * exhaust the port window so browser login dies until the Host restarts.
1481
1369
  */
1482
1370
  private starting;
1483
1371
  /** A live attempt's destination; different rows may not rejoin it. */
@@ -1550,32 +1438,25 @@ declare class CommandCodeLoginFlow {
1550
1438
  declare const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
1551
1439
  /**
1552
1440
  * The factory-declared search provider id dsh ships by default (from
1553
- * `dsh-base`'s cordis patch `web.config.searchProvider`). Kept as a
1554
- * documented reference only: disabling this plugin's `webSearch` toggle
1555
- * restores the previously selected backend (see
1556
- * {@link applyCommandCodeSearchSelection}) — it never forces this default,
1557
- * because forcing it is what used to silence sibling search plugins such as
1558
- * modsearch even with Command Code search turned off (issue #26).
1441
+ * `dsh-base`'s cordis patch `web.config.searchProvider`). A documented
1442
+ * reference only: disabling this plugin's `webSearch` toggle restores the
1443
+ * PREVIOUSLY selected backend, never this default (issue #26).
1559
1444
  */
1560
1445
  declare const DEFAULT_WEB_SEARCH_PROVIDER_ID = "deepseek-official";
1561
1446
  /**
1562
1447
  * Tracked web-search selection state for one mounted `WebRuntime`.
1563
1448
  *
1564
- * `owner` marks whether this plugin currently owns the selection (i.e. it
1565
- * wrote `commandcode` and has not given it back yet). `displaced` is the
1566
- * backend id the plugin displaced when it took over — restored when the
1567
- * toggle turns off or the plugin unloads. `undefined` means "nothing was
1568
- * configured, leave auto-select" and must round-trip untouched: writing the
1569
- * factory default instead would still override a sibling plugin's own
1570
- * constructor-time pin.
1449
+ * `owner` marks whether this plugin currently owns the selection. `displaced`
1450
+ * is the backend it took over — restored on disable or unload — and
1451
+ * `undefined` means "nothing was configured, leave auto-select" and must
1452
+ * round-trip untouched.
1571
1453
  *
1572
1454
  * `preexisting` is the one fact `displaced` cannot carry: an `undefined`
1573
1455
  * `displaced` means EITHER "the field was unset when we took over" (give
1574
- * `undefined` back on disable) OR "the field already read `commandcode`"
1575
- * (touch nothing on disable — see {@link applyCommandCodeSearchSelection}).
1576
- * Collapsing the two is what turned a user's own `searchProvider: commandcode`
1577
- * pin into an auto-select — and then into `WEB_PROVIDER_AMBIGUOUS` on every
1578
- * search — the moment this plugin was disabled or unloaded.
1456
+ * `undefined` back) OR "the field already read `commandcode`" (touch
1457
+ * nothing). Collapsing the two is what turned a user's own
1458
+ * `searchProvider: commandcode` pin into an auto-select, and then into
1459
+ * `WEB_PROVIDER_AMBIGUOUS` on every search.
1579
1460
  */
1580
1461
  interface CommandCodeSearchSelection {
1581
1462
  owner: boolean;
@@ -1590,24 +1471,15 @@ declare function commandCodeSearchSelection(): CommandCodeSearchSelection;
1590
1471
  * providers (issue #26).
1591
1472
  *
1592
1473
  * - Enabling writes `commandcode` and remembers whatever it displaced. When
1593
- * the plugin already owns the selection (e.g. a settings save while still
1594
- * on), the original `displaced` value is kept — the field currently holds
1595
- * our own id, which must never be mistaken for the user's backend.
1596
- * - Disabling hands the selection back to the remembered backend. When the
1597
- * state holds no memory (a fresh boot straight into `webSearch: false`),
1598
- * the field is left alone: the runtime's current value — a sibling's
1599
- * cordis pin such as `searchProvider: modsearch`, or unset for
1600
- * auto-select — already says what the user wants.
1601
- * - When the field already reads `commandcode` at first touch (e.g. a
1602
- * surviving runtime the plugin did not set, or a manual
1603
- * `searchProvider: commandcode` pin), `displaced` stays undefined and
1604
- * `preexisting` is set, so the later disable is a no-op rather than a guess
1605
- * at the factory default. A "no-op" means the field is left ALONE: writing
1606
- * that `undefined` back would destroy the user's own pin, and dsh-web reads
1607
- * a cleared `searchProviderId` as auto-select — where a second usable
1608
- * provider (the shipped `deepseek-official` is usable whenever a DeepSeek
1609
- * key resolves) makes EVERY later search throw
1610
- * `WEB_PROVIDER_AMBIGUOUS`.
1474
+ * the plugin already owns the selection, the original `displaced` is kept —
1475
+ * the field currently holds our own id, which must never be mistaken for the
1476
+ * user's backend.
1477
+ * - Disabling hands the selection back to the remembered backend only when
1478
+ * this plugin actually took it over. A fresh boot straight into
1479
+ * `webSearch: false`, or a `preexisting` field, leaves it ALONE: writing the
1480
+ * empty memory back would clear the user's own `searchProvider: commandcode`
1481
+ * pin and hand the selection to dsh-web's auto-select, where a second usable
1482
+ * provider makes every later search throw `WEB_PROVIDER_AMBIGUOUS`.
1611
1483
  *
1612
1484
  * Never throws: like the low-level rewrite, a hardened runtime shape degrades
1613
1485
  * to registered-but-unselected.
@@ -1623,11 +1495,11 @@ interface CommandCodeSearchProviderDeps {
1623
1495
  fetchImpl?: typeof fetch;
1624
1496
  }
1625
1497
  /**
1626
- * A `ctx.web` search provider backed by the Command Code Provider API. Reuses
1627
- * the plugin's credential chain and `apiBase`, so search "just works" with the
1628
- * existing key — the model-facing `web_search` tool needs no separate
1629
- * configuration. Selection between multiple search providers is the web seam's
1630
- * job (pin `searchProvider: commandcode` if ambiguous).
1498
+ * A `ctx.web` search provider backed by the Command Code Provider API, reusing
1499
+ * the plugin's credential chain and `apiBase` so the model-facing `web_search`
1500
+ * tool needs no separate configuration. Selection between multiple search
1501
+ * providers is the web seam's job (pin `searchProvider: commandcode` if
1502
+ * ambiguous).
1631
1503
  */
1632
1504
  declare class CommandCodeSearchProvider implements WebSearchProvider {
1633
1505
  private readonly deps;
@@ -1649,11 +1521,9 @@ interface TuiLocalizedText {
1649
1521
  type TuiSettingsFieldKind = 'text' | 'number' | 'boolean' | 'select';
1650
1522
  /** One choice of an options-bearing field. */
1651
1523
  interface TuiSettingsFieldOption {
1652
- /** Stored value. */
1653
1524
  readonly value: string;
1654
1525
  /** Display label (English; also the fallback). */
1655
1526
  readonly label: string;
1656
- /** Provider-owned translations for the label. */
1657
1527
  readonly descriptions?: TuiLocalizedText;
1658
1528
  }
1659
1529
  /** The write one field's draft stages when the section is saved. */
@@ -1669,11 +1539,9 @@ interface TuiSettingsField {
1669
1539
  readonly path: readonly string[];
1670
1540
  /** Short field label (English; also the fallback). */
1671
1541
  readonly label: string;
1672
- /** Provider-owned translations for the label. */
1673
1542
  readonly descriptions?: TuiLocalizedText;
1674
1543
  /** Optional one-line help rendered under the field. */
1675
1544
  readonly hint?: string;
1676
- /** Provider-owned translations for the hint. */
1677
1545
  readonly hintDescriptions?: TuiLocalizedText;
1678
1546
  /** Optional group id; grouped fields render on that group's subpage. */
1679
1547
  readonly group?: string;
@@ -1705,7 +1573,6 @@ interface TuiSettingsGroup {
1705
1573
  readonly id: string;
1706
1574
  /** Group title (English; also the fallback). */
1707
1575
  readonly title: string;
1708
- /** Provider-owned translations for the title. */
1709
1576
  readonly descriptions?: TuiLocalizedText;
1710
1577
  }
1711
1578
  /** One plugin's section inside the dsh-TUI settings screen. */
@@ -1714,7 +1581,6 @@ interface TuiSettingsSection {
1714
1581
  readonly ns: string;
1715
1582
  /** Section title (English; also the fallback). */
1716
1583
  readonly title: string;
1717
- /** Provider-owned translations for the title. */
1718
1584
  readonly descriptions?: TuiLocalizedText;
1719
1585
  /** Optional navigation groups, in display order. */
1720
1586
  readonly groups?: readonly TuiSettingsGroup[];
@@ -1782,25 +1648,22 @@ interface CommandCodeTuiSettingsDeps {
1782
1648
  * Build the section descriptor. Pure, so tests can pin the exact fields
1783
1649
  * without a dsh-TUI host.
1784
1650
  *
1785
- * Field choices worth keeping: the two option-bearing fields (`activeAccount`,
1786
- * `lang`) are `text` + `options` rather than `select`, because a `select`
1787
- * cannot express "unset" — cycling only ever lands on a declared option, so a
1788
- * `select` would strand the user on a pinned value with no way back to
1789
- * automatic. The `auto` sentinel plus a `parse` that clears the path keeps the
1790
- * unset state reachable. `filterModelsByPlan` formats its EFFECTIVE default
1791
- * (unset means true at the adapter), so a fresh install reads true instead of
1792
- * the screen's "(empty)".
1651
+ * The two option-bearing fields (`activeAccount`, `lang`) are `text` +
1652
+ * `options` rather than `select`, because a `select` cannot express "unset" —
1653
+ * cycling only ever lands on a declared option, so it would strand the user on
1654
+ * a pinned value with no way back to automatic. The `auto` sentinel plus a
1655
+ * `parse` that clears the path keeps unset reachable. `filterModelsByPlan`
1656
+ * formats its EFFECTIVE default (unset means true at the adapter) so a fresh
1657
+ * install reads true instead of the screen's "(empty)".
1793
1658
  */
1794
1659
  declare function buildCommandCodeTuiSection(deps: CommandCodeTuiSettingsDeps): TuiSettingsSection;
1795
1660
  /**
1796
1661
  * Register the Command Code section on a dsh-TUI host.
1797
1662
  *
1798
- * @param ctx - the context of an activated `tuiSettingsSections` injection.
1799
- * @param deps - plugin-owned facts the section reads.
1800
1663
  * @returns a refresh function that re-registers the section when a fact it
1801
- * renders changed (the plugin entry calls it from its settings `onChange`
1802
- * hook), or `undefined` when the seam is unusable. The returned function is
1803
- * inert after the fiber is torn down.
1664
+ * renders changed — the plugin entry calls it from its
1665
+ * `loader/volatile-update` listener — or `undefined` when the seam is
1666
+ * unusable. The returned function is inert after the fiber is torn down.
1804
1667
  */
1805
1668
  declare function applyCommandCodeTuiSettings(ctx: Context, deps: CommandCodeTuiSettingsDeps): (() => void) | undefined;
1806
1669
  //#endregion
@@ -1835,14 +1698,11 @@ interface Config {
1835
1698
  streamIdleTimeoutMs?: number;
1836
1699
  /**
1837
1700
  * Transport failures one request absorbs before the failure is surfaced;
1838
- * defaults to 5. The route's retry policy is near-unbounded on purpose (1000
1839
- * attempts, waits doubling to 15 minutes) because that shape is for the
1840
- * failures a provider asks to have retried — an exhausted rate-limit window,
1841
- * a gateway 520. A transport failure is not one of those: the first attempts
1842
- * recover an ordinary blip (the default 5 retries are scheduled 0.5/1/2/4/8 s
1843
- * after the failures before them, so ~15.5 s of grace), and after that the
1844
- * wait is pure stall, so the retries are capped here. Raise it on a genuinely
1845
- * flaky link; 0 surfaces every transport failure immediately.
1701
+ * defaults to 5. The route's retry policy is near-unbounded on purpose
1702
+ * (1000 attempts, waits doubling to 15 minutes) because that shape is for
1703
+ * the failures a provider asks to have retried; a transport failure is not
1704
+ * one of those, and after ~15.5 s of grace the wait is pure stall, so it is
1705
+ * capped here (issue #39). 0 surfaces every transport failure immediately.
1846
1706
  */
1847
1707
  transportMaxRetries?: number;
1848
1708
  /**
@@ -1854,8 +1714,7 @@ interface Config {
1854
1714
  filterModelsByPlan?: boolean;
1855
1715
  /**
1856
1716
  * Visible-model allowlist: catalog model ids shown in pickers. Empty or
1857
- * unset means "show everything". Persisted by the settings page's model
1858
- * filter card; applies after the subscription-tier filter.
1717
+ * unset means "show everything"; applied after the subscription-tier filter.
1859
1718
  */
1860
1719
  visibleModels?: string[];
1861
1720
  /**
@@ -1863,117 +1722,82 @@ interface Config {
1863
1722
  * list, keyed by catalog id (`true` = listed, `false` = hidden). An id here
1864
1723
  * decides that model on its own; an id absent here follows `visibleModels`.
1865
1724
  * dsh-TUI keys a staged edit by the field's path, so the checkboxes need one
1866
- * path per model — a map — because a boolean field cannot express "this id
1867
- * is a member of the array".
1725
+ * path per model — a map.
1868
1726
  */
1869
1727
  modelVisibility?: Record<string, boolean>;
1870
1728
  /**
1871
1729
  * Extra accounts for multi-account rotation. The top-level
1872
1730
  * `apiKey`/`apiKeyEnv` (plus the CLI auth file) always form the first
1873
- * (`default`) account; each entry here adds one more. When a request is
1874
- * rejected pre-stream with 429 (usage window exhausted) or 401, the next
1875
- * account's key retried transparently; when every account is exhausted the
1876
- * request fails with a `RATE_LIMIT` error naming the earliest window
1877
- * reset. Entries without `apiKey` or `apiKeyEnv` are ignored.
1731
+ * (`default`) account; each entry here adds one more, and an entry with
1732
+ * neither `apiKey` nor `apiKeyEnv` is ignored. A pre-stream 429/401 marks
1733
+ * the key and the next account's key is retried transparently.
1878
1734
  */
1879
1735
  accounts?: CommandCodeAccountConfig[];
1880
1736
  /**
1881
1737
  * Manually selected active account: a slot id — `default`, or an extra
1882
- * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). The
1883
- * selected account serves whenever it is usable; an unknown id or an
1884
- * exhausted selected account falls back to the first usable slot (automatic
1885
- * rotation still applies). Unset means "first usable account".
1738
+ * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). It serves
1739
+ * whenever usable; an unknown id or an exhausted one falls back to rotation
1740
+ * order. Unset means "first usable account".
1886
1741
  */
1887
1742
  activeAccount?: string;
1888
1743
  /**
1889
- * Model → account routing rules. Each rule lists catalog model ids to an
1890
- * account slot id (`default`, or an extra account's credential reference).
1891
- * When a request's model is in a rule's list and the routed account is
1892
- * usable, that account serves — before the manual {@link activeAccount} and
1893
- * the passive rotation order. A routed account that is exhausted or invalid
1894
- * falls back to the normal selection, so the router is a hint, never a hard
1895
- * gate. The first matching rule wins.
1744
+ * Model → account routing rules, each listing catalog model ids for an
1745
+ * account slot id. A matching rule's account serves before {@link
1746
+ * activeAccount} and the passive rotation order; an unusable routed account
1747
+ * falls back, so the router is a hint, never a hard gate. First match wins.
1896
1748
  */
1897
1749
  modelAccountRules?: CommandCodeModelAccountRule[];
1898
1750
  /**
1899
1751
  * Whether to use Command Code as the backend for dsh's model-facing
1900
- * `web_search` tool. When enabled, the plugin registers a `commandcode`
1901
- * search provider on `ctx.web` AND selects `commandcode` in the web seam
1902
- * (so it wins over the shipped `deepseek-official` or a sibling search
1903
- * plugin's pin), using the SAME Command Code API key/base as chat. When
1904
- * disabled, the selection is handed back to whichever backend was there
1905
- * before — turning it off never forces the factory default, so a sibling
1906
- * search plugin (e.g. modsearch) keeps working (issue #26). The rewrite
1907
- * rides dsh's internal `searchProviderId`, which is read per search call,
1908
- * so a setting change lands on the next search without a restart.
1909
- * Defaults to true.
1752
+ * `web_search` tool. Enabled registers a `commandcode` search provider on
1753
+ * `ctx.web` AND selects it over the shipped `deepseek-official` (or a
1754
+ * sibling plugin's pin), reusing the SAME key and apiBase as chat. Disabling
1755
+ * hands the selection back to whichever backend was there before, so a
1756
+ * sibling search plugin (e.g. modsearch) keeps working (issue #26). The
1757
+ * write rides dsh's internal `searchProviderId`, read per search call, so a
1758
+ * setting change lands on the next search without a restart. Defaults true.
1910
1759
  */
1911
1760
  webSearch?: boolean;
1912
1761
  /**
1913
1762
  * Whether the Web sidebar shows the plans & quota card
1914
- * (`sidebar.footer.action`). Defaults to false: the card is opt-in, so an
1915
- * unset document renders no quota surface in the sidebar and mounts no
1916
- * background usage poll for it. Only the sidebar entry is affected — the
1917
- * dashboard cell behind it stays registered, it simply has no trigger until
1918
- * the toggle is on. Read by the browser client; the adapter ignores it.
1763
+ * (`sidebar.footer.action`). Defaults to false, so an unset document mounts
1764
+ * no sidebar quota surface and no background usage poll for it; the
1765
+ * dashboard cell behind it stays registered. Read by the browser client; the
1766
+ * adapter ignores it.
1919
1767
  */
1920
1768
  showSidebarQuota?: boolean;
1921
- /**
1922
- * Whether the Command Code decision model (`typesafe/jev`) may auto-approve
1923
- * shell commands that dsh was about to ask about. Defaults to FALSE: the
1924
- * guard turns a model's opinion into a one-shot approval grant, so it is
1925
- * opt-in, and the command text (plus the agent's own description of it) is
1926
- * sent to Command Code to judge. Only commands a policy already wanted a
1927
- * human to look at are ever judged, and only a confident "safe" verdict
1928
- * (`commandGuardLevel`) skips the prompt — every other outcome, including
1929
- * any failure of the decision call itself, delegates to the normal approval
1930
- * flow. See `./command-guard.ts`.
1931
- */
1932
- commandGuard?: boolean;
1933
- /**
1934
- * How confident every verdict must be before the guard skips the approval
1935
- * prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower
1936
- * level approves more, on less evidence. The decision budget is fixed
1937
- * (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.
1938
- */
1939
- commandGuardLevel?: CommandGuardLevel;
1940
1769
  /**
1941
1770
  * Whether requests enforce zero data retention: the provider then routes
1942
1771
  * them only through upstreams that keep no prompts/completions and never
1943
1772
  * train on them (its own opt-in, `CMD_ZDR=1` in the CLI / `x-cmd-zdr: 1` on
1944
1773
  * the Provider API). Defaults to FALSE: `zdr` changes WHERE a request is
1945
- * served. Every chat request carries the header when enabled; a model with
1946
- * no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` instead of
1947
- * being routed through an upstream that retains data. ZDR capacity is
1948
- * priced pass-through and usually costs more, and the price readout keeps
1949
- * quoting the ordinary catalog rates (the real per-request price shows in
1950
- * Command Code's Studio). The decision endpoint behind the command guard is
1951
- * never ZDR-enforced — see `./systemone.ts`.
1774
+ * served. Every chat request carries the header when enabled, and a model
1775
+ * with no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` rather
1776
+ * than losing the guarantee. ZDR capacity is priced pass-through and usually
1777
+ * costs more; the price readout keeps quoting the ordinary catalog rates
1778
+ * (the real per-request price shows in Command Code's Studio).
1952
1779
  */
1953
1780
  zdr?: boolean;
1954
1781
  /**
1955
1782
  * Language override for the `/commandcode` Host-side command's user-facing
1956
- * copy. Host commands cannot read the client's `ctx.locale`, so this is
1957
- * the explicit knob: `'zh'` or `'en'`. Unset means the command reads
1958
- * `LC_ALL`/`LANG` from the launching shell, falling back to `'zh'`. The
1959
- * web settings page is unaffected — it follows the browser's language
1960
- * preference on its own. Two surfaces, two independent locales. The
1961
- * declared type is `string` (the schemastery `pattern` cannot narrow
1962
- * literal types); an unknown value is treated as "unset" by
1963
- * `pickCommandLocale`.
1783
+ * copy. Host commands cannot read the client's `ctx.locale`, so this is the
1784
+ * explicit knob: `'zh'` or `'en'`, defaulting to `'zh'`. The web settings
1785
+ * page is unaffected — it follows the browser's language preference on its
1786
+ * own. The declared type is `string` (the schemastery `pattern` cannot
1787
+ * narrow literal types); `pickCommandLocale` treats an unknown value as
1788
+ * "unset" and then reads `LC_ALL`/`LANG`, which is only reachable when
1789
+ * `lang` is absent from a programmatically built config.
1964
1790
  */
1965
1791
  lang?: string;
1966
1792
  }
1967
1793
  /**
1968
1794
  * The Config schema: every field volatile except the composition-only `apiKey`
1969
- * secret.
1970
- *
1971
- * dsh 0.1.7's settings forms are projected from the schema's `meta.volatile`
1972
- * nodes, so an unmarked field would be invisible to AND unwritable from the
1973
- * settings page and refused by form-edit path validation — and the loader
1974
- * hands `apply()` a live reference per marked field, committing later writes
1975
- * without remounting this fiber (the `loader/volatile-update` listener at the
1976
- * bottom of `apply` covers the facts that are not re-derived per read).
1795
+ * secret. 0.1.7's settings forms are projected from the schema's
1796
+ * `meta.volatile` nodes, so an unmarked field would be invisible to AND
1797
+ * unwritable from the settings page. The loader also hands `apply()` a live
1798
+ * reference per marked field, so writes commit in place without remounting
1799
+ * this fiber — the `loader/volatile-update` listener at the bottom of `apply`
1800
+ * re-derives the two facts that are not re-read per request.
1977
1801
  */
1978
1802
  declare const Config: z<Config>;
1979
1803
  /** One resolution's complete request facts: connection plus credential reference. */
@@ -1984,7 +1808,7 @@ interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {
1984
1808
  * The one explicit resolve step from raw config to validated connection
1985
1809
  * facts. Programmatic construction may bypass Schemastery normalization, so
1986
1810
  * every default is re-judged here — for the composition entry at load and for
1987
- * each settings snapshot at its first use.
1811
+ * every settings-backed read.
1988
1812
  */
1989
1813
  declare function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions;
1990
1814
  declare function apply(ctx: Context, config: Config): void;