@mars-sea/dsh-commandcode-provider 0.11.16 → 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.2";
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,20 +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.2` `dist/cli.mjs`, unchanged from 1.65.0:
793
- * `modelSupportsZdr(id)` is exactly `!nonZdrSet.has(canonicalize(id))`, and
794
- * `knownModelSupportsZdr`
795
- * carries the same membership in the sibling route table — the union is this
796
- * set). The official docs (commandcode.ai/docs/resources/zdr) put it in prose
797
- * — "99% of our models have ZDR-capable upstreams … only a small handful of
798
- * models are affected" — so the CLI's exclusion list is the only per-model
799
- * evidence there is; a ZDR request naming one of these fails with HTTP 422
800
- * `cmd_zdr_no_providers` instead of routing through a provider that retains.
741
+ * registry (`command-code@1.66.0` `dist/cli.mjs`): `modelSupportsZdr(id)` is
742
+ * exactly `!nonZdrSet.has(canonicalize(id))`, and `knownModelSupportsZdr`
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.
801
752
  *
802
753
  * Why a NEGATIVE set, and why "not listed" answers TRUE: 99% of the catalog is
803
754
  * covered, so the maintained difference is the exception list. This helper is
804
755
  * informational; the adapter sends the ZDR header for EVERY request when the
805
- * 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
806
757
  * unsupported model rather than silently dropping the privacy guarantee.
807
758
  *
808
759
  * `minimax/minimax-m3-free` is the one entry the public catalog
@@ -813,16 +764,9 @@ declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
813
764
  * Keep in sync via the dsh-commandcode-upstream skill: the CLI's registry data
814
765
  * (its `zdr:{only:[…]}` provider routes and the per-provider `zdr`/`noTraining`
815
766
  * flags) is upstream-internal routing, not a per-model contract, so this table
816
- * is the snapshot of the exclusion set and nothing more. The 1.62.0 → 1.64.0
817
- * diff of that union is EMPTY: both anchors were extracted from both bundles
818
- * during the 2026-09-23 check and each carries the same 20 members — which is
819
- * how rare a change here is expected to be. The 1.64.0 → 1.65.0 diff (2026-09-24)
820
- * is the counterexample that proves the check still runs: exactly one member
821
- * joins (`stealth/space-bunny-alpha`), and it is in both anchors. `meituan/
822
- * LongCat-2.0` is the one member the two anchors disagree about (it is in
823
- * `modelSupportsZdr`'s set in both releases and in neither `knownModelSupportsZdr`
824
- * set), so the union is
825
- * 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).
826
770
  */
827
771
  declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
828
772
  /**
@@ -832,65 +776,30 @@ declare const KNOWN_NON_ZDR_MODELS: ReadonlySet<string>;
832
776
  */
833
777
  declare function supportsZeroDataRetention(modelId: string): boolean;
834
778
  /**
835
- * Models the official CLI's model table (command-code@1.53.0) marks
836
- * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
837
- * think automatically, with Command Code driving the depth. This is the
838
- * authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
839
- * mirrors the CLI's effort map exactly) stays the sole source for selectable
840
- * effort levels, and this snapshot is not surfaced in the picker's compact
841
- * 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.
842
785
  *
843
- * Source: the command-code@1.53.0 bundled model table (dist/cli.mjs),
844
- * cross-checked with https://commandcode.ai/docs/reference/cli/models.
845
- * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it
846
- * selectable `['low', 'high', 'max']` efforts; the preview then ended in
847
- * 1.34.0, removing the model from the catalog entirely. `tencent/hy4-preview`
848
- * joined this set in command-code@1.37.0 — reasoning:!0, no efforts, 1M
849
- * context, routed through OpenRouter — then gained selectable
850
- * `['low', 'medium', 'high']` efforts in command-code@1.38.0 and moved to
851
- * `KNOWN_EFFORTS`. `moonshotai/Kimi-K3` followed the same path in
852
- * command-code@1.39.3 — it gained `['low', 'high', 'max']` efforts and moved
853
- * to `KNOWN_EFFORTS`. command-code@1.42.0 added LongCat 2.0 (then
854
- * `meituan/LongCat-2.0:free`, now the paid `meituan/LongCat-2.0`; reasoning:!0,
855
- * no efforts). command-code@1.45.0 gave the Muse Spark family
856
- * (1.1, 1.2, 1.2-contributor, 1.3, 1.3-contributor) selectable
857
- * `['low', 'medium', 'high', 'xhigh']` efforts — they moved to `KNOWN_EFFORTS`.
858
- * command-code@1.51.3 gave `MiniMaxAI/MiniMax-M3` selectable
859
- * `['low', 'medium', 'high']` efforts — it moved to `KNOWN_EFFORTS` too.
860
- * command-code@1.52.0 added `inclusionai/ling-3.0-flash-sante:free`
861
- * (reasoning:!0, no efforts).)
862
- * command-code@1.53.0 added `deepseek/deepseek-v4.1-flash` with selectable
863
- * ['low', 'high', 'max'] efforts, so it lives in `KNOWN_EFFORTS`, not here.)
864
- * 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).
865
791
  */
866
792
  declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
867
793
  /**
868
794
  * The minimum subscription plan a model is included in, per the official plan
869
- * pages (`/docs/plans/go`, `/docs/plans/goat`, `/docs/plans/pro`, `/docs/plans/max`
870
- * and `/docs/resources/pricing-limits`). Each plan's model list is a superset of
871
- * the one below it: Go ⊂ GOAT ⊂ Pro ⊂ Provider/Max. Models absent from every
872
- * plan list (Claude Opus/Fable, Fugu Ultra) are Provider-tier.
873
- * `claude-fable-5-1` (Claude Fable 5.1, added in command-code@1.40.0) is
874
- * Provider/Max-tier exactly like `claude-fable-5` — its availability matrix on
875
- * the official plan/pricing pages grants individual-provider/max/ultra and
876
- * teams-pro only, and the CLI's plan-access map blocks it on Go/GOAT/Pro.
877
- * command-code@1.41.0 added `Qwen/Qwen3.8-Max-0902` (Go) and 1.42.0 added
878
- * LongCat 2.0 (Go — a free promo until 2026-09-19, when the backend renamed
879
- * `meituan/LongCat-2.0:free` to the paid `meituan/LongCat-2.0`); 1.43.0 added
880
- * `google/gemini-3.8-flash` (GOAT) and 1.44.0 added `meta/muse-spark-1.3`
881
- * (GOAT) plus its Contributor sibling (Go); command-code@1.52.0 added the
882
- * free `inclusionai/ling-3.0-flash-sante:free` (Go); command-code@1.53.0
883
- * added `deepseek/deepseek-v4.1-flash` (Go); command-code@1.56.0 added
884
- * `Qwen/Qwen3.8-Omni-Flash` (Go); command-code@1.57.0 added
885
- * `z-ai/glm-5.3-flashx` (Go); command-code@1.59.0 added `xai/grok-4.7` (GOAT)
886
- * and 1.60.0 added `stepfun/Step-5-Preview` (Go); command-code@1.62.0 added the
887
- * MiMo V2.6 family — `xiaomi/mimo-v2.6-flash` + `xiaomi/mimo-v2.6-pro` (Go) and
888
- * `xiaomi/mimo-v2.6-pro-ultraspeed` (GOAT) — so the 1.58.0 -> 1.62.0 window's
889
- * only tier changes are additions and the superset chain still holds. The
890
- * 1.62.0 -> 1.65.0 window continues the pattern: 1.64.0 added
891
- * `claude-opus-5-5` (Provider/Max), `gpt-6-sol` (Pro) and `gpt-6-luna` (Go),
892
- * and 1.65.0 added `stealth/space-bunny-alpha` (Go, every tier) — additions
893
- * 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.
894
803
  *
895
804
  * The Provider API exposes no plan metadata, so this snapshot is the source of
896
805
  * truth for the picker's plan annotation — it answers "which plan do I need to
@@ -922,11 +831,11 @@ declare function compareByPlan(a: {
922
831
  }): number;
923
832
  /**
924
833
  * Subscription plan table, synced from the official CLI bundle's plan maps
925
- * (located by the `"individual-go"` key in command-code@1.53.0 `dist/cli.mjs`,
926
- * re-verified unchanged through 1.53.0): subscription `planId`
927
- * prefix → display name and the plan's monthly credit total. This is the
928
- * account's own subscription (from `/alpha/billing/subscriptions`) — distinct
929
- * 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.
930
839
  *
931
840
  * `tierWeight` is plugin-added (not from the CLI maps): the plan's rank on
932
841
  * the {@link PLAN_ORDER} scale, used by the picker's plan filter
@@ -982,8 +891,13 @@ declare function modelVisibleInPlan(modelId: string, access: CommandCodeBillingA
982
891
  * render time against `Date.now()`), the deal label is hidden until the
983
892
  * snapshot is refreshed from the official page. `undefined` means
984
893
  * "no expiry" (permanent).
985
- * - `free` marks models whose requests cost no credits (Laguna S 2.1), shown
986
- * 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).
987
901
  *
988
902
  * Keep in sync with the official pricing page when deals change (see the
989
903
  * dsh-commandcode-upstream skill).
@@ -1003,24 +917,11 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
1003
917
  * charges by the hour: peak hours are 01:00–04:00 and 06:00–10:00 UTC (7h per
1004
918
  * weekday, full price) **Monday to Friday only**; the other 17 hours of a
1005
919
  * weekday and every hour of Saturday/Sunday (UTC) are off-peak at half price.
1006
- * The V4 Flash Vision (exp) variant (command-code@1.32.0) shares the V4 Flash
1007
- * rates exactly — $0.15/$0.60 off-peak and $0.30/$1.20 peak, per the page's own
1008
- * `timeOfDay` block, not merely 2× its own off-peak figures: a rate that is
1009
- * internally consistent can still be the wrong row, which is why the vendored
1010
- * price table (`./model-prices.ts`) is synced from the page and not hand-kept.
1011
- * The picker shows the
1012
- * *current* state as a compact
1013
- * label (`Peak`/`Half`) matching the English noun style of the other markers
1014
- * (`Image`, `FREE`), so a developer can tell at a glance whether calling the
1015
- * model right now is cheap or expensive.
1016
- *
1017
- * Authoritative extraction: the pricing page embeds a model JSON array whose
1018
- * hourly-priced entries carry a `timeOfDay` block
1019
- * (`{ windows: "01–04 & 06–10 UTC, Mon–Fri", peakHoursPerDay: 7,
1020
- * offPeakHoursPerDay: 17, peak: {...}, offPeak: {...} }`). Exactly four models
1021
- * carry it: V4 Pro, V4 Flash, V4 Flash Vision (exp), and V4.1 Flash (added in
1022
- * command-code@1.53.0 at $0.15/$0.60 off-peak, $0.30/$1.20 peak — the same
1023
- * 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.
1024
925
  *
1025
926
  * Extraction caution: the rendered HTML rows are a trap. Each annotation div
1026
927
  * sits inside its OWN row's container, immediately before the NEXT row starts,
@@ -1028,18 +929,19 @@ declare const KNOWN_DEALS: Readonly<Record<string, KnownDeal>>;
1028
929
  * to the model printed after it — that is how `deepseek/deepseek-v4-flash-fast`
1029
930
  * was wrongly added here (its row is flat-priced at $0.28/$0.56/$0.07 and has
1030
931
  * no `timeOfDay` block). Trust the embedded JSON's `timeOfDay` membership and
1031
- * 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.
1032
937
  *
1033
938
  * Keep in sync with the official pricing page when the model set, the peak
1034
939
  * windows, or the weekday rule change (see the dsh-commandcode-upstream skill).
1035
940
  */
1036
941
  declare const KNOWN_PEAK_PRICING: ReadonlySet<string>;
1037
942
  /**
1038
- * Whether `now` (defaults to `Date.now()`) falls in a peak-pricing window for
1039
- * time-of-day-priced models. Peak rates apply Monday–Friday (UTC) only: the
1040
- * official rule charges Saturday and Sunday completely off-peak for all 24
1041
- * hours, so a weekend timestamp is off-peak even inside `PEAK_HOUR_RANGES`.
1042
- * `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.
1043
945
  */
1044
946
  declare function peakPricingState(modelId: string, now?: number): 'peak' | 'off-peak' | undefined;
1045
947
  /**
@@ -1193,19 +1095,16 @@ interface CommandCodePriceTable {
1193
1095
  //#endregion
1194
1096
  //#region src/command-locales.d.ts
1195
1097
  /**
1196
- * Locale copy for the `/commandcode` usage command and the friendly
1197
- * image-gate error rewrite. Distinct from `./client/locales.ts` (the
1198
- * settings-page namespace `settings.commandcode`): the command runs on the
1199
- * Host and has no access to the client's `ctx.locale`, so the dictionaries
1200
- * are exposed as plain constants for direct lookup; the resolver lives in
1201
- * `pickCommandLocale()`. The image-gate wrapper also lives on the client
1202
- * but is reached from a non-React path that has no `t` in scope, so the
1203
- * 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).
1204
1103
  *
1205
- * zh is the source of truth for the key set; en must carry the exact same
1206
- * 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.
1207
1106
  */
1208
- /** Active locale id recognized by the command and the image-gate wrapper. */
1107
+ /** Active locale id for the `/commandcode` command. */
1209
1108
  type LocaleId = 'zh' | 'en';
1210
1109
  //#endregion
1211
1110
  //#region src/commands.d.ts
@@ -1220,11 +1119,9 @@ interface CommandCodeCommandDeps<C extends CommandCodeConnectionOptions = Comman
1220
1119
  */
1221
1120
  reports?: () => Promise<CommandCodeAccountsReport>;
1222
1121
  /**
1223
- * Resolve the active locale for one command run. The plugin entry wires
1224
- * this from `Config.lang` and the shell's `LC_ALL`/`LANG`. Absent in
1225
- * programmatic setups (notably the existing test), the command renders
1226
- * with the default locale (`'zh'`) — historically the only language the
1227
- * 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'`.
1228
1125
  */
1229
1126
  getLocale?: () => LocaleId;
1230
1127
  }
@@ -1286,9 +1183,9 @@ declare const loginStatusSchema: TypertSchema<CommandCodeLoginStatus>;
1286
1183
  /**
1287
1184
  * The browser-login face the usage service exposes (`commandcode/login*`).
1288
1185
  * Backed by the Host-half {@link !CommandCodeLoginFlow} when the plugin entry
1289
- * wired one; absent, `status`/`cancel` degrade to the idle status while
1290
- * `begin` rejects with a plain message (so the page's manual paste path
1291
- * 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.
1292
1189
  */
1293
1190
  interface LoginFlowFacade {
1294
1191
  /** Start (or rejoin) an attempt; rejects when it cannot start at all. */
@@ -1309,10 +1206,9 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
1309
1206
  */
1310
1207
  reports?: () => Promise<CommandCodeAccountsReport>;
1311
1208
  /**
1312
- * Model-catalog source for the settings page's model editors (the
1313
- * routing-rule editor and the visible-models filter; wired by the plugin
1314
- * entry). Absent, the `models` endpoint answers an empty list — the page's
1315
- * 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.
1316
1212
  */
1317
1213
  listModels?: () => Promise<CommandCodeCatalog>;
1318
1214
  /**
@@ -1322,11 +1218,7 @@ interface CommandCodeUsageDeps<C extends CommandCodeConnectionOptions = CommandC
1322
1218
  * only to stub it in a test.
1323
1219
  */
1324
1220
  prices?: () => CommandCodePriceTable;
1325
- /**
1326
- * The browser-login flow (wired by the plugin entry). Absent means the
1327
- * login endpoints answer `idle` / reject with a plain message — the page's
1328
- * manual paste path stays the fallback.
1329
- */
1221
+ /** The browser-login flow (wired by the plugin entry); see {@link LoginFlowFacade}. */
1330
1222
  login?: LoginFlowFacade;
1331
1223
  }
1332
1224
  /**
@@ -1340,34 +1232,30 @@ declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = C
1340
1232
  private readonly deps;
1341
1233
  constructor(ctx: Context, deps: CommandCodeUsageDeps<C>);
1342
1234
  /**
1343
- * Account, usage, and credit state for the settings page's account card —
1344
- * one entry per pool account when the plugin entry wired `reports`, a
1345
- * single default-account entry otherwise. Degrades per endpoint like the
1346
- * `/commandcode` command (failures land in `report.failures`); throws
1347
- * `MISSING_CREDENTIAL` when no key resolves, which the Gateway folds into
1348
- * 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.
1349
1239
  */
1350
1240
  report(): Promise<CommandCodeAccountsReport>;
1351
1241
  /**
1352
- * The full model catalog for the settings page's model editors (the
1353
- * routing-rule editor and the visible-models filter). The browser never
1354
- * calls the Command Code API directly — the Host serves the catalog
1355
- * (already fetched/cached by the adapter) so models can be picked from
1356
- * 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.
1357
1246
  */
1358
1247
  models(): Promise<CommandCodeCatalog>;
1359
1248
  /**
1360
1249
  * The model price table the composer prices an in-progress session with.
1361
- * Static vendored data (the official pricing page's rates), served Host-side
1362
- * so the browser bundle never carries a copy that could drift from the
1363
- * 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.
1364
1253
  */
1365
1254
  prices(): Promise<CommandCodePriceTable>;
1366
1255
  /**
1367
1256
  * Start (or rejoin) a browser-login attempt and return its fresh status —
1368
1257
  * `waiting` carrying the Studio URL. Rejects when the flow cannot start
1369
- * (no free loopback port, disposed plugin); the Gateway folds the throw
1370
- * into the failure branch the page renders.
1258
+ * (no free loopback port, disposed plugin).
1371
1259
  */
1372
1260
  loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
1373
1261
  /** Poll a login attempt's status. */
@@ -1469,16 +1357,15 @@ declare class CommandCodeLoginFlow {
1469
1357
  * asynchronously (`complete()`), and that window is open to a cancel or a
1470
1358
  * fresh `begin()`; the generation lets a late completion recognize that it
1471
1359
  * no longer owns the status face and stop instead of storing a credential
1472
- * the user cancelled and flipping the page back to success.
1360
+ * the user cancelled.
1473
1361
  */
1474
1362
  private attemptSeq;
1475
1363
  /**
1476
- * The start currently binding a port, if any. Every `begin()` that arrives
1477
- * before it settles joins it: two independent starts would each bind their
1478
- * own loopback server, and only the LAST one is reachable by
1479
- * {@link CommandCodeLoginFlow.teardown} — the orphan keeps listening and
1480
- * answering `/callback` for the process's lifetime, and ten of them exhaust
1481
- * 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.
1482
1369
  */
1483
1370
  private starting;
1484
1371
  /** A live attempt's destination; different rows may not rejoin it. */
@@ -1551,32 +1438,25 @@ declare class CommandCodeLoginFlow {
1551
1438
  declare const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
1552
1439
  /**
1553
1440
  * The factory-declared search provider id dsh ships by default (from
1554
- * `dsh-base`'s cordis patch `web.config.searchProvider`). Kept as a
1555
- * documented reference only: disabling this plugin's `webSearch` toggle
1556
- * restores the previously selected backend (see
1557
- * {@link applyCommandCodeSearchSelection}) — it never forces this default,
1558
- * because forcing it is what used to silence sibling search plugins such as
1559
- * 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).
1560
1444
  */
1561
1445
  declare const DEFAULT_WEB_SEARCH_PROVIDER_ID = "deepseek-official";
1562
1446
  /**
1563
1447
  * Tracked web-search selection state for one mounted `WebRuntime`.
1564
1448
  *
1565
- * `owner` marks whether this plugin currently owns the selection (i.e. it
1566
- * wrote `commandcode` and has not given it back yet). `displaced` is the
1567
- * backend id the plugin displaced when it took over — restored when the
1568
- * toggle turns off or the plugin unloads. `undefined` means "nothing was
1569
- * configured, leave auto-select" and must round-trip untouched: writing the
1570
- * factory default instead would still override a sibling plugin's own
1571
- * 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.
1572
1453
  *
1573
1454
  * `preexisting` is the one fact `displaced` cannot carry: an `undefined`
1574
1455
  * `displaced` means EITHER "the field was unset when we took over" (give
1575
- * `undefined` back on disable) OR "the field already read `commandcode`"
1576
- * (touch nothing on disable — see {@link applyCommandCodeSearchSelection}).
1577
- * Collapsing the two is what turned a user's own `searchProvider: commandcode`
1578
- * pin into an auto-select — and then into `WEB_PROVIDER_AMBIGUOUS` on every
1579
- * 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.
1580
1460
  */
1581
1461
  interface CommandCodeSearchSelection {
1582
1462
  owner: boolean;
@@ -1591,24 +1471,15 @@ declare function commandCodeSearchSelection(): CommandCodeSearchSelection;
1591
1471
  * providers (issue #26).
1592
1472
  *
1593
1473
  * - Enabling writes `commandcode` and remembers whatever it displaced. When
1594
- * the plugin already owns the selection (e.g. a settings save while still
1595
- * on), the original `displaced` value is kept — the field currently holds
1596
- * our own id, which must never be mistaken for the user's backend.
1597
- * - Disabling hands the selection back to the remembered backend. When the
1598
- * state holds no memory (a fresh boot straight into `webSearch: false`),
1599
- * the field is left alone: the runtime's current value — a sibling's
1600
- * cordis pin such as `searchProvider: modsearch`, or unset for
1601
- * auto-select — already says what the user wants.
1602
- * - When the field already reads `commandcode` at first touch (e.g. a
1603
- * surviving runtime the plugin did not set, or a manual
1604
- * `searchProvider: commandcode` pin), `displaced` stays undefined and
1605
- * `preexisting` is set, so the later disable is a no-op rather than a guess
1606
- * at the factory default. A "no-op" means the field is left ALONE: writing
1607
- * that `undefined` back would destroy the user's own pin, and dsh-web reads
1608
- * a cleared `searchProviderId` as auto-select — where a second usable
1609
- * provider (the shipped `deepseek-official` is usable whenever a DeepSeek
1610
- * key resolves) makes EVERY later search throw
1611
- * `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`.
1612
1483
  *
1613
1484
  * Never throws: like the low-level rewrite, a hardened runtime shape degrades
1614
1485
  * to registered-but-unselected.
@@ -1624,11 +1495,11 @@ interface CommandCodeSearchProviderDeps {
1624
1495
  fetchImpl?: typeof fetch;
1625
1496
  }
1626
1497
  /**
1627
- * A `ctx.web` search provider backed by the Command Code Provider API. Reuses
1628
- * the plugin's credential chain and `apiBase`, so search "just works" with the
1629
- * existing key — the model-facing `web_search` tool needs no separate
1630
- * configuration. Selection between multiple search providers is the web seam's
1631
- * 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).
1632
1503
  */
1633
1504
  declare class CommandCodeSearchProvider implements WebSearchProvider {
1634
1505
  private readonly deps;
@@ -1650,11 +1521,9 @@ interface TuiLocalizedText {
1650
1521
  type TuiSettingsFieldKind = 'text' | 'number' | 'boolean' | 'select';
1651
1522
  /** One choice of an options-bearing field. */
1652
1523
  interface TuiSettingsFieldOption {
1653
- /** Stored value. */
1654
1524
  readonly value: string;
1655
1525
  /** Display label (English; also the fallback). */
1656
1526
  readonly label: string;
1657
- /** Provider-owned translations for the label. */
1658
1527
  readonly descriptions?: TuiLocalizedText;
1659
1528
  }
1660
1529
  /** The write one field's draft stages when the section is saved. */
@@ -1670,11 +1539,9 @@ interface TuiSettingsField {
1670
1539
  readonly path: readonly string[];
1671
1540
  /** Short field label (English; also the fallback). */
1672
1541
  readonly label: string;
1673
- /** Provider-owned translations for the label. */
1674
1542
  readonly descriptions?: TuiLocalizedText;
1675
1543
  /** Optional one-line help rendered under the field. */
1676
1544
  readonly hint?: string;
1677
- /** Provider-owned translations for the hint. */
1678
1545
  readonly hintDescriptions?: TuiLocalizedText;
1679
1546
  /** Optional group id; grouped fields render on that group's subpage. */
1680
1547
  readonly group?: string;
@@ -1706,7 +1573,6 @@ interface TuiSettingsGroup {
1706
1573
  readonly id: string;
1707
1574
  /** Group title (English; also the fallback). */
1708
1575
  readonly title: string;
1709
- /** Provider-owned translations for the title. */
1710
1576
  readonly descriptions?: TuiLocalizedText;
1711
1577
  }
1712
1578
  /** One plugin's section inside the dsh-TUI settings screen. */
@@ -1715,7 +1581,6 @@ interface TuiSettingsSection {
1715
1581
  readonly ns: string;
1716
1582
  /** Section title (English; also the fallback). */
1717
1583
  readonly title: string;
1718
- /** Provider-owned translations for the title. */
1719
1584
  readonly descriptions?: TuiLocalizedText;
1720
1585
  /** Optional navigation groups, in display order. */
1721
1586
  readonly groups?: readonly TuiSettingsGroup[];
@@ -1783,25 +1648,22 @@ interface CommandCodeTuiSettingsDeps {
1783
1648
  * Build the section descriptor. Pure, so tests can pin the exact fields
1784
1649
  * without a dsh-TUI host.
1785
1650
  *
1786
- * Field choices worth keeping: the two option-bearing fields (`activeAccount`,
1787
- * `lang`) are `text` + `options` rather than `select`, because a `select`
1788
- * cannot express "unset" — cycling only ever lands on a declared option, so a
1789
- * `select` would strand the user on a pinned value with no way back to
1790
- * automatic. The `auto` sentinel plus a `parse` that clears the path keeps the
1791
- * unset state reachable. `filterModelsByPlan` formats its EFFECTIVE default
1792
- * (unset means true at the adapter), so a fresh install reads true instead of
1793
- * 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)".
1794
1658
  */
1795
1659
  declare function buildCommandCodeTuiSection(deps: CommandCodeTuiSettingsDeps): TuiSettingsSection;
1796
1660
  /**
1797
1661
  * Register the Command Code section on a dsh-TUI host.
1798
1662
  *
1799
- * @param ctx - the context of an activated `tuiSettingsSections` injection.
1800
- * @param deps - plugin-owned facts the section reads.
1801
1663
  * @returns a refresh function that re-registers the section when a fact it
1802
- * renders changed (the plugin entry calls it from its settings `onChange`
1803
- * hook), or `undefined` when the seam is unusable. The returned function is
1804
- * 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.
1805
1667
  */
1806
1668
  declare function applyCommandCodeTuiSettings(ctx: Context, deps: CommandCodeTuiSettingsDeps): (() => void) | undefined;
1807
1669
  //#endregion
@@ -1836,14 +1698,11 @@ interface Config {
1836
1698
  streamIdleTimeoutMs?: number;
1837
1699
  /**
1838
1700
  * Transport failures one request absorbs before the failure is surfaced;
1839
- * defaults to 5. The route's retry policy is near-unbounded on purpose (1000
1840
- * attempts, waits doubling to 15 minutes) because that shape is for the
1841
- * failures a provider asks to have retried — an exhausted rate-limit window,
1842
- * a gateway 520. A transport failure is not one of those: the first attempts
1843
- * recover an ordinary blip (the default 5 retries are scheduled 0.5/1/2/4/8 s
1844
- * after the failures before them, so ~15.5 s of grace), and after that the
1845
- * wait is pure stall, so the retries are capped here. Raise it on a genuinely
1846
- * 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.
1847
1706
  */
1848
1707
  transportMaxRetries?: number;
1849
1708
  /**
@@ -1855,8 +1714,7 @@ interface Config {
1855
1714
  filterModelsByPlan?: boolean;
1856
1715
  /**
1857
1716
  * Visible-model allowlist: catalog model ids shown in pickers. Empty or
1858
- * unset means "show everything". Persisted by the settings page's model
1859
- * filter card; applies after the subscription-tier filter.
1717
+ * unset means "show everything"; applied after the subscription-tier filter.
1860
1718
  */
1861
1719
  visibleModels?: string[];
1862
1720
  /**
@@ -1864,117 +1722,82 @@ interface Config {
1864
1722
  * list, keyed by catalog id (`true` = listed, `false` = hidden). An id here
1865
1723
  * decides that model on its own; an id absent here follows `visibleModels`.
1866
1724
  * dsh-TUI keys a staged edit by the field's path, so the checkboxes need one
1867
- * path per model — a map — because a boolean field cannot express "this id
1868
- * is a member of the array".
1725
+ * path per model — a map.
1869
1726
  */
1870
1727
  modelVisibility?: Record<string, boolean>;
1871
1728
  /**
1872
1729
  * Extra accounts for multi-account rotation. The top-level
1873
1730
  * `apiKey`/`apiKeyEnv` (plus the CLI auth file) always form the first
1874
- * (`default`) account; each entry here adds one more. When a request is
1875
- * rejected pre-stream with 429 (usage window exhausted) or 401, the next
1876
- * account's key retried transparently; when every account is exhausted the
1877
- * request fails with a `RATE_LIMIT` error naming the earliest window
1878
- * 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.
1879
1734
  */
1880
1735
  accounts?: CommandCodeAccountConfig[];
1881
1736
  /**
1882
1737
  * Manually selected active account: a slot id — `default`, or an extra
1883
- * account's credential reference (e.g. `COMMANDCODE_API_KEY_2`). The
1884
- * selected account serves whenever it is usable; an unknown id or an
1885
- * exhausted selected account falls back to the first usable slot (automatic
1886
- * 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".
1887
1741
  */
1888
1742
  activeAccount?: string;
1889
1743
  /**
1890
- * Model → account routing rules. Each rule lists catalog model ids to an
1891
- * account slot id (`default`, or an extra account's credential reference).
1892
- * When a request's model is in a rule's list and the routed account is
1893
- * usable, that account serves — before the manual {@link activeAccount} and
1894
- * the passive rotation order. A routed account that is exhausted or invalid
1895
- * falls back to the normal selection, so the router is a hint, never a hard
1896
- * 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.
1897
1748
  */
1898
1749
  modelAccountRules?: CommandCodeModelAccountRule[];
1899
1750
  /**
1900
1751
  * Whether to use Command Code as the backend for dsh's model-facing
1901
- * `web_search` tool. When enabled, the plugin registers a `commandcode`
1902
- * search provider on `ctx.web` AND selects `commandcode` in the web seam
1903
- * (so it wins over the shipped `deepseek-official` or a sibling search
1904
- * plugin's pin), using the SAME Command Code API key/base as chat. When
1905
- * disabled, the selection is handed back to whichever backend was there
1906
- * before — turning it off never forces the factory default, so a sibling
1907
- * search plugin (e.g. modsearch) keeps working (issue #26). The rewrite
1908
- * rides dsh's internal `searchProviderId`, which is read per search call,
1909
- * so a setting change lands on the next search without a restart.
1910
- * 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.
1911
1759
  */
1912
1760
  webSearch?: boolean;
1913
1761
  /**
1914
1762
  * Whether the Web sidebar shows the plans & quota card
1915
- * (`sidebar.footer.action`). Defaults to false: the card is opt-in, so an
1916
- * unset document renders no quota surface in the sidebar and mounts no
1917
- * background usage poll for it. Only the sidebar entry is affected — the
1918
- * dashboard cell behind it stays registered, it simply has no trigger until
1919
- * 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.
1920
1767
  */
1921
1768
  showSidebarQuota?: boolean;
1922
- /**
1923
- * Whether the Command Code decision model (`typesafe/jev`) may auto-approve
1924
- * shell commands that dsh was about to ask about. Defaults to FALSE: the
1925
- * guard turns a model's opinion into a one-shot approval grant, so it is
1926
- * opt-in, and the command text (plus the agent's own description of it) is
1927
- * sent to Command Code to judge. Only commands a policy already wanted a
1928
- * human to look at are ever judged, and only a confident "safe" verdict
1929
- * (`commandGuardLevel`) skips the prompt — every other outcome, including
1930
- * any failure of the decision call itself, delegates to the normal approval
1931
- * flow. See `./command-guard.ts`.
1932
- */
1933
- commandGuard?: boolean;
1934
- /**
1935
- * How confident every verdict must be before the guard skips the approval
1936
- * prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower
1937
- * level approves more, on less evidence. The decision budget is fixed
1938
- * (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.
1939
- */
1940
- commandGuardLevel?: CommandGuardLevel;
1941
1769
  /**
1942
1770
  * Whether requests enforce zero data retention: the provider then routes
1943
1771
  * them only through upstreams that keep no prompts/completions and never
1944
1772
  * train on them (its own opt-in, `CMD_ZDR=1` in the CLI / `x-cmd-zdr: 1` on
1945
1773
  * the Provider API). Defaults to FALSE: `zdr` changes WHERE a request is
1946
- * served. Every chat request carries the header when enabled; a model with
1947
- * no ZDR-capable upstream fails with 422 `cmd_zdr_no_providers` instead of
1948
- * being routed through an upstream that retains data. ZDR capacity is
1949
- * priced pass-through and usually costs more, and the price readout keeps
1950
- * quoting the ordinary catalog rates (the real per-request price shows in
1951
- * Command Code's Studio). The decision endpoint behind the command guard is
1952
- * 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).
1953
1779
  */
1954
1780
  zdr?: boolean;
1955
1781
  /**
1956
1782
  * Language override for the `/commandcode` Host-side command's user-facing
1957
- * copy. Host commands cannot read the client's `ctx.locale`, so this is
1958
- * the explicit knob: `'zh'` or `'en'`. Unset means the command reads
1959
- * `LC_ALL`/`LANG` from the launching shell, falling back to `'zh'`. The
1960
- * web settings page is unaffected — it follows the browser's language
1961
- * preference on its own. Two surfaces, two independent locales. The
1962
- * declared type is `string` (the schemastery `pattern` cannot narrow
1963
- * literal types); an unknown value is treated as "unset" by
1964
- * `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.
1965
1790
  */
1966
1791
  lang?: string;
1967
1792
  }
1968
1793
  /**
1969
1794
  * The Config schema: every field volatile except the composition-only `apiKey`
1970
- * secret.
1971
- *
1972
- * dsh 0.1.7's settings forms are projected from the schema's `meta.volatile`
1973
- * nodes, so an unmarked field would be invisible to AND unwritable from the
1974
- * settings page and refused by form-edit path validation — and the loader
1975
- * hands `apply()` a live reference per marked field, committing later writes
1976
- * without remounting this fiber (the `loader/volatile-update` listener at the
1977
- * 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.
1978
1801
  */
1979
1802
  declare const Config: z<Config>;
1980
1803
  /** One resolution's complete request facts: connection plus credential reference. */
@@ -1985,7 +1808,7 @@ interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {
1985
1808
  * The one explicit resolve step from raw config to validated connection
1986
1809
  * facts. Programmatic construction may bypass Schemastery normalization, so
1987
1810
  * every default is re-judged here — for the composition entry at load and for
1988
- * each settings snapshot at its first use.
1811
+ * every settings-backed read.
1989
1812
  */
1990
1813
  declare function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions;
1991
1814
  declare function apply(ctx: Context, config: Config): void;