@mars-sea/dsh-commandcode-provider 0.11.11 → 0.11.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +34 -31
- package/README.zh-CN.md +28 -31
- package/lib/client.js +2073 -1837
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +55 -86
- package/lib/index.js +350 -390
- package/lib/index.js.map +1 -1
- package/package.json +40 -48
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["numberField","booleanField","IDLE","record","stringField","reject","pkg.version","(pkg as { repository?: unknown }).repository","useState","useMemo","Menu","useRef","Button","HIDDEN_STYLE","useState","useRef","useState","Button","useRef"],"sources":["../src/client/snapshot-store.ts","../src/client/settings-scope.ts","../src/client/settings.ts","../src/client/legacy-credentials.ts","../src/client/usage.ts","../src/client/prices.ts","../src/client/login.ts","../src/wire-shared.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/client/login-row.tsx","../src/client/model-select.ts","../package.json","../src/client/version.ts","../src/client/update.ts","../src/client/section.tsx","../src/client/card.tsx","../src/client/panel-copy.ts","../src/client/panel.ts","../src/client/panel-view.tsx","../src/cost-facts.ts","../src/client/session-cost.ts","../src/client/session-cost-display.ts","../src/client/session-cost-view.tsx","../src/client/page-styles.ts","../src/client/panel-styles.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * A tiny observable snapshot store — the `getSnapshot` / `subscribe` / `set`\n * triple React's `useSyncExternalStore` consumes through the harness slot kit\n * (the host builds each slot's `useFoo(selector)` hook from one of these).\n *\n * Vendored on purpose. DSH 0.1.2 seeds `@deepseek-ai/dsh-client-store` as a\n * platform module, but older Web shells do not and the package is not yet\n * published independently on npm. Inlining the small subset used here avoids\n * a version-specific module request while preserving the slot-hook contract.\n */\n\n/** Mutable observable snapshot consumed by slot hooks. */\nexport interface SnapshotStore<T> {\n getSnapshot(): T\n subscribe(listener: () => void): () => void\n set(value: T): void\n}\n\n/** Notify every subscriber without letting one faulty UI consumer suppress the rest. */\nfunction notifyListeners(listeners: ReadonlySet<() => void>): void {\n for (const listener of listeners) {\n try {\n listener()\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] snapshot subscriber failed:', error)\n }\n }\n}\n\n/** Create one observable snapshot store. */\nexport function createSnapshotStore<T>(initial: T): SnapshotStore<T> {\n let snapshot = initial\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => snapshot,\n subscribe(listener: () => void) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n set(value: T) {\n if (Object.is(value, snapshot)) return\n snapshot = value\n notifyListeners(listeners)\n },\n }\n}\n","/**\n * Browser settings scope over the `remote.settings` Typert namespace.\n *\n * Until dsh 0.1.6 the web client bound `ctx.settingsScope` — a wrapper\n * `ui-settings` provided, itself derived from a shared mirror of\n * `remote.settings.describe()`. The 0.1.7 settings rewrite REMOVED that\n * wrapper service (settings became schema-derived profile Config forms), but\n * the wire underneath — `describe()`, `mutate(namespace, ops, revision)`, the\n * forwarded `settings/document-updated` invalidation, and the view shape\n * `{ writable, namespaces: [{ ns, value, base, user, revision, schema }] }` —\n * is byte-identical from 0.1.2-rc.1 through 0.1.7-alpha.1 (verified against\n * both engines' `ui-settings` bundles, which drove the SAME mirror/controller\n * pair from the first release this plugin supports to the newest).\n *\n * So this module speaks that wire directly and implements the\n * `SettingsScope<T>` face the settings-page controller already consumes —\n * one path for every supported engine, no dependency on a wrapper that only\n * half of them ship:\n *\n * - A mirror serializes `describe()` reads behind one snapshot store (a\n * read during a read marks exactly one rerun; a FAILED read keeps the\n * held view, so a transient Host error never blanks the page).\n * - The scope derives this namespace's row from the mirror — `ready` with\n * the row's value when present, `unavailable` when the namespace is not\n * in the directory — and writes through a single-flight `mutate` queue\n * fenced by the row's revision, folding each accepted answer back into\n * the mirror and re-reading after a rejected one.\n * - Persistence follows the rule both generations of `ui-settings` use: a\n * loopback page edits the Host, a remote page stays process-local\n * (`mode: 'memory'`, status `unavailable`, writes become no-ops).\n *\n * The namespace object is NOT read off the context: `remote.settings` is a\n * Cordis service nested under `remote`, and Cordis throws\n * `cannot get property \"remote.settings\" without inject` for an undeclared\n * read. It arrives through the `resolveRemote` seam instead — an object\n * captured inside `ctx.inject(['remote.settings'], …)` by the client entry\n * (see {@link SettingsRemoteResolver} for the failure this prevents).\n *\n * React-free on purpose, so `tests/settings-scope.test.ts` can drive the\n * whole lifecycle over a fake remote.\n *\n * @module dsh-commandcode-provider/client/settings-scope\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot } from './settings.ts'\nimport { createSnapshotStore, type SnapshotStore } from './snapshot-store.ts'\n\n/** Result envelope of one current Typert Remote call. */\ntype Envelope<T> = { ok: true; value: T } | { ok: false; error?: { message?: string } | undefined }\n\n/** One path-addressed form edit — the `SettingsPathOp` wire shape. */\nexport interface SettingsPathOp {\n op: 'set' | 'unset'\n path: readonly string[]\n value?: unknown\n}\n\n/** One entry's row inside a `settings.describe()` view — `SettingsNamespaceView`. */\ninterface SettingsNamespaceRow {\n ns?: unknown\n value?: unknown\n base?: unknown\n user?: unknown\n revision?: unknown\n}\n\n/** The `settings.describe()` view: the directory plus the Host's write posture. */\ninterface SettingsView {\n namespaces?: SettingsNamespaceRow[] | undefined\n writable?: boolean | undefined\n}\n\n/** The `remote.settings` namespace this scope calls. Structural: never imported. */\nexport interface SettingsRemoteNamespace {\n describe(): Promise<Envelope<SettingsView>>\n /** A write answers with the fresh ROW for its namespace, not the directory. */\n mutate(\n namespace: string,\n ops: readonly SettingsPathOp[],\n revision?: number,\n ): Promise<Envelope<SettingsNamespaceRow>>\n}\n\n/**\n * Reads the `remote.settings` namespace object, or `undefined` while it is not\n * mounted.\n *\n * This is a SEAM rather than a property on {@link SettingsScopeContext} because\n * `remote.settings` is a Cordis service nested under `remote`, and Cordis\n * throws for an undeclared nested read:\n *\n * Error: cannot get property \"remote.settings\" without inject\n *\n * The service object therefore has to be captured inside a context that\n * declares it (`ctx.inject(['remote.settings'], (settingsCtx) => …)`) and handed\n * in here. Reading it off our own `ctx.remote` instead throws on EVERY\n * supported engine — including ≤0.1.6, whose `remote.settings` namespace is the\n * same shape — and the throw lands inside this module's own `try`/`catch`, so\n * the failure is silent: no describe is ever sent, the scope keeps its initial\n * `writable: false` snapshot, and the settings page renders read-only with every\n * control disabled. That was the 0.1.7 settings-page report.\n */\nexport type SettingsRemoteResolver = () => SettingsRemoteNamespace | undefined\n\n/**\n * The client `Context` slice this module consumes, typed structurally so the\n * browser bundle never imports a version-specific module value and node tests\n * can hand in a plain object. Only `remote` itself (a declared service) is read\n * here — never `remote.<namespace>`, which requires its own inject.\n */\nexport interface SettingsScopeContext {\n remote: {\n $host?: { isLoopback?: boolean } | undefined\n $on?: ((event: string, listener: () => void) => (() => void) | undefined) | undefined\n }\n /** Connection lifecycle; older clients and tests may omit it. */\n on?: ((event: string, listener: () => void) => unknown) | undefined\n}\n\n/** Mirror snapshot: one in-flight-or-idle describe read and its held view. */\ninterface MirrorState {\n status: 'idle' | 'loading' | 'ready' | 'unavailable'\n view: SettingsView | null\n error: string | null\n}\n\nconst MEMORY_STATUS: MirrorState['status'] = 'unavailable'\n\n/**\n * Backoff before re-reading a directory whose FIRST read failed, in millis.\n *\n * A first read can lose to a Host that is still coming up (the gateway's WS\n * handshake, a settings service mid-start): the failure is transient, but the\n * scope has nothing held, so it keeps its initial `{ status: 'loading',\n * writable: false }` snapshot — and every control on the settings page renders\n * disabled behind a \"read-only\" banner. Nothing else would ever re-read it:\n * the forwarded `settings/document-updated` and `connection/reset` signals need\n * a live Host to fire, and the namespace only re-mounts on a page reload. So a\n * failure with NOTHING held retries on this bounded ladder; a failure with a\n * held view keeps it (no retry — the page is already showing the last good\n * document, and `tests/settings-scope.test.ts` pins that).\n */\nexport const SETTINGS_DESCRIBE_RETRY_MS: readonly number[] = [1000, 2000, 4000]\n\n/** Timer seam for the bounded describe retry; tests drive it without waiting. */\nexport interface SettingsRetryTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\n\n/** The production timer: a browser/node timeout, no polling. */\nconst REAL_SETTINGS_TIMER: SettingsRetryTimer = {\n set(callback, ms) {\n const handle = setTimeout(callback, ms)\n ;(handle as { unref?: () => void }).unref?.()\n return handle\n },\n clear(handle) { clearTimeout(handle as ReturnType<typeof setTimeout>) },\n}\n\n/** Shallow equality over the snapshot fields, so an unchanged derive never churns subscribers. */\nfunction sameSnapshot(a: SettingsScopeSnapshot<never>, b: SettingsScopeSnapshot<never>): boolean {\n return a.status === b.status\n && Object.is(a.value, b.value)\n && Object.is(a.base, b.base)\n && Object.is(a.user, b.user)\n && Object.is(a.revision, b.revision)\n && a.writable === b.writable\n && a.mode === b.mode\n}\n\n/** Accept a decoded row value only when it is the object a settings section is. */\nfunction decodeRow(value: unknown): Record<string, unknown> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n return value as Record<string, unknown>\n}\n\n/**\n * One shared mirror of the Host `settings.describe()` view.\n *\n * The run loop is the harness's own: serialize behind `inFlight`, fold a\n * concurrent invalidation into exactly one rerun, and hold the previous view\n * across a failed read (status stays `ready` with an `error`, or returns to\n * `idle` when nothing was ever held).\n */\nclass SettingsDescribeMirror {\n private readonly store: SnapshotStore<MirrorState>\n private readonly persistence: 'host' | 'memory'\n private inFlight: Promise<void> | undefined\n private rerun = false\n private generation = 0\n /** Pending retry handle and how many of {@link SETTINGS_DESCRIBE_RETRY_MS} are spent. */\n private retryHandle: unknown\n private retries = 0\n private disposed = false\n\n /**\n * @param resolveRemote - Reads the inject-captured `remote.settings` namespace.\n * @param persistence - Client-selected Host persistence; non-loopback pages may stay process-local.\n * @param timer - Retry timer seam (see {@link SETTINGS_DESCRIBE_RETRY_MS}).\n */\n constructor(\n private readonly resolveRemote: SettingsRemoteResolver,\n persistence: 'host' | 'memory',\n private readonly timer: SettingsRetryTimer = REAL_SETTINGS_TIMER,\n ) {\n this.persistence = persistence\n this.store = createSnapshotStore<MirrorState>({\n status: persistence === 'host' ? 'idle' : MEMORY_STATUS,\n view: null,\n error: null,\n })\n }\n\n getSnapshot(): MirrorState {\n return this.store.getSnapshot()\n }\n\n subscribe(listener: () => void): () => void {\n return this.store.subscribe(listener)\n }\n\n /** The cheap idempotent entry: kick a first read (a no-op on memory persistence). */\n ensure(): void {\n void this.load()\n }\n\n /**\n * Refresh from the Host. A call during an in-flight read marks one rerun\n * after it settles instead of racing a second wire read.\n * @returns settlement after this call's freshness is reflected.\n */\n load(): Promise<void> {\n // Memory persistence: the mirror never loads (the initial snapshot IS the\n // terminal state), matching both generations of ui-settings.\n if (this.disposed || this.persistence === 'memory') return Promise.resolve()\n // A live read supersedes a scheduled retry: the retry exists only to\n // revive a mirror that nothing else would ever re-read.\n this.clearRetry()\n if (this.inFlight !== undefined) {\n this.rerun = true\n return this.inFlight\n }\n const run = Promise.resolve().then(() => this.run())\n this.inFlight = run\n return run\n }\n\n /**\n * Fold one write answer's namespace ROW into the held view without a wire\n * read, and invalidate any read still in flight: a read begun before the\n * write committed must not publish the pre-write document over it. With no\n * held document the answer is not published as a partial document — the\n * next read (or the failed-write recovery) picks it up.\n * @param row - The namespace view a settings write answered with.\n */\n acceptView(row: SettingsNamespaceRow): void {\n const before = this.store.getSnapshot()\n this.generation += 1\n if (this.inFlight !== undefined) this.rerun = true\n if (before.view === null) return\n const held = before.view\n const namespaces = held.namespaces?.some((candidate) => candidate.ns === row.ns)\n ? held.namespaces.map((candidate) => (candidate.ns === row.ns ? row : candidate))\n : [...(held.namespaces ?? []), row]\n this.store.set({ ...before, view: { ...held, namespaces } })\n }\n\n private async run(): Promise<void> {\n try {\n for (;;) {\n const before = this.store.getSnapshot()\n if (before.status === 'idle') this.store.set({ ...before, status: 'loading' })\n this.rerun = false\n const generation = ++this.generation\n let outcome: { view: SettingsView } | { failure: string }\n try {\n const namespace = this.resolveRemote()\n if (namespace === undefined) throw new Error('the settings remote namespace is not mounted')\n const response = await namespace.describe()\n if (response.ok) {\n const value: unknown = response.value\n // The mirror holds a VIEW or nothing: an empty/malformed answer\n // must not be published as `ready` with an undefined view, or the\n // derive below would read through it. (Upstream guards the same way\n // by testing the held view for `undefined`.)\n outcome = typeof value === 'object' && value !== null\n ? { view: value as SettingsView }\n : { failure: 'settings describe answered no view' }\n } else {\n outcome = { failure: response.error?.message ?? 'settings describe failed' }\n }\n } catch (error: unknown) {\n outcome = { failure: error instanceof Error ? error.message : String(error) }\n }\n if (generation !== this.generation) continue\n if ('view' in outcome) {\n this.retries = 0\n this.store.set({ status: 'ready', view: outcome.view, error: null })\n } else {\n const held = this.store.getSnapshot()\n this.store.set({\n status: held.view === null ? 'idle' : 'ready',\n view: held.view,\n error: outcome.failure,\n })\n // Nothing was EVER held: the scope is stuck on its initial\n // `loading`/`writable: false` snapshot, which the settings page\n // renders as a fully disabled form. Retry on the bounded ladder so a\n // Host that was still starting up heals without a page reload; a\n // held view needs none (the page already shows the last good\n // document).\n if (held.view === null) this.scheduleRetry()\n }\n if (!this.rerun) break\n }\n } finally {\n this.inFlight = undefined\n }\n }\n\n /**\n * Schedule the next retry of a failed FIRST read ({@link SETTINGS_DESCRIBE_RETRY_MS}).\n * Bounded: once the ladder is spent the scope keeps its degraded snapshot,\n * exactly as before, until an invalidation or a namespace re-mount arrives.\n */\n private scheduleRetry(): void {\n if (this.disposed || this.retries >= SETTINGS_DESCRIBE_RETRY_MS.length) return\n const delay = SETTINGS_DESCRIBE_RETRY_MS[this.retries]!\n this.retries += 1\n this.retryHandle = this.timer.set(() => {\n this.retryHandle = undefined\n void this.load()\n }, delay)\n }\n\n /** Cancel a pending retry (a live read is starting, or the scope is going away). */\n private clearRetry(): void {\n if (this.retryHandle !== undefined) this.timer.clear(this.retryHandle)\n this.retryHandle = undefined\n }\n\n /** Stop the mirror: no further reads, and no retry may fire after disposal. */\n dispose(): void {\n this.disposed = true\n this.clearRetry()\n }\n}\n\n/**\n * One namespace's derived scope over the shared mirror, plus its serialized\n * Host writes. This is the face `CommandCodeSettingsController` consumes\n * (`getSnapshot` / `subscribe` / `set` / `unset`), so the controller itself\n * needs no changes for either generation.\n */\nclass RemoteSettingsScope<T> implements SettingsScope<T> {\n private readonly resolveRemote: SettingsRemoteResolver\n private readonly store: SnapshotStore<SettingsScopeSnapshot<T>>\n private readonly mirror: SettingsDescribeMirror\n private readonly namespace: string\n private readonly persistence: 'host' | 'memory'\n private tail: Promise<void> = Promise.resolve()\n private writeGeneration = 0\n private disposed = false\n private unsubscribe: (() => void) | undefined\n /** Revision answered by a superseded write still ahead of the mirror. */\n private pendingRevision: number | undefined\n\n constructor(\n resolveRemote: SettingsRemoteResolver,\n mirror: SettingsDescribeMirror,\n namespace: string,\n persistence: 'host' | 'memory',\n ) {\n this.resolveRemote = resolveRemote\n this.mirror = mirror\n this.namespace = namespace\n this.persistence = persistence\n this.store = createSnapshotStore<SettingsScopeSnapshot<T>>({\n status: persistence === 'host' ? 'loading' : 'unavailable',\n value: undefined,\n base: undefined,\n user: undefined,\n revision: undefined,\n writable: false,\n mode: persistence,\n })\n if (persistence === 'host') {\n this.unsubscribe = mirror.subscribe(() => { this.derive() })\n this.derive()\n }\n }\n\n getSnapshot(): SettingsScopeSnapshot<T> {\n return this.store.getSnapshot()\n }\n\n subscribe(listener: () => void): () => void {\n return this.store.subscribe(listener)\n }\n\n /** Queue one field write (the single-path `set` op form). */\n set(field: string, value: unknown): Promise<void> {\n return this.mutate([{ op: 'set', path: [field], value }])\n }\n\n /** Queue one field clear (the single-path `unset` op form). */\n unset(field: string): Promise<void> {\n return this.mutate([{ op: 'unset', path: [field] }])\n }\n\n /**\n * Queue one atomic namespace mutation behind the single-flight fence.\n * A rejected write (e.g. `SETTINGS_CONFLICT`) re-reads the Host so the\n * snapshot reports what actually landed; an accepted one folds its answer\n * in directly — unless a newer write already superseded it, in which case\n * that answer's revision becomes the next write's fence.\n */\n private mutate(ops: readonly SettingsPathOp[], expectedRevision?: number): Promise<void> {\n const ownedOps = structuredClone(ops)\n const generation = ++this.writeGeneration\n return this.enqueue(async () => {\n const revision = expectedRevision ?? this.pendingRevision ?? this.getSnapshot().revision\n const response = await this.mutateRemote(ownedOps, revision)\n if (!response.ok) {\n await this.recover(generation)\n return\n }\n if (this.disposed) return\n const row = response.value\n if (generation === this.writeGeneration) {\n this.pendingRevision = undefined\n this.mirror.acceptView(row)\n } else {\n this.pendingRevision = typeof row.revision === 'number' ? row.revision : undefined\n }\n })\n }\n\n private async mutateRemote(\n ops: readonly SettingsPathOp[],\n revision: number | undefined,\n ): Promise<Envelope<SettingsNamespaceRow>> {\n try {\n const namespace = this.resolveRemote()\n if (namespace === undefined) {\n return { ok: false, error: { message: 'the settings remote namespace is not mounted' } }\n }\n return await namespace.mutate(this.namespace, ops, revision)\n } catch (error: unknown) {\n return { ok: false, error: { message: error instanceof Error ? error.message : String(error) } }\n }\n }\n\n /** Reload Host state for the latest failed write; superseded failures leave recovery to it. */\n private async recover(generation: number): Promise<void> {\n if (this.disposed || generation !== this.writeGeneration) return\n this.pendingRevision = undefined\n await this.mirror.load()\n }\n\n /** Derive this namespace's snapshot from the mirror's held view. */\n private derive(): void {\n if (this.disposed) return\n const mirrored = this.mirror.getSnapshot()\n // `undefined` as well as `null`: the held view is only ever the wire's\n // answer, and a malformed one never reaches the store (see `run`).\n if (mirrored.view === null || mirrored.view === undefined) return\n const writable = mirrored.view.writable === true\n const row = mirrored.view.namespaces?.find((candidate) => candidate.ns === this.namespace)\n if (row === undefined) {\n this.publish({ status: 'unavailable', writable })\n return\n }\n const decoded = decodeRow(row.value)\n if (decoded === undefined) return\n this.publish({\n status: 'ready',\n writable,\n value: decoded as T,\n base: row.base,\n user: row.user,\n revision: typeof row.revision === 'number' ? row.revision : undefined,\n })\n }\n\n /** Publish `next` over the current snapshot, skipping the write when nothing changed. */\n private publish(next: {\n status: SettingsScopeSnapshot<T>['status']\n writable: boolean\n value?: T\n base?: unknown\n user?: unknown\n revision?: number | undefined\n }): void {\n const current = this.store.getSnapshot()\n const candidate: SettingsScopeSnapshot<T> = {\n status: next.status,\n value: 'value' in next ? next.value : current.value,\n base: 'base' in next ? next.base : current.base,\n user: 'user' in next ? next.user : current.user,\n revision: 'revision' in next ? next.revision : current.revision,\n writable: next.writable,\n mode: current.mode,\n }\n if (sameSnapshot(candidate as SettingsScopeSnapshot<never>, current as SettingsScopeSnapshot<never>)) return\n this.store.set(candidate)\n }\n\n /** Queue operations one at a time; memory persistence and disposal are no-ops. */\n private enqueue(operation: () => Promise<void>): Promise<void> {\n if (this.persistence === 'memory' || this.disposed) return Promise.resolve()\n const task = this.tail.then(async () => {\n if (this.disposed) return\n await operation()\n })\n this.tail = task.catch(() => {})\n return task\n }\n\n /** Stop queued operations, stop deriving, and wait for the current wire call to settle. */\n async dispose(): Promise<void> {\n this.disposed = true\n this.writeGeneration += 1\n this.unsubscribe?.()\n await this.tail\n }\n}\n\n/** The scope plus the handles the plugin entry wires into its fiber lifecycle. */\nexport interface ManagedSettingsScope<T> extends SettingsScope<T> {\n /** Re-read the Host — used when the `remote.settings` namespace mounts after boot. */\n refresh(): void\n /** Stop deriving, drop the forwarded-event subscriptions, and settle in-flight work. */\n dispose(): Promise<void>\n}\n\n/**\n * Build the plugin's settings scope for one namespace.\n *\n * Subscribes the two signals that can move the Host view — the forwarded\n * `settings/document-updated` invalidation and (when the client exposes it)\n * `connection/reset` — kicks the first describe read, and derives the\n * namespace row on every mirror change.\n *\n * `resolveRemote` is the INJECT-CAPTURED namespace (see\n * {@link SettingsRemoteResolver}): `remote.settings` is a Cordis service nested\n * under `remote`, so a read through our own context throws and has to be\n * replaced by an object captured inside `ctx.inject(['remote.settings'], …)`.\n * The caller that owns that inject calls {@link ManagedSettingsScope.refresh}\n * once the namespace lands, which is what turns the first, namespace-less read\n * into a served one; a profile that never mounts the namespace leaves the page\n * in its degraded (`unavailable`, read-only) state instead of throwing.\n *\n * @param context - The client context slice (only the declared `remote` service is read).\n * @param namespace - Settings namespace (profile entry id) this scope binds.\n * @param resolveRemote - Reads the inject-captured `remote.settings` namespace.\n * @returns The scope plus the refresh/dispose handles the entry wires into its fiber.\n */\nexport function createSettingsScope<T>(\n context: SettingsScopeContext,\n namespace: string,\n resolveRemote: SettingsRemoteResolver,\n timer: SettingsRetryTimer = REAL_SETTINGS_TIMER,\n): ManagedSettingsScope<T> {\n // Persistence follows ui-settings on both generations: a loopback page\n // edits the Host; a remote page stays process-local.\n const loopback = context.remote.$host?.isLoopback === true\n const persistence: 'host' | 'memory' = loopback ? 'host' : 'memory'\n const mirror = new SettingsDescribeMirror(resolveRemote, persistence, timer)\n const scope = new RemoteSettingsScope<T>(resolveRemote, mirror, namespace, persistence)\n const disposers: Array<() => void> = []\n if (loopback) {\n if (typeof context.remote.$on === 'function') {\n const off = context.remote.$on('settings/document-updated', () => { mirror.ensure() })\n if (typeof off === 'function') disposers.push(off)\n }\n if (typeof context.on === 'function') {\n const off = context.on('connection/reset', () => { void mirror.load() })\n if (typeof off === 'function') disposers.push(off as () => void)\n }\n mirror.ensure()\n }\n return {\n getSnapshot: () => scope.getSnapshot(),\n subscribe: (listener) => scope.subscribe(listener),\n set: (field, value) => scope.set(field, value),\n unset: (field) => scope.unset(field),\n refresh: () => { void mirror.load() },\n dispose: async () => {\n for (const dispose of disposers.splice(0)) dispose()\n // Before the scope: a pending describe retry would otherwise re-read a\n // directory nobody is rendering any more.\n mirror.dispose()\n await scope.dispose()\n },\n }\n}\n","/**\n * Browser controller for the \"Command Code\" settings page.\n *\n * The page lives at the same settings-nav level as General / Models / Plugins\n * (a `settings.section` entry, id `commandcode`). It exists because the\n * Models page renders an unknown-adapter-family card for the `commandcode`\n * provider and deliberately disables its submit — the API key cannot be\n * configured there. This page owns the connection facts the plugin resolves\n * per request:\n *\n * - API key -> written through the credentials domain under the reference\n * the plugin resolves (`apiKeyEnv`, default\n * `COMMANDCODE_API_KEY`). The literal never rides a response,\n * so the control only reports whether one is configured.\n * - API base -> the `llm-commandcode` settings namespace (`apiBase`), same\n * namespace the Models page card addresses.\n * - Working dir, request/stream timeouts -> the same namespace.\n *\n * The controller mirrors the plugin-card pattern from the harness's own\n * settings UI: it binds the `llm-commandcode` namespace through a\n * `SettingsScope` — this plugin's own binding of `remote.settings` (see\n * `./settings-scope.ts`; the harness's `settingsScope` wrapper existed only\n * through 0.1.6 and was removed with the 0.1.7 settings rewrite, while the\n * wire underneath spans every supported release) — keeps a staged draft of\n * edits, and writes them on save through `scope.set` / the credentials\n * domain. The Host stays the single fact source; the snapshot is republished\n * after each accepted write.\n *\n * This module is deliberately free of JSX — it only produces the state face\n * the React component renders.\n */\n\n/** The settings namespace the plugin registers (host half, src/index.ts). */\nexport const COMMANDCODE_NS = 'llm-commandcode'\n/** Default credential reference the plugin resolves when none is named. */\nexport const DEFAULT_API_KEY_REF = 'COMMANDCODE_API_KEY'\n\n/** The settings-scope snapshot fields consumed by this controller. */\nexport interface SettingsScopeSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n base: unknown\n user: unknown\n revision: number | undefined\n writable: boolean\n mode: 'host' | 'memory'\n}\n\n/** Current settings-scope service face used without importing a browser plugin value. */\nexport interface SettingsScope<T> {\n getSnapshot(): SettingsScopeSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n unset(field: string): Promise<void>\n}\n\n/** Result envelope returned by one current Typert Remote call. */\ninterface RemoteResult<T> {\n ok: boolean\n value?: T\n error?: { message: string }\n}\n\n/** Credential facts returned without exposing the credential value. */\ninterface CredentialInfo {\n configured: boolean\n writable: boolean\n}\n\n/** The narrow slice of the wire face this controller needs. */\nexport interface SettingsPageApi {\n /** Credential methods exposed by the current Typert Remote namespace. */\n credentials: {\n describe(refs: string[]): Promise<RemoteResult<Record<string, CredentialInfo>>>\n set(ref: string, value: string): Promise<RemoteResult<void>>\n unset(ref: string): Promise<RemoteResult<void>>\n }\n /**\n * The model catalog for the settings page's model editors (the\n * routing-rule editor and the visible-models filter; Host-side). Absent\n * on legacy transports without the Remote mount — the editors degrade to\n * the empty-catalog state.\n */\n models?(): Promise<RemoteResult<{ models: CatalogModelOption[] }>>\n}\n\n/** The Host-description observable the page reads the process cwd from. */\nexport interface HostDescriptionSource {\n getSnapshot(): { cwd?: string } | undefined\n subscribe(fn: () => void): () => void\n}\n\n/** One editable text field's staged state (blank = keep stored value). */\nexport interface StagedField {\n /** Live draft text the input shows. */\n text: string\n /** Whether the user explicitly cleared the field (reset to inherited). */\n clear: boolean\n /** Whether the user layer carries this field (marks it overridden). */\n overridden: boolean\n /** Whether the staged draft fails to parse (blocks save). */\n invalid: boolean\n /**\n * Why the draft is invalid — a non-number (`format`) or an out-of-range\n * number (`tooSmall`/`tooLarge`); undefined when valid.\n */\n invalidReason: InvalidReason | undefined\n}\n\n/** Why a staged draft fails validation (drives the per-field error copy). */\nexport type InvalidReason = 'format' | 'tooSmall' | 'tooLarge'\n\n/** One extra account row's staged state (the default account uses `apiKey`). */\nexport interface AccountItemState {\n /** Stable id — the account's credential reference. */\n id: string\n /** Credential reference this account's key lives under. */\n ref: string\n /** Label draft text (the stored/generated label until edited). */\n label: string\n /** The API key draft (write-only; starts blank, never echoes the stored key). */\n keyText: string\n /** Whether a key is stored for this account (Host-reported). */\n configured: boolean\n /** Whether the credentials domain can store the key. */\n writable: boolean\n /** Staged for addition (not yet saved). */\n added: boolean\n /** Staged for key removal on the next save (the stored key is bad/unwanted). */\n clearStaged: boolean\n}\n\n/** One model → account routing rule row's staged state. */\nexport interface RuleItemState {\n /** Stable row id (`rule-N` for stored rows, `new-N` for staged adds). */\n id: string\n /** Model ids the rule routes to the account (multi-select). */\n models: string[]\n /** Account slot id the rule routes matching models to. */\n account: string\n /** Staged for addition (not yet saved). */\n added: boolean\n}\n\n/** One selectable catalog model in the settings page's model editors. */\nexport interface CatalogModelOption {\n id: string\n name: string\n /**\n * Minimum plan-tier key (a Host `KNOWN_PLANS` value), or undefined for\n * models outside the snapshot / older Hosts. Drives the tier headings in\n * the editor dropdowns; absent tiers render unheaded.\n */\n tier?: string\n}\n\n/** The page's full state face, projected from the scope + drafts + credential. */\nexport interface SettingsPageState {\n /** Whether the namespace snapshot is ready. */\n available: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the API key is currently configured (Host-reported). */\n apiKeyConfigured: boolean\n /** Whether ANY account (default or extra) has a stored key — gates the usage card. */\n anyAccountConfigured: boolean\n /** Whether the credentials domain can store the key. */\n apiKeyWritable: boolean\n /** The API key draft (write-only; starts blank, never echoes the stored key). */\n apiKey: StagedField\n /** Whether the default account's stored key is staged for removal on the next save. */\n apiKeyClearStaged: boolean\n /** apiBase draft. */\n apiBase: StagedField\n /** workingDir draft. */\n workingDir: StagedField\n /**\n * The working directory a blank `workingDir` resolves to: the Host\n * process cwd (`host.describe().cwd`). Shown as the field's placeholder so\n * the user sees what \"leave it empty\" means — no configuration needed.\n */\n defaultWorkingDir: string | undefined\n /** requestTimeoutMs draft. */\n requestTimeoutMs: StagedField\n /** streamIdleTimeoutMs draft. */\n streamIdleTimeoutMs: StagedField\n /**\n * transportMaxRetries draft: how many transport failures one request absorbs\n * before the failure surfaces (issue #39's second report — the retry policy's\n * 1000-attempt, 15-minute cadence turned a 10-second TCP connect timeout into\n * an ~8-minute stall). Unset means the Host default, so it stages like the\n * timeout fields above rather than as a toggle with an implicit default.\n */\n transportMaxRetries: StagedField\n /**\n * filterModelsByPlan draft, staged as `'true'`/`'false'`/`''` (unset). The\n * component renders it as a toggle; `''` means \"inherit the default\" (on).\n */\n filterModelsByPlan: StagedField\n /**\n * webSearch draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (on — Command Code\n * serves the dsh web_search tool).\n */\n webSearch: StagedField\n /**\n * showSidebarQuota draft, staged as `'true'`/`'false'`/`''` (unset). The\n * component renders it as a toggle; `''` means \"inherit the default\" (off —\n * the sidebar quota card is opt-in, so an unset document shows nothing on\n * the left).\n */\n showSidebarQuota: StagedField\n /**\n * commandGuard draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (off — the guard\n * turns a decision model's opinion into an approval grant, so it is opt-in).\n */\n commandGuard: StagedField\n /**\n * commandGuardThreshold draft: the minimum probability of \"safe\" that skips\n * the approval prompt. Unset means the Host default (0.9), so it stages like\n * the numeric fields above.\n */\n commandGuardThreshold: StagedField\n /** commandGuardTimeoutMs draft: the decision budget in milliseconds. */\n commandGuardTimeoutMs: StagedField\n /**\n * zdr draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (off — ZDR\n * changes which upstream serves a request and usually what it costs, so it\n * is opt-in like the guard above).\n */\n zdr: StagedField\n /**\n * Whether the STORED document turns the sidebar quota card on\n * (`showSidebarQuota === true`). This is the fact the sidebar card itself\n * follows — deliberately NOT the staged draft above: the page has an explicit\n * Save, and a card that appeared from an unsaved draft would outlive a\n * discarded edit (the staging lives as long as the client does) until the\n * next page load. The stored fact flips the moment a save lands, so the card\n * still appears/disappears without a reload.\n */\n sidebarQuota: boolean\n /**\n * The manually selected active account, staged as a slot id (`default`\n * or an extra account's credential reference); `''` means \"auto — first\n * usable account\". The component renders it as a select.\n */\n activeAccount: StagedField\n /** Extra accounts (multi-account rotation), in rotation order. */\n accounts: AccountItemState[]\n /** Refs of stored accounts staged for removal (the usage card hides them). */\n accountsRemoving: string[]\n /** Model → account routing rules, in list order (first match wins). */\n rules: RuleItemState[]\n /** Effective visible-model allowlist: staged draft or stored value. Empty = show all. */\n visibleModels: string[]\n /** The catalog the model editors offer (Host-side, empty until loaded). */\n catalogModels: CatalogModelOption[]\n /** Whether the catalog fetch failed (editors fall back to typing). */\n catalogFailed: boolean\n /** Whether any staged edit differs from the stored section. */\n dirty: boolean\n /** Whether a staged numeric field fails to parse (save blocked). */\n invalid: boolean\n /** Whether a save is in flight. */\n saving: boolean\n /** Whether the last save failed (drafts retained for correction). */\n failed: boolean\n /**\n * Monotonic counter bumped once per accepted save. The component watches it\n * to flash the \"Saved ✓\" affordance (timing lives in the component; the\n * controller stays a plain state machine with no timers).\n */\n savedCount: number\n}\n\n/** Parsed outcome of one field's draft. */\ntype Parsed =\n | { kind: 'set'; value: string | number | boolean }\n | { kind: 'clear' }\n | { kind: 'invalid'; reason: InvalidReason }\n\n/** One field's staged draft (internal; the public face adds derived flags). */\ninterface Staged {\n text: string\n clear: boolean\n}\n\n/** A field conversion spec. */\ninterface FieldSpec {\n field: string\n format(value: unknown): string\n parse(text: string): Parsed\n}\n\n/** A free-text field; an empty draft clears it. */\nfunction textField(field: string): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'string' ? value : ''),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A numeric field; an empty draft clears it, anything non-numeric blocks\n * save, and an optional inclusive `bounds` range rejects out-of-range values\n * with a specific reason (the Host schema would reject them at save time with\n * only a generic failure — catching it here names the problem while typing).\n * Decimals pass: the Host schema is `z.number()` too, and a fractional\n * millisecond value is harmless even if pointless.\n */\nfunction numberField(field: string, bounds?: { min?: number; max?: number }): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'number' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return { kind: 'invalid', reason: 'format' }\n if (bounds?.min !== undefined && parsed < bounds.min) return { kind: 'invalid', reason: 'tooSmall' }\n if (bounds?.max !== undefined && parsed > bounds.max) return { kind: 'invalid', reason: 'tooLarge' }\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/**\n * A boolean field, staged as the strings `'true'`/`'false'` (an empty draft\n * clears it). The component renders a toggle and only ever stages these two\n * strings; anything else blocks save.\n */\nfunction booleanField(field: string): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'boolean' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return { kind: 'invalid', reason: 'format' }\n },\n }\n}\n\n/**\n * Inclusive bounds for the millisecond timeout fields, mirroring the Host\n * Config schema (`z.number().min(1).max(MAX_TIMER_DELAY_MS)` in src/index.ts;\n * `MAX_TIMER_DELAY_MS` is dsh-timeout's 2^31-1 timer ceiling). The client\n * bundle cannot import the node-side package, so the bound is pinned here —\n * the host remains the final gate.\n */\nexport const MIN_TIMEOUT_MS = 1\nexport const MAX_TIMEOUT_MS = 2147483647\n\n/** The fields this page edits inside the `llm-commandcode` namespace. */\nconst SECTION_FIELDS: FieldSpec[] = [\n textField('apiBase'),\n textField('workingDir'),\n numberField('requestTimeoutMs', { min: MIN_TIMEOUT_MS, max: MAX_TIMEOUT_MS }),\n numberField('streamIdleTimeoutMs', { min: MIN_TIMEOUT_MS, max: MAX_TIMEOUT_MS }),\n // A COUNT of retries, not a millisecond wait: it shares the Host schema's\n // 0..50 bounds (`MAX_TRANSPORT_MAX_RETRIES` in src/transport-retry.ts, applied\n // to `transportMaxRetries` in src/index.ts) rather than the timer ceiling\n // above, so a draft can never be saved in a shape the Host rejects. The Host\n // stays the final gate, and the client bundle cannot import that node-side\n // module — `tests/transport-retry.test.ts` pins the schema's bound against\n // the constant so this mirrored literal cannot drift unnoticed.\n numberField('transportMaxRetries', { min: 0, max: 50 }),\n booleanField('filterModelsByPlan'),\n booleanField('webSearch'),\n booleanField('showSidebarQuota'),\n booleanField('commandGuard'),\n // The bounds mirror COMMAND_GUARD_MIN/MAX_THRESHOLD and\n // COMMAND_GUARD_MIN/MAX_TIMEOUT_MS in the Host's `src/command-guard.ts`;\n // this bundle cannot import that node-side module, so the literals are\n // mirrored here like `transportMaxRetries`' own bounds, and the Host schema\n // stays the final gate.\n numberField('commandGuardThreshold', { min: 0.5, max: 1 }),\n numberField('commandGuardTimeoutMs', { min: 200, max: 10000 }),\n booleanField('zdr'),\n textField('activeAccount'),\n]\n\n/** Whether two model-id lists are equal as sets (order-insensitive). */\nfunction sameModels(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false\n const set = new Set(a)\n return b.every((id) => set.has(id))\n}\n\n/**\n * Order-sensitive content fingerprint of the stored routing rules. Stored rule\n * ids are positional (`rule-<index>`), so equality of this fingerprint across a\n * save is exactly the statement \"no rules write landed and no row shifted\".\n */\nfunction ruleFingerprint(rules: ReadonlyArray<{ models: readonly string[]; account: string }>): string {\n return JSON.stringify(rules.map((rule) => [rule.models, rule.account]))\n}\n\n/**\n * Controller bridging the `llm-commandcode` scope and the credentials domain\n * onto the page. Public API mirrors the harness's CardForm actions, so the\n * component stays thin.\n */\nexport class CommandCodeSettingsController {\n private readonly scope: SettingsScope<Record<string, unknown>>\n private readonly api: SettingsPageApi\n private readonly specs = new Map(SECTION_FIELDS.map((spec) => [spec.field, spec]))\n private readonly staged = new Map<string, Staged>()\n private readonly listeners = new Set<() => void>()\n private readonly disposers: Array<() => void> = []\n private disposed = false\n private defaultWorkingDir: string | undefined\n /** The credential reference the default account resolves. */\n private credentialRef = DEFAULT_API_KEY_REF\n /** Host-reported configured/writable state per credential reference. */\n private readonly credentialStates = new Map<string, { configured: boolean; writable: boolean }>()\n /** Staged account additions (not yet saved). */\n private addedAccounts: Array<{ label: string; ref: string }> = []\n /** Staged removals of stored extra accounts, by credential reference. */\n private readonly removedRefs = new Set<string>()\n /** Staged label drafts, by credential reference. */\n private readonly labelDrafts = new Map<string, string>()\n /** Staged key drafts, by credential reference (blank = keep stored key). */\n private readonly keyDrafts = new Map<string, string>()\n /** Credential references staged for removal on the next save. */\n private readonly keyClears = new Set<string>()\n /** Staged model→account routing rules (not yet saved). */\n private addedRules: Array<{ models: string[]; account: string }> = []\n /** Staged edits to stored routing rules, by stored row id. */\n private readonly ruleDrafts = new Map<string, { models: string[]; account: string }>()\n /**\n * Stored routing rule rows staged for removal, by stored row id with a\n * content snapshot. The snapshot makes reconcile content-based: stored\n * row ids are positional (`rule-N`) and shift after any write, so an\n * id-only check would misread a landed removal as pending (and a retry\n * would delete the wrong row).\n */\n private readonly removedRuleIds = new Map<string, { models: string[]; account: string }>()\n /**\n * Fingerprint of the stored routing rules when the last `save()` started;\n * `undefined` outside a save. Lets reconcile distinguish a landed rules\n * write from a save that failed before reaching it.\n */\n private rulesBeforeSave: string | undefined = undefined\n /** Staged visible-model allowlist (undefined = no draft). */\n private visibleModelsDraft: string[] | undefined = undefined\n /** The catalog the model editors offer (Host-side). */\n private catalogModels: CatalogModelOption[] = []\n private catalogFailed = false\n private saving = false\n private failed = false\n private savedCount = 0\n\n /**\n * @param scope - bound scope for the `llm-commandcode` namespace.\n * @param api - credentials wire face.\n * @param hostDescription - the Host-description observable whose `cwd` is\n * shown as the placeholder a blank `workingDir` field resolves to.\n */\n constructor(\n scope: SettingsScope<Record<string, unknown>>,\n api: SettingsPageApi,\n hostDescription?: HostDescriptionSource,\n ) {\n this.scope = scope\n this.api = api\n this.disposers.push(scope.subscribe(() => {\n this.recomputeCredentialRef()\n void this.describeAll()\n this.publish()\n }))\n if (hostDescription !== undefined) {\n this.defaultWorkingDir = hostDescription.getSnapshot()?.cwd\n this.disposers.push(hostDescription.subscribe(() => {\n if (this.disposed) return\n const cwd = hostDescription.getSnapshot()?.cwd\n if (cwd !== this.defaultWorkingDir) {\n this.defaultWorkingDir = cwd\n this.publish()\n }\n }))\n }\n this.recomputeCredentialRef()\n void this.describeAll()\n this.refreshCatalog()\n }\n\n /** Release every subscription held on external sources. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n for (const dispose of this.disposers) dispose()\n this.disposers.length = 0\n this.listeners.clear()\n }\n\n /**\n * The credential reference the section names, or the provider default. A\n * user who renamed `apiKeyEnv` in `settings.yaml` (or the composition\n * config) gets a page that addresses the renamed ref instead of silently\n * writing the default — mirroring the Models page's `refFor()`.\n */\n private recomputeCredentialRef(): void {\n const snapshot = this.scope.getSnapshot()\n const named = typeof snapshot.value?.apiKeyEnv === 'string' && snapshot.value.apiKeyEnv.length > 0\n ? snapshot.value.apiKeyEnv\n : DEFAULT_API_KEY_REF\n if (named === this.credentialRef) return\n // Prune the orphaned OLD ref's cached state (renames only move forward;\n // the new ref re-describes on the next describeAll).\n this.credentialStates.delete(this.credentialRef)\n this.credentialRef = named\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Build the current page state face. */\n state(): SettingsPageState {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n const credential = this.credentialStates.get(this.credentialRef)\n const accounts = this.effectiveAccounts()\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n apiKeyConfigured: credential?.configured ?? false,\n anyAccountConfigured: (credential?.configured ?? false) || accounts.some((account) => account.configured),\n apiKeyWritable: credential?.writable ?? true,\n apiKey: {\n text: this.staged.get('apiKey')?.text ?? '',\n clear: false,\n overridden: false,\n invalid: false,\n invalidReason: undefined,\n },\n apiKeyClearStaged: this.keyClears.has(this.credentialRef),\n apiBase: this.field('apiBase'),\n workingDir: this.field('workingDir'),\n defaultWorkingDir: this.defaultWorkingDir,\n requestTimeoutMs: this.field('requestTimeoutMs'),\n streamIdleTimeoutMs: this.field('streamIdleTimeoutMs'),\n transportMaxRetries: this.field('transportMaxRetries'),\n filterModelsByPlan: this.field('filterModelsByPlan'),\n webSearch: this.field('webSearch'),\n showSidebarQuota: this.field('showSidebarQuota'),\n commandGuard: this.field('commandGuard'),\n commandGuardThreshold: this.field('commandGuardThreshold'),\n commandGuardTimeoutMs: this.field('commandGuardTimeoutMs'),\n zdr: this.field('zdr'),\n sidebarQuota: this.sectionValue('showSidebarQuota') === true,\n activeAccount: this.field('activeAccount'),\n accounts,\n accountsRemoving: [...this.removedRefs],\n rules: this.effectiveRules(),\n visibleModels: this.effectiveVisibleModels(),\n catalogModels: this.catalogModels,\n catalogFailed: this.catalogFailed,\n dirty: plan.length > 0 || this.accountsDirty() || this.rulesDirty() || this.visibleModelsDirty(),\n invalid: plan.some((item) => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n savedCount: this.savedCount,\n }\n }\n\n /** Stage a new extra account (saved on the next `save()`). */\n addAccount(): void {\n const used = new Set([\n this.credentialRef,\n ...this.storedExtras().map((extra) => extra.ref),\n ...this.addedAccounts.map((extra) => extra.ref),\n ])\n // New refs derive from the current credential reference's prefix (the\n // same one `this.credentialRef` names), so a renamed apiKeyEnv yields\n // `MY_KEY_2`-style refs consistent with the default slot — never a stray\n // COMMANDCODE_API_KEY_2 that no longer matches the page's reference.\n let n = 2\n while (used.has(`${this.credentialRef}_${n}`)) n += 1\n const index = this.storedExtras().length + this.addedAccounts.length + 2\n this.addedAccounts.push({ label: `Account ${index}`, ref: `${this.credentialRef}_${n}` })\n this.failed = false\n void this.describeAll()\n this.publish()\n }\n\n /** Stage one extra account's removal (or drop an unsaved addition). */\n removeAccount(id: string): void {\n const addedIndex = this.addedAccounts.findIndex((extra) => extra.ref === id)\n if (addedIndex >= 0) this.addedAccounts.splice(addedIndex, 1)\n else this.removedRefs.add(id)\n this.labelDrafts.delete(id)\n this.keyDrafts.delete(id)\n // A pinned active account that is going away must not linger as a ghost\n // selection: stage its clear alongside the removal (the host would fall\n // back to rotation order, but the stored value would be meaningless).\n const stagedActive = this.staged.get('activeAccount')\n const activeValue = stagedActive !== undefined\n ? stagedActive.clear ? '' : stagedActive.text\n : typeof this.sectionValue('activeAccount') === 'string' ? this.sectionValue('activeAccount') as string : ''\n if (activeValue === id) {\n this.staged.set('activeAccount', { text: '', clear: true })\n }\n this.failed = false\n this.publish()\n }\n\n /** Stage one extra account's label draft. */\n editAccountLabel(id: string, text: string): void {\n this.labelDrafts.set(id, text)\n this.failed = false\n this.publish()\n }\n\n /** Stage one extra account's key draft (blank keeps the stored key). */\n editAccountKey(id: string, text: string): void {\n this.keyDrafts.set(id, text)\n // Typing a replacement cancels a staged removal — the two intents are\n // mutually exclusive (replace vs remove), and a staged clear would\n // otherwise silently discard what is being typed.\n this.keyClears.delete(id)\n this.failed = false\n this.publish()\n }\n\n /**\n * Toggle the staged removal of one account's stored key: the next save\n * unsets the credential so the account reports unconfigured and falls back\n * to its other key sources. Only meaningful while a key is actually\n * stored. `target` is `'default'` (the implicit first account) or an extra\n * account's credential reference.\n */\n toggleKeyClear(target: string): void {\n const ref = target === 'default' ? this.credentialRef : target\n if (this.keyClears.has(ref)) {\n this.keyClears.delete(ref)\n } else {\n if (this.credentialStates.get(ref)?.configured !== true) return\n // A staged replacement and a staged removal are mutually exclusive.\n this.keyDrafts.delete(ref)\n if (ref === this.credentialRef) this.staged.delete('apiKey')\n this.keyClears.add(ref)\n }\n this.failed = false\n void this.describeAll()\n this.publish()\n }\n\n /** Stage a new model → account routing rule (saved on the next `save()`). */\n addRule(): void {\n this.addedRules.push({ models: [], account: 'default' })\n this.failed = false\n this.publish()\n }\n\n /** Stage one routing rule's removal (or drop an unsaved addition). */\n removeRule(id: string): void {\n const addedIndex = this.addedRules.findIndex((_, index) => `new-${index}` === id)\n if (addedIndex >= 0) this.addedRules.splice(addedIndex, 1)\n else {\n // Snapshot the row content: stored ids are positional and shift after\n // any write, so reconcile must compare content, not ids.\n const stored = this.storedRules().find((rule) => rule.id === id)\n this.removedRuleIds.set(id, stored === undefined\n ? { models: [], account: '' }\n : { models: [...stored.models], account: stored.account })\n }\n this.ruleDrafts.delete(id)\n this.failed = false\n this.publish()\n }\n\n /** Stage one routing rule's selected model ids (multi-select). */\n editRuleModels(id: string, models: string[]): void {\n const addedIndex = this.addedRules.findIndex((_, index) => `new-${index}` === id)\n if (addedIndex >= 0) {\n this.addedRules[addedIndex] = { ...this.addedRules[addedIndex]!, models }\n } else {\n const current = this.ruleDrafts.get(id) ?? this.storedRules().find((rule) => rule.id === id) ?? { models: [], account: 'default' }\n this.ruleDrafts.set(id, { ...current, models })\n }\n this.failed = false\n this.publish()\n }\n\n /** Stage one routing rule's target account draft. */\n editRuleAccount(id: string, text: string): void {\n const addedIndex = this.addedRules.findIndex((_, index) => `new-${index}` === id)\n if (addedIndex >= 0) {\n this.addedRules[addedIndex] = { ...this.addedRules[addedIndex]!, account: text }\n } else {\n const current = this.ruleDrafts.get(id) ?? this.storedRules().find((rule) => rule.id === id) ?? { models: [], account: 'default' }\n this.ruleDrafts.set(id, { ...current, account: text })\n }\n this.failed = false\n this.publish()\n }\n\n /** Stage one field's draft text. */\n edit(field: string, text: string): void {\n this.staged.set(field, { text, clear: false })\n // Typing a replacement for the default key cancels a staged removal.\n if (field === 'apiKey') this.keyClears.delete(this.credentialRef)\n this.failed = false\n this.publish()\n }\n\n /** Reset one section field to its inherited (composition) value. */\n resetField(field: string): void {\n if (field === 'apiKey') {\n this.staged.delete('apiKey')\n this.failed = false\n this.publish()\n return\n }\n const spec = this.spec(field)\n this.staged.set(field, { text: spec.format(this.baseValue(field)), clear: true })\n this.failed = false\n this.publish()\n }\n\n /** Discard every staged edit. */\n discard(): void {\n if (this.staged.size === 0 && !this.accountsStaged() && !this.rulesStaged() && !this.visibleModelsStaged() && !this.failed) return\n this.staged.clear()\n this.clearAccountStaging()\n this.clearRuleStaging()\n this.clearVisibleModelsStaging()\n this.failed = false\n this.publish()\n }\n\n /**\n * Re-read the Host's credential facts without any staged edit. The browser\n * login stores a key Host-side behind the page's back; the plugin entry\n * calls this when a login lands so the configured/writable badges follow.\n */\n refreshCredentials(): void {\n void this.describeAll()\n }\n\n /** Write every staged edit, then re-read the Host's accepted state. */\n async save(): Promise<void> {\n const plan = this.plan()\n const accountRuns = this.accountPlan()\n const ruleRuns = this.rulesPlan()\n const visibleRuns = this.visibleModelsPlan()\n if ((plan.length === 0 && accountRuns.length === 0 && ruleRuns.length === 0 && visibleRuns.length === 0) || this.saving) return\n const runs: Array<() => Promise<boolean>> = []\n for (const item of plan) {\n if (item.run === undefined) return\n runs.push(item.run)\n }\n this.saving = true\n this.failed = false\n // Snapshot the stored routing rules before any write: reconcile needs to\n // tell \"the rules write landed (rows shifted)\" from \"the save failed\n // earlier (rows untouched)\" — see reconcileRuleStaging.\n this.rulesBeforeSave = ruleFingerprint(this.storedRules())\n this.publish()\n let landed = true\n // Keys land first so a saved accounts list never names a ref whose key\n // write failed silently; the accounts list itself writes last. Stop at\n // the first failure: running later writes after a failed one would\n // persist a partial state the staged drafts no longer describe. A\n // throwing write counts as a failure too (the scope seam may reject)\n // so the surviving staging is reconciled instead of dropped.\n for (const run of [...runs, ...accountRuns, ...ruleRuns, ...visibleRuns]) {\n let ok = false\n try {\n ok = await run()\n } catch {\n ok = false\n }\n if (!ok) {\n landed = false\n break\n }\n }\n this.saving = false\n this.failed = !landed\n if (landed) {\n this.savedCount += 1\n this.staged.clear()\n this.clearAccountStaging()\n this.clearRuleStaging()\n this.clearVisibleModelsStaging()\n } else {\n // A failed save may still have landed earlier writes (e.g. the accounts\n // list made it while a key write did not). Reconcile the staging with\n // the stored section so a landed account is not simultaneously stored\n // AND staged-for-addition (which a retry would persist twice).\n this.reconcileAccountStaging()\n this.reconcileRuleStaging()\n this.reconcileVisibleModelsStaging()\n }\n this.publish()\n }\n\n /**\n * Drop account staging the stored section already reflects: additions whose\n * ref is now stored, removals whose ref is gone, and label drafts that the\n * stored label proves landed. Key drafts are kept — a landed key write is\n * idempotent on retry, and the draft carries the user's intent when it was\n * the accounts write that failed.\n */\n private reconcileAccountStaging(): void {\n const stored = new Set(this.storedExtras().map((extra) => extra.ref))\n this.addedAccounts = this.addedAccounts.filter((extra) => !stored.has(extra.ref))\n for (const ref of [...this.removedRefs]) {\n if (!stored.has(ref)) this.removedRefs.delete(ref)\n }\n for (const [ref, text] of [...this.labelDrafts]) {\n const storedLabel = this.storedExtras().find((extra) => extra.ref === ref)?.label\n // A label draft is dropped only when the stored section proves it\n // landed. An ABSENT entry is not proof: keys land before the accounts\n // list, so a failed save routinely leaves a staged addition stored\n // nowhere — treating \"not stored\" as \"already applied\" silently threw\n // away the label the user had typed and persisted the auto-generated\n // name on the retry instead.\n if (storedLabel !== undefined && storedLabel === text.trim()) this.labelDrafts.delete(ref)\n }\n // A landed clear already did its job (the Host reports unconfigured);\n // keep only clears that failed so a retry re-attempts them.\n for (const ref of [...this.keyClears]) {\n if (this.credentialStates.get(ref)?.configured !== true) this.keyClears.delete(ref)\n }\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n private spec(field: string): FieldSpec {\n const spec = this.specs.get(field)\n if (spec === undefined) throw new Error(`commandcode settings page has no field ${field}`)\n return spec\n }\n\n /** One field's rendered state: draft text, whether it is user-overridden, invalid. */\n private field(field: string): StagedField {\n const spec = this.spec(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return {\n text: spec.format(this.sectionValue(field)),\n clear: false,\n overridden: this.stored(field),\n invalid: false,\n invalidReason: undefined,\n }\n }\n const parsed = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n clear: staged.clear,\n overridden: parsed.kind === 'set',\n invalid: parsed.kind === 'invalid',\n invalidReason: parsed.kind === 'invalid' ? parsed.reason : undefined,\n }\n }\n\n private sectionValue(field: string): unknown {\n return this.scope.getSnapshot().value?.[field]\n }\n\n private baseValue(field: string): unknown {\n const base = this.scope.getSnapshot().base\n return typeof base === 'object' && base !== null && !Array.isArray(base)\n ? (base as Record<string, unknown>)[field]\n : undefined\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n const user = this.scope.getSnapshot().user\n return typeof user === 'object' && user !== null && !Array.isArray(user)\n ? (user as Record<string, unknown>)\n : undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.prototype.hasOwnProperty.call(user, field)\n }\n\n /**\n * The writes a save would perform, in staged order. A field whose draft is\n * not a value its spec accepts carries no write (the save refuses).\n */\n private plan(): Array<{ field: string; run: (() => Promise<boolean>) | undefined }> {\n const plan: Array<{ field: string; run: (() => Promise<boolean>) | undefined }> = []\n for (const [field, staged] of this.staged) {\n if (field === 'apiKey') {\n const value = staged.text.trim()\n if (value !== '') {\n plan.push({ field, run: () => this.writeKey(value) })\n }\n continue\n }\n const spec = this.spec(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const parsed = spec.parse(staged.text)\n if (parsed.kind === 'invalid') plan.push({ field, run: undefined })\n else if (parsed.kind === 'clear') plan.push({ field, run: () => this.clear(field) })\n else plan.push({ field, run: () => this.store(field, parsed.value) })\n }\n return plan\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: string | number | boolean): Promise<boolean> {\n await this.scope.set(field, value)\n return this.userLayer()?.[field] === value\n }\n\n /** Write the staged default key, then re-read whether the Host holds it. */\n private async writeKey(value: string): Promise<boolean> {\n return this.writeKeyTo(this.credentialRef, value)\n }\n\n /** Write one account's key, then re-read the Host's credential states. */\n private async writeKeyTo(ref: string, value: string): Promise<boolean> {\n try {\n const response = await this.api.credentials.set(ref, value)\n if (!response.ok) return false\n } catch {\n return false\n }\n await this.describeAll()\n return this.credentialStates.get(ref)?.configured ?? false\n }\n\n /** Ask the credentials domain about every reference this page writes. */\n private async describeAll(): Promise<void> {\n const refs = [\n this.credentialRef,\n ...this.storedExtras().map((extra) => extra.ref),\n ...this.addedAccounts.map((extra) => extra.ref),\n ]\n let response: Awaited<ReturnType<SettingsPageApi['credentials']['describe']>>\n try {\n response = await this.api.credentials.describe(refs)\n } catch {\n return\n }\n if (!response.ok) return\n let changed = false\n for (const ref of refs) {\n const view = response.value?.[ref]\n const next = {\n configured: view?.configured ?? false,\n writable: view?.writable ?? true,\n }\n const prev = this.credentialStates.get(ref)\n if (prev === undefined || prev.configured !== next.configured || prev.writable !== next.writable) {\n this.credentialStates.set(ref, next)\n changed = true\n }\n }\n if (changed) this.publish()\n }\n\n /**\n * Fetch the model catalog for the settings page's model editors through\n * the Host Remote. Runs once at construction; call again (e.g. from the\n * client entry once the Remote mount lands) to (re)try — a later success\n * clears a prior failure flag so the editors recover without a page reload.\n */\n refreshCatalog(): void {\n const models = this.api.models\n if (models === undefined) {\n this.catalogFailed = true\n this.publish()\n return\n }\n void models().then((response) => {\n if (response.ok && Array.isArray(response.value?.models)) {\n // Defensive per-entry shaping: the Remote result is untrusted at the\n // boundary, and an older Host predates the tier field.\n const shaped: CatalogModelOption[] = []\n for (const model of response.value.models) {\n if (typeof model !== 'object' || model === null) continue\n const entry = model as unknown as Record<string, unknown>\n if (typeof entry.id !== 'string' || typeof entry.name !== 'string') continue\n shaped.push({\n id: entry.id,\n name: entry.name,\n ...(typeof entry.tier === 'string' ? { tier: entry.tier } : {}),\n })\n }\n this.catalogModels = shaped\n this.catalogFailed = false\n } else {\n this.catalogFailed = true\n }\n }, () => {\n this.catalogFailed = true\n }).then(() => this.publish())\n }\n\n // -----------------------------------------------------------------------\n // Multi-account staging\n // -----------------------------------------------------------------------\n\n /** The raw `accounts` array of the stored section, verbatim. */\n private rawStoredAccounts(): Array<Record<string, unknown>> {\n const raw = this.scope.getSnapshot().value?.accounts\n if (!Array.isArray(raw)) return []\n return raw.filter(\n (entry): entry is Record<string, unknown> =>\n typeof entry === 'object' && entry !== null && !Array.isArray(entry),\n )\n }\n\n /**\n * The stored extra accounts from the settings section (`accounts`): the rows\n * this page can address, i.e. the ones carrying a credential reference.\n *\n * Entries the page cannot name are deliberately NOT listed here but are also\n * never dropped — `writeAccounts()` rebuilds the stored list from\n * {@link rawStoredAccounts} and only rewrites the reference-carrying entries\n * it manages (see the note there), so a literal-key entry stays in the\n * document and simply has no row.\n */\n private storedExtras(): Array<{ label: string; ref: string }> {\n const out: Array<{ label: string; ref: string }> = []\n for (const record of this.rawStoredAccounts()) {\n const ref = record.apiKeyEnv\n if (typeof ref !== 'string' || ref === '') continue\n const label = record.label\n out.push({ label: typeof label === 'string' && label !== '' ? label : ref, ref })\n }\n return out\n }\n\n /** Every extra account row: stored (minus staged removals) + staged adds. */\n private effectiveAccounts(): AccountItemState[] {\n const stored = this.storedExtras()\n .filter((extra) => !this.removedRefs.has(extra.ref))\n .map((extra) => ({ ...extra, added: false }))\n const added = this.addedAccounts.map((extra) => ({ ...extra, added: true }))\n return [...stored, ...added].map((extra) => ({\n id: extra.ref,\n ref: extra.ref,\n label: this.labelDrafts.get(extra.ref) ?? extra.label,\n keyText: this.keyDrafts.get(extra.ref) ?? '',\n configured: this.credentialStates.get(extra.ref)?.configured ?? false,\n writable: this.credentialStates.get(extra.ref)?.writable ?? true,\n added: extra.added,\n clearStaged: this.keyClears.has(extra.ref),\n }))\n }\n\n /** Whether any account-level staging (add/remove/label/key/clear) exists. */\n private accountsStaged(): boolean {\n return this.addedAccounts.length > 0\n || this.removedRefs.size > 0\n || this.labelDrafts.size > 0\n || this.keyDrafts.size > 0\n || this.keyClears.size > 0\n }\n\n /** Whether the staged account edits differ from the stored section. */\n private accountsDirty(): boolean {\n if (this.addedAccounts.length > 0 || this.removedRefs.size > 0) return true\n for (const [ref, text] of this.labelDrafts) {\n const base = this.storedExtras().find((extra) => extra.ref === ref)?.label\n if (base !== undefined && text.trim() !== '' && text !== base) return true\n }\n for (const text of this.keyDrafts.values()) {\n if (text.trim() !== '') return true\n }\n // A staged clear is only meaningful while the key is actually stored —\n // staging one against an unconfigured ref is a no-op, not dirt.\n for (const ref of this.keyClears) {\n if (this.credentialStates.get(ref)?.configured === true) return true\n }\n return false\n }\n\n /** Reset every account-level staged edit. */\n private clearAccountStaging(): void {\n this.addedAccounts = []\n this.removedRefs.clear()\n this.labelDrafts.clear()\n this.keyDrafts.clear()\n this.keyClears.clear()\n }\n\n /** Unset one stored credential, then re-read the Host's credential states. */\n private async unsetKey(ref: string): Promise<boolean> {\n try {\n const response = await this.api.credentials.unset(ref)\n if (!response.ok) return false\n } catch {\n return false\n }\n await this.describeAll()\n return this.credentialStates.get(ref)?.configured !== true\n }\n\n /** The account-level writes a save performs (empty when nothing staged). */\n private accountPlan(): Array<() => Promise<boolean>> {\n if (!this.accountsDirty()) return []\n const runs: Array<() => Promise<boolean>> = []\n // Staged removals land first: a cleared credential must be gone before\n // the accounts list write, or a removed row would leave an orphaned\n // secret behind. Removed rows keep their clear (clean removal).\n for (const ref of this.keyClears) {\n if (this.credentialStates.get(ref)?.configured === true) {\n runs.push(() => this.unsetKey(ref))\n }\n }\n for (const [ref, text] of this.keyDrafts) {\n const value = text.trim()\n if (value !== '' && !this.removedRefs.has(ref) && !this.keyClears.has(ref)) {\n runs.push(() => this.writeKeyTo(ref, value))\n }\n }\n runs.push(() => this.writeAccounts())\n return runs\n }\n\n /**\n * Persist the staged accounts list into the settings section.\n *\n * The stored list is the base — NOT a list rebuilt from this page's rows.\n * A composition-config entry may carry a literal `apiKey` (or a shape this\n * page does not know), and the settings layer replaces the whole array, so a\n * rebuilt list would silently delete every entry the page cannot name along\n * with the literal keys of the entries it can. Entries are therefore carried\n * over verbatim and only the reference-carrying rows are rewritten (label\n * draft applied, staged removals dropped, staged additions appended).\n */\n private async writeAccounts(): Promise<boolean> {\n const removed = this.removedRefs\n const written = new Set<string>()\n const list: Array<Record<string, unknown>> = []\n for (const entry of this.rawStoredAccounts()) {\n const ref = entry.apiKeyEnv\n // Not a row this page manages (literal-key or unknown entry): preserve\n // it exactly as stored rather than dropping it with the rewrite.\n if (typeof ref !== 'string' || ref === '') {\n list.push({ ...entry })\n continue\n }\n if (removed.has(ref) || written.has(ref)) continue\n written.add(ref)\n list.push(this.accountEntry(ref, entry))\n }\n // Defensive dedupe by ref: a partially landed earlier save can leave an\n // account both stored and staged-for-addition; never persist duplicates.\n // A staged addition whose ref is already stored is skipped too — the\n // stored entry (with any literal key or unknown field) wins.\n for (const extra of this.addedAccounts) {\n if (written.has(extra.ref)) continue\n written.add(extra.ref)\n list.push(this.accountEntry(extra.ref, extra))\n }\n await this.scope.set('accounts', list)\n // Verify against the same raw entries the write was built from: the\n // page's row view ignores reference-less entries, so comparing it to\n // `list` would report a false failure whenever one is present.\n const after = this.rawStoredAccounts()\n return after.length === list.length\n && list.every((item, index) => after[index]?.apiKeyEnv === item.apiKeyEnv)\n }\n\n /**\n * One written account entry: the stored/added facts plus the label draft.\n * `fallback` contributes the non-managed fields (a stored entry's literal\n * `apiKey`, or any future field) so a rewrite never strips them.\n */\n private accountEntry(\n ref: string,\n fallback: { label: string } | Record<string, unknown>,\n ): Record<string, unknown> {\n const draft = this.labelDrafts.get(ref)?.trim()\n const base = 'ref' in fallback\n ? { label: (fallback as { label: string }).label }\n : { ...(fallback as Record<string, unknown>) }\n const storedLabel = base.label\n return {\n ...base,\n label: draft !== undefined && draft !== ''\n ? draft\n : typeof storedLabel === 'string' && storedLabel !== '' ? storedLabel : ref,\n apiKeyEnv: ref,\n }\n }\n\n // -----------------------------------------------------------------------\n // Model → account routing-rule staging\n // -----------------------------------------------------------------------\n\n /** The stored routing rules from the settings section (`modelAccountRules`). */\n private storedRules(): Array<{ id: string; models: string[]; account: string }> {\n const raw = this.scope.getSnapshot().value?.modelAccountRules\n if (!Array.isArray(raw)) return []\n const out: Array<{ id: string; models: string[]; account: string }> = []\n for (const [index, entry] of raw.entries()) {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) continue\n const record = entry as Record<string, unknown>\n const models = record.models\n const account = record.account\n const modelsList = Array.isArray(models) && models.every((m) => typeof m === 'string')\n ? (models as string[]).filter((m) => m !== '')\n : []\n if (modelsList.length === 0) continue\n out.push({\n id: `rule-${index}`,\n models: modelsList,\n account: typeof account === 'string' && account !== '' ? account : 'default',\n })\n }\n return out\n }\n\n /** Every routing rule row: stored (minus staged removals, with drafts) + staged adds. */\n private effectiveRules(): RuleItemState[] {\n const stored = this.storedRules()\n .filter((rule) => !this.removedRuleIds.has(rule.id))\n .map((rule) => {\n const draft = this.ruleDrafts.get(rule.id)\n return {\n id: rule.id,\n models: draft?.models ?? rule.models,\n account: draft?.account ?? rule.account,\n added: false,\n }\n })\n const added = this.addedRules.map((rule, index) => ({\n id: `new-${index}`,\n models: rule.models,\n account: rule.account,\n added: true,\n }))\n return [...stored, ...added]\n }\n\n /** Whether any routing-rule staging (add/remove/edit) exists. */\n private rulesStaged(): boolean {\n return this.addedRules.length > 0 || this.removedRuleIds.size > 0 || this.ruleDrafts.size > 0\n }\n\n /** Whether the staged routing rules differ from the stored section. */\n private rulesDirty(): boolean {\n if (this.addedRules.length > 0 || this.removedRuleIds.size > 0) return true\n for (const [id, draft] of this.ruleDrafts) {\n const base = this.storedRules().find((rule) => rule.id === id)\n if (base === undefined) continue\n if (draft.models.length > 0 && !sameModels(draft.models, base.models)) return true\n if (draft.account !== base.account) return true\n }\n return false\n }\n\n /** Reset every routing-rule staged edit. */\n private clearRuleStaging(): void {\n this.addedRules = []\n this.ruleDrafts.clear()\n this.removedRuleIds.clear()\n }\n\n /**\n * Drop rule staging the stored section already reflects (partial-save\n * retry). Stored row ids are positional (`rule-N`) and shift after any\n * write, so every check here is content-based, never id-based:\n * - landed additions (in `addedRules`, already in stored) are dropped, or\n * a retry would persist them twice;\n * - staged removals whose snapshot row is gone from stored have landed\n * (drop them); a removal whose snapshot still matches a stored row is\n * still pending (keep it).\n */\n private reconcileRuleStaging(): void {\n const stored = this.storedRules()\n this.addedRules = this.addedRules.filter((added) =>\n !stored.some((rule) =>\n sameModels(added.models, rule.models) && added.account === rule.account))\n for (const [id, snapshot] of [...this.removedRuleIds]) {\n const landed = !stored.some((rule) =>\n sameModels(snapshot.models, rule.models) && snapshot.account === rule.account)\n if (landed) this.removedRuleIds.delete(id)\n }\n // Drafts are keyed by positional stored ids, so they survive a failed save\n // exactly as long as the stored list did not change: writes run in order\n // and stop at the first failure, so a failure BEFORE the rules write leaves\n // the stored rows (and their ids) untouched and the drafts still describe\n // them — clearing here would silently revert the user's edit and leave\n // `dirty` false, i.e. nothing to retry. Only a save that actually landed\n // the rules write shifts every positional id, which makes a draft\n // unattributable; matching shifted rows by content would misattribute\n // edits, so those drafts are dropped and the user re-applies the edit.\n if (this.rulesBeforeSave !== undefined && ruleFingerprint(stored) === this.rulesBeforeSave) return\n this.ruleDrafts.clear()\n }\n\n /** The stored visible-model allowlist (`visibleModels`); empty = show all. */\n private storedVisibleModels(): string[] {\n const raw = this.scope.getSnapshot().value?.visibleModels\n if (!Array.isArray(raw)) return []\n return raw.filter((m): m is string => typeof m === 'string' && m !== '')\n }\n\n /** Effective visible-model allowlist: staged draft or stored value. */\n private effectiveVisibleModels(): string[] {\n return this.visibleModelsDraft ?? this.storedVisibleModels()\n }\n\n /** Whether the staged visible-model selection differs from stored. */\n private visibleModelsDirty(): boolean {\n return this.visibleModelsDraft !== undefined\n && !sameModels(this.visibleModelsDraft, this.storedVisibleModels())\n }\n\n /** Whether any visible-model staging exists. */\n private visibleModelsStaged(): boolean {\n return this.visibleModelsDraft !== undefined\n }\n\n /** Reset the visible-model staged edit. */\n private clearVisibleModelsStaging(): void {\n this.visibleModelsDraft = undefined\n }\n\n /** Drop visible-model staging the stored section already reflects. */\n private reconcileVisibleModelsStaging(): void {\n if (this.visibleModelsDraft !== undefined\n && sameModels(this.visibleModelsDraft, this.storedVisibleModels())) {\n this.visibleModelsDraft = undefined\n }\n }\n\n /** The visible-model writes a save performs (empty when nothing staged). */\n private visibleModelsPlan(): Array<() => Promise<boolean>> {\n if (!this.visibleModelsDirty()) return []\n return [() => this.writeVisibleModels()]\n }\n\n /** Persist the staged visible-model allowlist into the settings section. */\n private async writeVisibleModels(): Promise<boolean> {\n const list = this.visibleModelsDraft ?? []\n await this.scope.set('visibleModels', list)\n return sameModels(this.storedVisibleModels(), list)\n }\n\n /** Stage the visible-model allowlist (multi-select). */\n editVisibleModels(models: string[]): void {\n this.visibleModelsDraft = [...models]\n this.failed = false\n this.publish()\n }\n\n /** Stage \"show all models\" (clears the allowlist). */\n clearVisibleModels(): void {\n this.visibleModelsDraft = []\n this.failed = false\n this.publish()\n }\n\n /** The routing-rule writes a save performs (empty when nothing staged). */\n private rulesPlan(): Array<() => Promise<boolean>> {\n if (!this.rulesDirty()) return []\n return [() => this.writeRules()]\n }\n\n /** Persist the staged routing rules into the settings section. */\n private async writeRules(): Promise<boolean> {\n const base = this.storedRules().filter((rule) => {\n const snapshot = this.removedRuleIds.get(rule.id)\n // Content-based removal: positional ids shift after any write, so a\n // staged removal only filters the row it snapshotted.\n return snapshot === undefined\n || !sameModels(snapshot.models, rule.models)\n || snapshot.account !== rule.account\n })\n const list = [\n ...base.map((rule) => {\n const draft = this.ruleDrafts.get(rule.id)\n return {\n models: draft !== undefined && draft.models.length > 0 ? draft.models : rule.models,\n account: draft?.account !== undefined && draft.account !== '' ? draft.account : rule.account,\n }\n }),\n ...this.addedRules.map((rule) => ({\n models: rule.models,\n account: rule.account,\n })),\n ].filter((rule) => rule.models.length > 0)\n // Defensive dedupe by content: a partially landed earlier save can leave\n // a rule both stored and staged-for-addition; never persist duplicates.\n const seen = new Set<string>()\n const deduped = list.filter((rule) => {\n const key = `${rule.account}\\u0001${[...rule.models].sort().join('\\u0001')}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n await this.scope.set('modelAccountRules', deduped)\n const after = this.storedRules()\n return after.length === deduped.length\n && deduped.every((item, index) =>\n after[index] !== undefined\n && sameModels(after[index].models, item.models)\n && after[index].account === item.account)\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of this.listeners) listener()\n }\n}\n","/** Legacy ApiProxy credentials adapter for pre-0.1.2 DSH clients. */\n\nimport type { SettingsPageApi } from './settings.ts'\n\ninterface LegacyFailure {\n message: string\n}\n\ninterface LegacyResponse<T> {\n result:\n | { ok: true; value: T }\n | { ok: false; error: LegacyFailure }\n}\n\n/** The pre-0.1.2 `connection.api.credentials` face. */\nexport interface LegacyCredentialsApi {\n describe(request: { refs: string[] }): Promise<LegacyResponse<{\n credentials: Record<string, { configured: boolean; writable: boolean }>\n }>>\n set(request: { ref: string; value: string }): Promise<LegacyResponse<unknown>>\n unset(request: { ref: string }): Promise<LegacyResponse<unknown>>\n}\n\n/** Convert a legacy credentials ApiProxy into the current settings-page face. */\nexport function adaptLegacyCredentials(\n legacy: LegacyCredentialsApi | undefined,\n): SettingsPageApi | undefined {\n if (legacy === undefined) return undefined\n return {\n credentials: {\n describe: async (refs) => {\n const response = await legacy.describe({ refs })\n return response.result.ok\n ? { ok: true, value: response.result.value.credentials }\n : { ok: false, error: response.result.error }\n },\n set: async (ref, value) => {\n const response = await legacy.set({ ref, value })\n return response.result.ok\n ? { ok: true, value: undefined }\n : { ok: false, error: response.result.error }\n },\n unset: async (ref) => {\n const response = await legacy.unset({ ref })\n return response.result.ok\n ? { ok: true, value: undefined }\n : { ok: false, error: response.result.error }\n },\n },\n }\n}\n","/**\n * Browser controller for the settings page's account-usage card.\n *\n * The card renders the same account/usage/credit facts the `/commandcode`\n * command prints, fetched Host-side through the `commandcode/report` Remote\n * (the browser never holds the API key). This controller owns the fetch\n * lifecycle — idle/loading/ready/error, one in-flight request at a time,\n * stale-response dropping — and the display formatting, so the React\n * component stays a thin renderer and node tests can drive everything.\n *\n * Deliberately JSX-free, mirroring `./settings.ts`.\n *\n * @module dsh-commandcode-provider/client/usage\n */\n\nimport type { CommandCodeAccountsReport, CommandCodeCatalog, CommandCodePriceTable } from '../usage-wire.ts'\nimport type { CommandCodeLoginStatus } from '../login-wire.ts'\nimport type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'\n\n/**\n * Merge the plugin's Remote endpoints into the harness's typed client Remote\n * surface (the same declaration pattern the harness's generated\n * typert.remote-client files use), so `ctx.remote.commandcode.*()` is typed\n * once each contribution is mounted. The `commandcode` namespace member is\n * declared exactly once (interface merging forbids duplicate members), so\n * this one declaration carries the usage report, the model catalog, the price\n * table, AND the login endpoints — the endpoint-level declarations live beside\n * their controllers.\n */\ndeclare module '@deepseek-ai/dsh-typert-protocol' {\n interface TypertRemoteMap {\n 'commandcode/report': () => Promise<RemoteResult<CommandCodeAccountsReport>>\n 'commandcode/models': () => Promise<RemoteResult<CommandCodeCatalog>>\n 'commandcode/prices': () => Promise<RemoteResult<CommandCodePriceTable>>\n }\n interface TypertRemoteNamespaceMap {\n commandcode: {\n report: () => Promise<RemoteResult<CommandCodeAccountsReport>>\n models: () => Promise<RemoteResult<CommandCodeCatalog>>\n /**\n * Optional because the Host half and this browser bundle can be a\n * cross-version pair: a Host older than the price table mounts no\n * `commandcode/prices` descriptor, so the member is genuinely absent at\n * runtime. The price controller reads a missing method as \"no table\"\n * (see `./prices.ts`) instead of throwing.\n */\n prices?: () => Promise<RemoteResult<CommandCodePriceTable>>\n loginBegin: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n loginStatus: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n loginCancel: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n }\n }\n}\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface UsageRemote {\n report(): Promise<\n | { ok: true; value: CommandCodeAccountsReport }\n | { ok: false; error: { message: string } }\n >\n models(): Promise<\n | { ok: true; value: CommandCodeCatalog }\n | { ok: false; error: { message: string } }\n >\n /**\n * Optional for the same cross-version reason as the namespace member above:\n * an older Host serves no price table. `CommandCodePricesController` reads\n * the absence as a permanent \"no prices\" state.\n */\n prices?(): Promise<\n | { ok: true; value: CommandCodePriceTable }\n | { ok: false; error: { message: string } }\n >\n}\n\n/** The card's fetch lifecycle. */\nexport type UsageStatus =\n /** Never fetched (no API key configured yet, or not requested). */\n | 'idle'\n /** A fetch is in flight; `report` retains the last good data if any. */\n | 'loading'\n /** The last fetch succeeded. */\n | 'ready'\n /** The last fetch failed (no key, unreachable host, old plugin). */\n | 'error'\n\n/** The card's full state face. */\nexport interface UsagePageState {\n status: UsageStatus\n /** The last successfully fetched report (retained across refetches). */\n report: CommandCodeAccountsReport | undefined\n /** The last failure's message (error status). */\n error: string | undefined\n /** Millis timestamp of the last successful fetch. */\n fetchedAt: number | undefined\n}\n\nconst IDLE: UsagePageState = { status: 'idle', report: undefined, error: undefined, fetchedAt: undefined }\n\n/**\n * Controller bridging the `commandcode/report` Remote onto the card. Public\n * API mirrors {@link CommandCodeSettingsController}: `state()` projections,\n * `subscribe`, and one `refresh()` action.\n */\nexport class CommandCodeUsageController {\n private readonly remote: UsageRemote\n private readonly listeners = new Set<() => void>()\n private current: UsagePageState = IDLE\n private generation = 0\n private inFlight = false\n private disposed = false\n\n constructor(remote: UsageRemote) {\n this.remote = remote\n }\n\n /** Release every subscription. Idempotent; in-flight results are dropped. */\n dispose(): void {\n this.disposed = true\n this.generation += 1\n this.listeners.clear()\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current card state face. */\n state(): UsagePageState {\n return this.current\n }\n\n /**\n * Fetch (or refetch) the report. Concurrent refreshes collapse onto one\n * request; a superseded fetch's late result is dropped, never published.\n */\n async refresh(): Promise<void> {\n if (this.disposed || this.inFlight) return\n const generation = ++this.generation\n this.inFlight = true\n this.current = { ...this.current, status: 'loading', error: undefined }\n this.publish()\n try {\n const response = await this.remote.report()\n if (this.disposed || generation !== this.generation) return\n if (response.ok) {\n this.current = { status: 'ready', report: response.value, error: undefined, fetchedAt: Date.now() }\n } else {\n this.current = { ...this.current, status: 'error', error: response.error.message }\n }\n } catch (error: unknown) {\n if (this.disposed || generation !== this.generation) return\n this.current = {\n ...this.current,\n status: 'error',\n error: error instanceof Error ? error.message : String(error),\n }\n } finally {\n if (generation === this.generation) this.inFlight = false\n }\n this.publish()\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of this.listeners) listener()\n }\n}\n\n// ---------------------------------------------------------------------------\n// Display formatting (shared by the component, covered by node tests)\n// ---------------------------------------------------------------------------\n\n/** Format a dollar amount compactly (2 decimals). */\nexport function formatMoney(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\n/** Format a dollar amount precisely (4 decimals) for small totals. */\nexport function formatMoneyExact(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\n/** Format a large token count compactly (1.9M style). */\nexport function formatTokensCompact(value: number): string {\n if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`\n if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`\n if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`\n return String(value)\n}\n\n/**\n * Format a success-rate percentage (already in percent units, e.g. 99.96):\n * at most two decimals, trailing zeros trimmed — `100` stays `100`, not\n * `100.00`, and the raw upstream float `99.965552876334` becomes `99.97`.\n * The `%` suffix is appended by the caller (the card and the dashboard line\n * both compose it).\n */\nexport function formatSuccessRate(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** One window's fill ratio in [0, 1]; 0 when uncapped. */\nexport function windowRatio(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.max(0, Math.min(1, used / cap))\n}\n\n/** Format a millis timestamp as a local short date-time; empty when unset. */\nexport function formatResetAt(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleString()\n}\n\n/** Host facts drive the usage card, including keys invisible to browser credentials. */\nexport function usageCardState(usage: UsagePageState) {\n const accounts = usage.report?.accounts ?? []\n return {\n loading: usage.status === 'loading',\n shouldRefresh: usage.status === 'idle',\n noKey: accounts.length > 0 && !accounts.some(account => account.configured),\n }\n}\n","/**\n * Browser controller for the model price table the composer's session-cost\n * figure depends on.\n *\n * The rates are vendored Host-side (`src/model-prices.ts`) and cross the\n * `commandcode/prices` Remote, so the browser never carries its own copy that\n * could drift from the snapshot, and a price update reaches an open page\n * without rebuilding the client bundle.\n *\n * Successful reads are cached until the Host namespace rebinds. Transient\n * failures retry three times with bounded backoff; manual refresh can retry\n * after that. Rebinding drops stale in-flight results and resets the budget.\n * Missing endpoints are permanent until the namespace changes.\n *\n * Deliberately JSX-free, mirroring `./usage.ts`.\n *\n * @module dsh-commandcode-provider/client/prices\n */\n\nimport type { CommandCodePriceTable } from '../usage-wire.ts'\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface PricesRemote {\n /**\n * Optional because the Host and the browser bundle can be a cross-version\n * pair: a Host half older than this feature serves no `commandcode/prices`\n * endpoint, and the controller must read that as \"no price table\" instead of\n * calling an undefined method.\n */\n prices?(): Promise<\n | { ok: true; value: CommandCodePriceTable }\n | { ok: false; error: { message: string; permanent?: boolean } }\n >\n}\n\n/** The price table's fetch lifecycle. */\nexport type PricesStatus =\n /** Never requested. */\n | 'idle'\n /** A fetch is in flight. */\n | 'loading'\n /** The table is loaded and cached for the page's lifetime. */\n | 'ready'\n /** The last fetch failed; `ensure()` may try again. */\n | 'error'\n\n/** The readout's price-table state face. */\nexport interface SessionCostPricesState {\n status: PricesStatus\n /** The cached table (only ever set once). */\n table: CommandCodePriceTable | undefined\n /** The last failure's message. */\n error: string | undefined\n}\n\nconst IDLE: SessionCostPricesState = { status: 'idle', table: undefined, error: undefined }\n\n/**\n * Timer seam for the bounded retry backoff, so a node test can drive the\n * schedule without waiting on it.\n */\nexport interface PriceRetryTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\nconst RETRY_TIMER: PriceRetryTimer = {\n set(callback, ms) { const handle = setTimeout(callback, ms); handle.unref?.(); return handle },\n clear(handle) { clearTimeout(handle as ReturnType<typeof setTimeout>) },\n}\n\n/**\n * Cache over the `commandcode/prices` Remote, with a bounded transient-retry\n * budget. Public API mirrors {@link CommandCodeUsageController}: `state()`,\n * `subscribe`, and `ensure()`; `reload()` additionally drops the cache and\n * restarts the budget when the Host namespace rebinds.\n *\n * Not a one-shot: the last fetch is cached until `reload()`, a transient\n * failure is retried three times at 1/2/4 s (the delays are bounded, not a\n * poll), and a MANUAL `ensure()` still fetches after that budget is spent. A\n * PERMANENT failure — the Host serving no such endpoint — is terminal for the\n * binding and is only cleared by `reload()`.\n */\nexport class CommandCodePricesController {\n private readonly remote: PricesRemote\n private readonly listeners = new Set<() => void>()\n private current: SessionCostPricesState = IDLE\n private generation = 0\n private inFlight = false\n private disposed = false\n\n private retryHandle: unknown\n private attempts = 0\n private permanent = false\n private readonly timer: PriceRetryTimer\n\n constructor(remote: PricesRemote, timer: PriceRetryTimer = RETRY_TIMER) {\n this.timer = timer\n this.remote = remote\n }\n\n /** Release every subscription. Idempotent; in-flight results are dropped. */\n dispose(): void {\n this.disposed = true\n this.clearRetry()\n this.listeners.clear()\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current state face. */\n state(): SessionCostPricesState {\n return this.current\n }\n\n /**\n * Fetch the table unless it is already loaded, permanent, or in flight — and\n * unless a bounded retry already owns the next attempt.\n *\n * The only callers are the client entry: `reload()` when the Remote namespace\n * lands or rebinds, and a manual refresh. Nothing in the composer calls it, so\n * a mounted readout does not trigger a fetch of its own — it renders whatever\n * the table's state currently is.\n */\n ensure(): void {\n if (this.disposed || this.permanent || this.inFlight || this.current.status === 'ready') return\n this.clearRetry()\n const call = this.remote.prices\n // An older Host half serves no price endpoint. That is a permanent\n // condition for this page, so it lands in the error state (the readout\n // stays hidden) rather than retrying on every mount.\n if (typeof call !== 'function') {\n this.permanent = true\n this.publish({ status: 'error', table: undefined, error: 'the Host serves no commandcode/prices endpoint' })\n return\n }\n const generation = this.generation\n this.inFlight = true\n this.attempts += 1\n this.publish({ status: 'loading', table: this.current.table, error: undefined })\n let request: ReturnType<NonNullable<PricesRemote['prices']>>\n try { request = call.call(this.remote) } catch (error) { request = Promise.reject(error) }\n void request.then((result) => {\n if (this.disposed || generation !== this.generation) return\n this.inFlight = false\n if (result.ok) {\n this.publish({ status: 'ready', table: result.value, error: undefined })\n return\n }\n this.permanent = result.error.permanent === true\n this.publish({ status: 'error', table: undefined, error: result.error.message })\n this.scheduleRetry()\n }, (error: unknown) => {\n if (this.disposed || generation !== this.generation) return\n this.inFlight = false\n this.publish({\n status: 'error',\n table: undefined,\n error: error instanceof Error ? error.message : String(error),\n })\n this.scheduleRetry()\n })\n }\n\n /** Rebinding a Host invalidates cached prices and restarts the bounded retry budget. */\n reload(): void {\n if (this.disposed) return\n this.generation += 1\n this.inFlight = false\n this.clearRetry()\n this.permanent = false\n this.attempts = 0\n this.current = IDLE\n this.ensure()\n }\n\n private clearRetry(): void {\n if (this.retryHandle !== undefined) this.timer.clear(this.retryHandle)\n this.retryHandle = undefined\n }\n\n private scheduleRetry(): void {\n if (this.disposed || this.permanent || this.attempts >= 4) return\n this.retryHandle = this.timer.set(() => { this.retryHandle = undefined; this.ensure() }, 1000 * 2 ** (this.attempts - 1))\n }\n\n private publish(next: SessionCostPricesState): void {\n this.current = next\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * Browser controller for the settings page's login panel.\n *\n * The panel drives the Host-half browser login (the official\n * `command-code login` loopback dance) through the Typert Gateway: `begin`\n * asks the Host to bind the callback server and returns the Studio URL, the\n * controller polls `loginStatus` once a second while the attempt is live, and\n * `cancel` tears it down. The key itself never crosses to the browser — the\n * Host validates and stores it through the credentials seam.\n *\n * Transport-level failures (no mounted Remote, an older Host without the\n * login endpoints) land in the dedicated `unavailable` phase so the page can\n * point back at manual paste. Deliberately JSX-free, mirroring\n * `./settings.ts` and `./usage.ts`.\n *\n * @module dsh-commandcode-provider/client/login\n */\n\nimport type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'\nimport type { CommandCodeLoginFailureReason, CommandCodeLoginStatus } from '../login-wire.ts'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\n\n/** The endpoint-level Remote surface this controller calls. */\ndeclare module '@deepseek-ai/dsh-typert-protocol' {\n interface TypertRemoteMap {\n 'commandcode/loginBegin': (targetRef?: string) => Promise<RemoteResult<CommandCodeLoginStatus>>\n 'commandcode/loginStatus': () => Promise<RemoteResult<CommandCodeLoginStatus>>\n 'commandcode/loginCancel': () => Promise<RemoteResult<CommandCodeLoginStatus>>\n }\n}\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface LoginRemote {\n loginBegin(targetRef?: string): Promise<LoginCallResult>\n loginStatus(): Promise<LoginCallResult>\n loginCancel(): Promise<LoginCallResult>\n}\n\n/** One Remote call's outcome as the controller sees it. */\nexport type LoginCallResult =\n | { ok: true; value: CommandCodeLoginStatus }\n | { ok: false; error: { message: string } }\n\n/** The panel's full state face. */\nexport interface LoginPageState {\n /**\n * `idle` — nothing started; `starting` — begin() in flight; `waiting` —\n * the Studio URL is live and polling; `success`/`failed` — terminal;\n * `unavailable` — the Remote itself could not be reached (old Host, mount\n * failure), manual paste is the way.\n */\n phase: 'idle' | 'starting' | 'waiting' | 'success' | 'failed' | 'unavailable'\n /** The saved extra account receiving this attempt, or undefined for default. */\n targetRef?: string\n /** The Studio authorization URL while `waiting`. */\n authUrl: string | undefined\n /** The account display name on `success`. */\n userName: string | undefined\n /** The key's Studio label on `success`. */\n keyName: string | undefined\n /** The stable failure reason when `failed`. */\n reason: CommandCodeLoginFailureReason | undefined\n /** Secondary failure detail when `failed`/`unavailable`. */\n message: string | undefined\n}\n\n/** Keep one account's login status out of every other account's row. */\nexport function loginStateForTarget(\n state: LoginPageState,\n targetRef: string | undefined,\n): { visible: LoginPageState; busyElsewhere: boolean } {\n if (state.targetRef === targetRef) return { visible: state, busyElsewhere: false }\n return {\n visible: { ...state, phase: 'idle', authUrl: undefined },\n busyElsewhere: state.phase === 'starting' || state.phase === 'waiting',\n }\n}\n\n/** How often a live attempt is polled. */\nconst POLL_INTERVAL_MS = 1_000\n\n/**\n * The login panel's fetch/poll lifecycle. One poll loop at a time; a fresh\n * `begin()` supersedes any previous loop via a generation token.\n */\nexport class CommandCodeLoginController {\n private readonly remote: () => LoginRemote | undefined\n private readonly listeners = new Set<() => void>()\n private readonly pollMs: number\n /** Monotonic token; only the latest loop may publish polling results. */\n private generation = 0\n private disposed = false\n\n private phase: LoginPageState['phase'] = 'idle'\n private targetRef: string | undefined\n private authUrl: string | undefined\n private userName: string | undefined\n private keyName: string | undefined\n private reason: CommandCodeLoginFailureReason | undefined\n private message: string | undefined\n\n constructor(remote: () => LoginRemote | undefined, pollMs = POLL_INTERVAL_MS) {\n this.remote = remote\n this.pollMs = pollMs\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Build the current panel state face. */\n state(): LoginPageState {\n return {\n phase: this.phase,\n ...(this.targetRef === undefined ? {} : { targetRef: this.targetRef }),\n authUrl: this.authUrl,\n userName: this.userName,\n keyName: this.keyName,\n reason: this.reason,\n message: this.message,\n }\n }\n\n /** Start (or rejoin) a login attempt and begin polling its status. */\n async begin(targetRef?: string): Promise<void> {\n if (this.disposed || this.phase === 'starting' || this.phase === 'waiting') return\n const generation = ++this.generation\n this.targetRef = targetRef\n this.set({ phase: 'starting', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: undefined })\n const remote = this.remote()\n if (remote === undefined) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: 'login remote is not mounted' })\n return\n }\n let result: LoginCallResult\n try {\n result = await remote.loginBegin(targetRef)\n } catch (error: unknown) {\n // A transport throw (gateway hiccup) reads the same as a rejected call.\n result = { ok: false, error: { message: error instanceof Error ? error.message : String(error) } }\n }\n if (this.superseded(generation)) return\n if (!result.ok) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: result.error.message })\n return\n }\n this.apply(result.value)\n if (this.currentPhase === 'waiting') void this.poll(generation)\n }\n\n /** Cancel a waiting attempt. */\n async cancel(): Promise<void> {\n if (this.disposed || (this.phase !== 'starting' && this.phase !== 'waiting')) return\n const generation = ++this.generation\n const remote = this.remote()\n if (remote === undefined) return\n let result: LoginCallResult\n try {\n result = await remote.loginCancel()\n } catch {\n // The Host may be gone; reflect the local cancel regardless.\n this.set({ phase: 'failed', authUrl: undefined, userName: undefined, keyName: undefined, reason: 'cancelled', message: undefined })\n return\n }\n if (this.superseded(generation)) return\n if (result.ok) this.apply(result.value)\n else this.set({ phase: 'failed', authUrl: undefined, userName: undefined, keyName: undefined, reason: 'cancelled', message: undefined })\n }\n\n /** Stop polling and release listeners. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.generation += 1\n this.listeners.clear()\n }\n\n // -----------------------------------------------------------------------\n // Internals\n // -----------------------------------------------------------------------\n\n /** Poll until the attempt leaves `waiting` or a newer loop supersedes us. */\n private async poll(generation: number): Promise<void> {\n // A getter read (not the field) so control-flow narrowing across `await`\n // cannot claim the phase is frozen.\n while (!this.disposed && !this.superseded(generation) && this.currentPhase === 'waiting') {\n await sleep(this.pollMs)\n if (this.disposed || this.superseded(generation) || this.currentPhase !== 'waiting') return\n const remote = this.remote()\n if (remote === undefined) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: 'login remote is not mounted' })\n return\n }\n let result: LoginCallResult\n try {\n result = await remote.loginStatus()\n } catch {\n continue // one missed poll is not an outage; the next tick retries\n }\n if (this.superseded(generation) || this.currentPhase !== 'waiting') return\n if (result.ok) this.apply(result.value)\n }\n }\n\n private get currentPhase(): LoginPageState['phase'] {\n return this.phase\n }\n\n /** Project one Host status onto the panel face. */\n private apply(status: CommandCodeLoginStatus): void {\n const base = { authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: undefined }\n if (status.state === 'waiting') {\n this.set({ ...base, phase: 'waiting', authUrl: status.authUrl })\n return\n }\n if (status.state === 'success') {\n this.set({ ...base, phase: 'success', userName: status.userName, keyName: status.keyName })\n return\n }\n if (status.state === 'failed') {\n this.set({ ...base, phase: 'failed', reason: status.reason, message: status.message })\n return\n }\n // `idle` mid-poll means the Host restarted; the attempt is gone.\n this.set({ ...base, phase: 'failed', reason: 'cancelled', message: 'the login attempt is no longer active' })\n }\n\n /** Replace the whole state face and notify. Explicit over partial patches. */\n private set(state: LoginPageState): void {\n this.phase = state.phase\n this.authUrl = state.authUrl\n this.userName = state.userName\n this.keyName = state.keyName\n this.reason = state.reason\n this.message = state.message\n this.publish()\n }\n\n private superseded(generation: number): boolean {\n return this.disposed || generation !== this.generation\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of [...this.listeners]) listener()\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n// ---------------------------------------------------------------------------\n// Hint copy for the login panel / card row (JSX-free so node tests drive it)\n// ---------------------------------------------------------------------------\n\n/**\n * The per-reason copy for a failed login attempt. Shared by the settings\n * page's login panel and the Models-page card's login row — the same reasons\n * can surface from either surface.\n */\nexport function loginFailureCopy(\n reason: CommandCodeLoginFailureReason | undefined,\n t: Translate<SettingsCommandCodeKey>,\n): string {\n if (reason === 'denied') return t('loginDenied')\n if (reason === 'timeout') return t('loginTimeout')\n if (reason === 'invalid-key') return t('loginInvalidKey')\n if (reason === 'network') return t('loginNetwork')\n if (reason === 'unavailable') return t('loginStoreFailed')\n if (reason === 'cancelled') return t('loginCancelled')\n return t('loginFailedGeneric')\n}\n\n/** One login panel row's computed hint: text, class stem, and optional title. */\nexport interface LoginHint {\n text: string\n className: string\n /** Tooltip shown when the row carries secondary failure detail. */\n title: string | undefined\n}\n\n/**\n * The hint text + class for one login panel state, shared by the settings\n * page's `LoginPanel` and the Models-page card's login row so both surfaces\n * can never drift apart. Pure: no timers, no state — the components render it.\n */\nexport function loginHint(\n state: LoginPageState,\n t: Translate<SettingsCommandCodeKey>,\n): LoginHint {\n if (state.phase === 'starting' || state.phase === 'waiting') {\n return {\n text: t(state.phase === 'starting' ? 'loginStarting' : 'loginWaiting'),\n className: 'cc-hint',\n title: undefined,\n }\n }\n if (state.phase === 'success') {\n const keyName = state.keyName !== undefined && state.keyName !== '' ? ` · ${state.keyName}` : ''\n return {\n text: `${t('loginSuccess')} ${state.userName ?? ''}${keyName}`.trim(),\n className: 'cc-loginDone',\n title: undefined,\n }\n }\n if (state.phase === 'failed') {\n return {\n text: loginFailureCopy(state.reason, t),\n className: 'cc-loginError',\n title: state.message,\n }\n }\n if (state.phase === 'unavailable') {\n return {\n text: `${t('loginUnavailable')} ${state.message ?? ''}`.trim(),\n className: 'cc-loginError',\n title: undefined,\n }\n }\n return { text: t('loginHintIdle'), className: 'cc-hint', title: undefined }\n}\n","/**\n * Shared boundary-validation and Remote-descriptor plumbing for the plugin's\n * hand-rolled Typert wire contracts (`commandcode/report`, `commandcode/models`,\n * `commandcode/login*`).\n *\n * Every Remote this plugin serves crosses the Typert Gateway with a strict\n * result schema: the Host half registers a descriptor against a Cordis service\n * (`src/usage-remote.ts`) and the browser half mounts the matching contribution\n * on `ctx.remote` (`src/client/index.ts`). The wire contract is deliberately\n * dependency-free so the client bundle can inline it — a pure-TS helper module\n * imported by the wire files keeps it that way while removing the schema\n * helpers and descriptor boilerplate they used to duplicate.\n *\n * @module dsh-commandcode-provider/wire-shared\n */\n\nimport type { InvocationDescriptor, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\n\n/** The npm package identity every contribution and descriptor claims. */\nexport const REMOTE_PACKAGE = '@mars-sea/dsh-commandcode-provider'\n\n/** The Cordis service key the Gateway resolves every Command Code Remote from. */\nexport const REMOTE_SERVICE = 'commandcodeUsage'\n\n/** The wire namespace all Command Code endpoints share. */\nexport const REMOTE_NAMESPACE = 'commandcode'\n\n/** The read/validate helpers one boundary codec needs. */\nexport interface BoundaryValidator {\n /** Reject one boundary value with a field-naming error. */\n reject(field: string): never\n /** Narrow an unknown value to a plain record, or reject. */\n record(value: unknown, field: string): Record<string, unknown>\n /** Read one required string field (`field` is the dotted error label). */\n stringField(source: Record<string, unknown>, key: string, field: string): string\n /** Read one required finite number field (`field` is the dotted error label). */\n numberField(source: Record<string, unknown>, key: string, field: string): number\n /** Read one required boolean field (`field` is the dotted error label). */\n booleanField(source: Record<string, unknown>, key: string, field: string): boolean\n}\n\n/**\n * Build the validator helpers one endpoint uses. `prefix` names the\n * endpoint in the rejection message (e.g. `commandcode/report result:`), so\n * each wire file keeps its own diagnostic phrasing while sharing the helper\n * bodies.\n *\n * The helpers return the reject call directly in the failure branch: since\n * `reject` is typed `never`, the ternary's union collapses to the success type\n * without relying on TypeScript's control-flow analysis of a never-returning\n * call (which only recognizes function declarations, not the destructured\n * arrow `reject` callers receive from this factory).\n */\nexport function makeBoundaryValidator(prefix: string): BoundaryValidator {\n const reject = (field: string): never => {\n throw new TypeError(`${prefix} invalid ${field}`)\n }\n const record = (value: unknown, field: string): Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : reject(field)\n const stringField = (source: Record<string, unknown>, key: string, field: string): string =>\n typeof source[key] === 'string' ? source[key] as string : reject(field)\n const numberField = (source: Record<string, unknown>, key: string, field: string): number =>\n typeof source[key] === 'number' && Number.isFinite(source[key] as number)\n ? source[key] as number\n : reject(field)\n const booleanField = (source: Record<string, unknown>, key: string, field: string): boolean =>\n typeof source[key] === 'boolean' ? source[key] as boolean : reject(field)\n return { reject, record, stringField, numberField, booleanField }\n}\n\n/**\n * One strict result codec written in BOTH Typert generations' vocabulary.\n *\n * The protocol changed shape under the same `mode: 'strict'` tag, and each\n * engine generation validates the member it knows while ignoring the other:\n *\n * - Every RELEASED engine (0.1.2-rc.1 … 0.1.6-alpha.1, i.e. all 21 published\n * versions) declares `schema: TypertSchema`; its registry throws\n * `typert: <subject> strict codec has no parse() method` unless\n * `codec.schema.parse` is a function, and its Gateway validates with\n * `codec.schema.parse(value)`.\n * - master after commit `e459e3263` (`perf(typert): materialize generated\n * schemas on first use`) replaced that member with the lazy factory\n * `create: () => TypertSchema`, throws `typert: <subject> strict codec has no\n * create() factory` unless `typeof codec.create === 'function'`, and\n * validates with `codec.create().parse(value)`.\n *\n * So the one codec carries both, which is a version-agnostic fix rather than a\n * probe: neither validator inspects the member it does not know, and the\n * member the running engine does not read is inert. Carrying only one of them\n * breaks half the engines the manifest declares compatible — that is exactly\n * issue #49, whose one-line patch (`schema` → `create`) would have fixed\n * unreleased master by breaking every install that exists today.\n *\n * This interface also stands in for the local typings: no published\n * `@deepseek-ai/dsh-typert-protocol` carries `create` yet, so the two-member\n * shape is stated here and handed to the protocol type by assignment (the\n * older generation's `InvocationDescriptor` requires `schema` and ignores the\n * extra `create`; the newer one requires `create`, so neither needs a cast).\n */\ninterface StrictCodec<Output> {\n readonly mode: 'strict'\n readonly typeSymbol: string\n /** Read by released engines (≤ `0.1.6-alpha.1`). */\n readonly schema: TypertSchema<Output>\n /** Read by engines after `e459e3263` — the lazy replacement for `schema`. */\n readonly create: () => TypertSchema<Output>\n}\n\n/** Use the same strict-codec shape for invocation parameters and results. */\nexport function makeStrictCodec<Output>(typeSymbol: string, schema: TypertSchema<Output>): StrictCodec<Output> {\n return { mode: 'strict', typeSymbol, schema, create: () => schema }\n}\n\n/**\n * Build one strict invocation descriptor. Every Command Code Remote shares the\n * `commandcode` namespace, the `commandcodeUsage` service, and a strict\n * `mode: 'strict'` result — only the endpoint, method, result type symbol, and\n * schema differ — so the boilerplate lives here once and each endpoint supplies\n * only its own facts.\n */\nexport function makeRemoteDescriptor<Output>(\n endpoint: string,\n method: string,\n typeSymbol: string,\n schema: TypertSchema<Output>,\n): InvocationDescriptor {\n // Both members name the SAME hand-rolled schema: `create()` is the newer\n // generation's lazy accessor for what the older one reads directly, so the\n // two generations can never validate against different rules. Defined as a\n // value (not inline) so the older typings' excess-property check does not\n // reject the member they do not declare.\n const result = makeStrictCodec(typeSymbol, schema)\n return {\n id: `${REMOTE_PACKAGE}#${endpoint}`,\n service: REMOTE_SERVICE,\n namespace: REMOTE_NAMESPACE,\n method,\n invocation: { kind: 'direct' },\n parameters: [],\n result,\n }\n}\n","/**\n * Wire contract for the Command Code account-usage Remote\n * (`commandcode/report`).\n *\n * The settings page renders the same account/usage/credit facts the\n * `/commandcode` command prints, but the browser never holds the API key —\n * the report must be produced Host-side and cross the Connection RPC carrier.\n * The harness exposes plugin-defined Host methods through the Typert Gateway:\n * the Host half registers a strict invocation descriptor against a Cordis\n * service (`src/usage-remote.ts`), and the browser half mounts the matching\n * Remote contribution on `ctx.remote` (`src/client/index.ts`).\n *\n * This module is the single source both halves share: the result validator\n * (a hand-rolled {@link TypertSchema}, so neither half needs a schema library)\n * and the exact descriptor object, so the endpoint can never drift apart.\n * It is deliberately dependency-free — the client bundle inlines it, and only\n * `import type` edges leave it (erased at build). The boundary-validator\n * helpers and the descriptor boilerplate live in `./wire-shared.ts`, shared\n * with the login wire contract.\n *\n * @module dsh-commandcode-provider/usage-wire\n */\n\nimport type { CommandCodeCredits, CommandCodeUsageReport, UsageBlockReason } from './adapter.ts'\n\nexport type { CommandCodeUsageReport, UsageBlockReason }\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** One account's usage entry in the multi-account report. */\nexport interface CommandCodeAccountUsage {\n /** Stable slot id (`default`, `account-2`, …). */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Whether an API key resolved for this account. */\n configured: boolean\n /** Whether this account currently serves requests (first usable slot). */\n active: boolean\n /** Rotation mark: `''` (usable), `'rate-limit'`, or `'invalid-credential'`. */\n mark: string\n /** Known cooldown end in millis; 0 when unknown or not cooling down. */\n cooldownUntil: number\n /** The per-account report; `failures`-only when the fetch itself failed. */\n report: CommandCodeUsageReport\n}\n\n/** The settings page's account card data: one entry per configured account. */\nexport interface CommandCodeAccountsReport {\n accounts: CommandCodeAccountUsage[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const USAGE_REMOTE_PACKAGE = REMOTE_PACKAGE\n\n/** Canonical `<namespace>/<method>` endpoint of the usage report Remote. */\nexport const USAGE_REPORT_ENDPOINT = 'commandcode/report'\n\n/**\n * The shared read/validate helpers for the usage report endpoint, prefixed\n * so rejection messages name the offending boundary.\n */\nconst { reject, record, stringField, numberField, booleanField } =\n makeBoundaryValidator('commandcode/report result:')\n\n/** Validate one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one quota window, or undefined when the frame carries no such window.\n *\n * The distinction is load-bearing at this boundary: an ABSENT window means the\n * billing endpoint reported none (an unlimited plan), while a present block with\n * `cap: 0` means uncapped spend that was really reported. Collapsing the two\n * would draw a zeroed quota row for an account that has no such limit.\n */\nfunction windowLimit(\n value: unknown,\n field: string,\n): { used: number; cap: number; exceeded: boolean; resetAt: number } | undefined {\n if (value === undefined) return undefined\n const source = record(value, field)\n return {\n used: numberField(source, 'used', `${field}.used`),\n cap: numberField(source, 'cap', `${field}.cap`),\n exceeded: booleanField(source, 'exceeded', `${field}.exceeded`),\n resetAt: numberField(source, 'resetAt', `${field}.resetAt`),\n }\n}\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeUsageReport}.\n * Optional sections stay optional; every present field is shape-checked so a\n * malformed frame fails the boundary instead of rendering garbage.\n */\nfunction parseUsageReport(value: unknown): CommandCodeUsageReport {\n const source = record(value, 'report')\n const failures = source.failures\n if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== 'string')) reject('failures')\n const report: CommandCodeUsageReport = { failures: failures as string[] }\n\n if (source.blocked !== undefined) {\n const blocked = source.blocked\n // Positive check: TS's never-return control-flow analysis only recognizes\n // function declarations, not the factory's destructured-arrow `reject`, so\n // narrow `blocked` in the positive branch instead.\n if (blocked === 'invalid-key' || blocked === 'service-unavailable' || blocked === 'invalid-response' || blocked === 'network') {\n report.blocked = blocked\n } else {\n reject('blocked')\n }\n }\n\n if (source.account !== undefined) {\n const account = record(source.account, 'account')\n report.account = {\n id: stringField(account, 'id', 'account.id'),\n name: stringField(account, 'name', 'account.name'),\n userName: stringField(account, 'userName', 'account.userName'),\n }\n }\n\n if (source.usage !== undefined) {\n const usage = record(source.usage, 'usage')\n report.usage = {\n totalCount: numberField(usage, 'totalCount', 'usage.totalCount'),\n totalCost: numberField(usage, 'totalCost', 'usage.totalCost'),\n successRate: numberField(usage, 'successRate', 'usage.successRate'),\n completedCount: numberField(usage, 'completedCount', 'usage.completedCount'),\n failedCount: numberField(usage, 'failedCount', 'usage.failedCount'),\n totalTokensIn: numberField(usage, 'totalTokensIn', 'usage.totalTokensIn'),\n totalTokensOut: numberField(usage, 'totalTokensOut', 'usage.totalTokensOut'),\n totalCredits: numberField(usage, 'totalCredits', 'usage.totalCredits'),\n periodBasis: stringField(usage, 'periodBasis', 'usage.periodBasis'),\n }\n }\n\n if (source.credits !== undefined) {\n const credits = record(source.credits, 'credits')\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberField(credits, 'monthlyCredits', 'credits.monthlyCredits'),\n purchasedCredits: numberField(credits, 'purchasedCredits', 'credits.purchasedCredits'),\n freeCredits: numberField(credits, 'freeCredits', 'credits.freeCredits'),\n }\n // OPTIONAL on the wire: a Host half that predates this field serves the\n // scalar 0 for an omitted balance, which cannot be told from a real zero.\n // An explicit `false` therefore means \"not reported\" and the panel keeps the\n // figure off the dashboard; an absent flag (an older Host) stays unset and\n // is read as \"assume reported\", so a real balance is not lost cross-version.\n // A PRESENT value must still be a boolean, so a malformed frame is rejected\n // here rather than coerced.\n if (credits.monthlyReported !== undefined) {\n parsed.monthlyReported = booleanField(credits, 'monthlyReported', 'credits.monthlyReported')\n }\n for (const flag of ['purchasedReported', 'freeReported'] as const) {\n if (credits[flag] !== undefined) parsed[flag] = booleanField(credits, flag, `credits.${flag}`)\n }\n // Absent means the endpoint reported no such window. The window parsers\n // return undefined for an absent block, and an optional member is only set\n // when it was really there.\n const fiveHour = windowLimit(credits.fiveHour, 'credits.fiveHour')\n const weekly = windowLimit(credits.weekly, 'credits.weekly')\n if (fiveHour !== undefined) parsed.fiveHour = fiveHour\n if (weekly !== undefined) parsed.weekly = weekly\n report.credits = parsed\n }\n\n if (source.plan !== undefined) {\n const plan = record(source.plan, 'plan')\n const monthly = plan.monthlyCredits\n if (monthly !== null && (typeof monthly !== 'number' || !Number.isFinite(monthly))) reject('plan.monthlyCredits')\n report.plan = {\n planId: stringField(plan, 'planId', 'plan.planId'),\n name: stringField(plan, 'name', 'plan.name'),\n status: stringField(plan, 'status', 'plan.status'),\n monthlyCredits: monthly as number | null,\n currentPeriodEnd: numberField(plan, 'currentPeriodEnd', 'plan.currentPeriodEnd'),\n }\n }\n\n return report\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeAccountUsage}. */\nfunction parseAccountUsage(value: unknown): CommandCodeAccountUsage {\n const source = record(value, 'account')\n return {\n id: stringField(source, 'id', 'account.id'),\n label: stringField(source, 'label', 'account.label'),\n configured: booleanField(source, 'configured', 'account.configured'),\n active: booleanField(source, 'active', 'account.active'),\n mark: stringField(source, 'mark', 'account.mark'),\n cooldownUntil: numberField(source, 'cooldownUntil', 'account.cooldownUntil'),\n report: parseUsageReport(source.report),\n }\n}\n\n/** Parse the wire result into a {@link CommandCodeAccountsReport}. */\nfunction parseAccountsReport(value: unknown): CommandCodeAccountsReport {\n const source = record(value, 'result')\n const accounts = source.accounts\n if (Array.isArray(accounts)) {\n return { accounts: accounts.map(parseAccountUsage) }\n }\n return reject('accounts')\n}\n\n/**\n * The strict result codec both halves attach to the descriptor. Hand-rolled:\n * the client bundle may not require a schema library, and `TypertSchema` is\n * deliberately minimal so one `parse` function satisfies it.\n */\nexport const usageReportSchema: TypertSchema<CommandCodeAccountsReport> = {\n parse: parseAccountsReport,\n}\n\n/**\n * The one invocation descriptor, shared verbatim by the Host registration and\n * the Client mount. `service` names the Cordis key the Gateway resolves the\n * receiver from; `namespace`/`method` name the wire endpoint.\n */\nexport const USAGE_REPORT_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeAccountsReport>(\n USAGE_REPORT_ENDPOINT,\n 'report',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeAccountsReport`,\n usageReportSchema,\n )\n\n/** The Host-face contribution registered on `ctx.typert`. */\nexport const USAGE_HOST_CONTRIBUTION = {\n package: USAGE_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // 0.1.2's Typert registry requires every Host contribution to carry its\n // reflection model. This hand-written Remote deliberately has no generated\n // reflection exports, so use the official empty-model form rather than a\n // cast that leaves registry inspection with `model: undefined`.\n model: { services: [], events: [], objects: [] },\n invocations: [USAGE_REPORT_DESCRIPTOR],\n}\n\n/** The Client-face contribution mounted on `ctx.remote`. */\nexport const USAGE_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [USAGE_REPORT_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog Remote (`commandcode/models`)\n// ---------------------------------------------------------------------------\n\n/** One catalog entry the settings page's model editors offer. */\nexport interface CommandCodeCatalogModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n /**\n * Minimum plan-tier key for this model (a `KNOWN_PLANS` value: `go`,\n * `goat`, `pro`, `provider`, `max`), or undefined for models outside the\n * snapshot. The settings page groups the model-editor dropdowns under\n * tier headings from this — the browser cannot import the Host's\n * capability snapshot, so the Host stamps it per entry.\n */\n tier?: string\n}\n\n/** The model-catalog Remote result: the full catalog, sorted for picking. */\nexport interface CommandCodeCatalog {\n models: CommandCodeCatalogModel[]\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the model-catalog Remote. */\nexport const MODELS_ENDPOINT = 'commandcode/models'\n\n/**\n * The shared read/validate helpers for the model-catalog endpoint — a\n * separate instance so catalog boundary errors name `commandcode/models`,\n * not the report endpoint.\n */\nconst {\n record: catalogRecord,\n stringField: catalogString,\n} = makeBoundaryValidator('commandcode/models result:')\n\n/** Parse one untrusted boundary value into a {@link CommandCodeCatalogModel}. */\nfunction parseCatalogModel(value: unknown): CommandCodeCatalogModel {\n const source = catalogRecord(value, 'model')\n const model: CommandCodeCatalogModel = {\n id: catalogString(source, 'id', 'model.id'),\n name: catalogString(source, 'name', 'model.name'),\n }\n // Tier is optional on the wire (older Hosts predate it); a present\n // non-string is a contract violation, not a silent drop.\n if (source.tier !== undefined) {\n model.tier = catalogString(source, 'tier', 'model.tier')\n }\n return model\n}\n\n/** Parse the wire result into a {@link CommandCodeCatalog}. */\nfunction parseCatalog(value: unknown): CommandCodeCatalog {\n const source = catalogRecord(value, 'result')\n const models = source.models\n if (Array.isArray(models)) {\n return { models: models.map(parseCatalogModel) }\n }\n throw new TypeError('commandcode/models result: invalid models')\n}\n\n/** The strict result codec for the model-catalog Remote. */\nexport const modelsSchema: TypertSchema<CommandCodeCatalog> = {\n parse: parseCatalog,\n}\n\n/**\n * The model-catalog invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the usage report.\n */\nexport const MODELS_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeCatalog>(\n MODELS_ENDPOINT,\n 'models',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeCatalog`,\n modelsSchema,\n )\n\n/** The Client-face contribution for the model-catalog endpoint. */\nexport const MODELS_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [MODELS_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model price table Remote (`commandcode/prices`)\n// ---------------------------------------------------------------------------\n\n/**\n * One model's per-token rates, in USD per 1,000,000 tokens — the unit the\n * official pricing page publishes in.\n */\nexport interface CommandCodeModelRates {\n /** Uncached (billed) input tokens. */\n inputCost: number\n /** Completion tokens. */\n outputCost: number\n /** Input tokens served from the provider's cache. */\n cacheReadCost: number\n /**\n * Input tokens written into the provider's cache. Present for a minority of\n * models — the page publishes no cache-write rate for the rest, whose\n * cache-write tokens are therefore UNPRICED. Do not substitute a multiple of\n * the input rate for a missing value.\n */\n cacheWriteCost?: number\n}\n\n/** One whole-request context band; maxContext is inclusive, absent on the last band. */\nexport interface CommandCodeContextTier extends CommandCodeModelRates {\n maxContext?: number\n}\n\n/** One model's rates plus the peak-hour override for time-of-day models. */\nexport interface CommandCodeModelPrice extends CommandCodeModelRates {\n /**\n * Lookup key: the catalog model id when a catalog model maps to this row,\n * otherwise the pricing page's own slug. A session reports catalog ids, so\n * this is the primary key the browser looks up by.\n */\n id: string\n /** The pricing page's slug for this row — the secondary lookup key. */\n slug: string\n /**\n * Rates charged inside the peak windows. The row's own top-level rates are\n * the off-peak rates, so a row WITH this block is time-of-day priced and a\n * row without it is flat-priced.\n */\n peak?: CommandCodeModelRates\n contextTiers?: CommandCodeContextTier[]\n /**\n * Whether the model costs nothing on every plan right now (a free deal or a\n * `:free` catalog variant). Served explicitly at zero rates so a surface can\n * say \"free\" rather than showing nothing.\n */\n free?: boolean\n}\n\n/** The price-table Remote result: every known model's rates. */\nexport interface CommandCodePriceTable {\n /**\n * Every priced model, keyed by {@link CommandCodeModelPrice.id} (catalog id\n * first, pricing slug as the fallback) and carrying its slug as a second\n * lookup key. A model absent from this list has no known price and must\n * render no cost at all rather than a guess.\n */\n models: CommandCodeModelPrice[]\n /**\n * Peak-pricing windows as `[startHour, endHour)` in UTC, end-exclusive,\n * applying Monday–Friday only. Shipped with the table so the browser prices\n * against the Host snapshot's schedule instead of restating it.\n */\n peakHours: Array<[number, number]>\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the price-table Remote. */\nexport const PRICES_ENDPOINT = 'commandcode/prices'\n\n/**\n * The shared read/validate helpers for the price-table endpoint — its own\n * instance so price boundary errors name `commandcode/prices`.\n */\nconst {\n reject: priceReject,\n record: priceRecord,\n stringField: priceString,\n numberField: priceNumber,\n booleanField: priceBoolean,\n} = makeBoundaryValidator('commandcode/prices result:')\n\n/** Parse one rate block (`rates`, or a model's `peak` override). */\nfunction parseRates(source: Record<string, unknown>, field: string): CommandCodeModelRates {\n const rates: CommandCodeModelRates = {\n inputCost: priceNumber(source, 'inputCost', `${field}.inputCost`),\n outputCost: priceNumber(source, 'outputCost', `${field}.outputCost`),\n cacheReadCost: priceNumber(source, 'cacheReadCost', `${field}.cacheReadCost`),\n }\n // Optional on the wire: only a minority of models publish a cache-write\n // rate, and a present non-number is a contract violation rather than a\n // silent zero.\n if (source.cacheWriteCost !== undefined) {\n rates.cacheWriteCost = priceNumber(source, 'cacheWriteCost', `${field}.cacheWriteCost`)\n }\n return rates\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeModelPrice}. */\nfunction parseModelPrice(value: unknown): CommandCodeModelPrice {\n const source = priceRecord(value, 'model')\n const price: CommandCodeModelPrice = {\n id: priceString(source, 'id', 'model.id'),\n slug: priceString(source, 'slug', 'model.slug'),\n ...parseRates(source, 'model'),\n }\n if (source.peak !== undefined) price.peak = parseRates(priceRecord(source.peak, 'model.peak'), 'model.peak')\n if (source.contextTiers !== undefined) {\n if (!Array.isArray(source.contextTiers) || source.contextTiers.length === 0) priceReject('contextTiers')\n let previous = 0\n price.contextTiers = (source.contextTiers as unknown[]).map((value, index, tiers) => {\n const tier = priceRecord(value, 'contextTier')\n const out: CommandCodeContextTier = parseRates(tier, 'contextTier')\n if (tier.maxContext !== undefined) {\n const max = priceNumber(tier, 'maxContext', 'contextTier.maxContext')\n if (!Number.isSafeInteger(max) || max <= previous || index === tiers.length - 1) priceReject('contextTier.maxContext')\n previous = max\n out.maxContext = max\n } else if (index !== tiers.length - 1) priceReject('contextTier.maxContext')\n return out\n })\n }\n if (source.free !== undefined) price.free = priceBoolean(source, 'free', 'model.free')\n return price\n}\n\n/** Parse the wire result into a {@link CommandCodePriceTable}. */\nfunction parsePriceTable(value: unknown): CommandCodePriceTable {\n const source = priceRecord(value, 'result')\n const models = source.models\n if (!Array.isArray(models)) priceReject('models')\n const peakHours = source.peakHours\n if (!Array.isArray(peakHours)) priceReject('peakHours')\n return {\n models: (models as unknown[]).map(parseModelPrice),\n peakHours: (peakHours as unknown[]).map((window) => {\n if (!Array.isArray(window) || window.length !== 2) priceReject('peakHours[]')\n const [start, end] = window as [unknown, unknown]\n if (typeof start !== 'number' || typeof end !== 'number') priceReject('peakHours[]')\n return [start, end] as [number, number]\n }),\n }\n}\n\n/** The strict result codec for the price-table Remote. */\nexport const pricesSchema: TypertSchema<CommandCodePriceTable> = {\n parse: parsePriceTable,\n}\n\n/**\n * The price-table invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the report and catalog endpoints.\n */\nexport const PRICES_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodePriceTable>(\n PRICES_ENDPOINT,\n 'prices',\n `${USAGE_REMOTE_PACKAGE}#CommandCodePriceTable`,\n pricesSchema,\n )\n\n/** The Client-face contribution for the price-table endpoint. */\nexport const PRICES_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [PRICES_DESCRIPTOR],\n}\n","/**\n * Wire contract for the Command Code login Remote endpoints\n * (`commandcode/loginBegin`, `commandcode/loginStatus`,\n * `commandcode/loginCancel`).\n *\n * The settings page can start a browser login against the official Command\n * Code Studio (the same loopback flow `command-code login` performs) instead\n * of pasting an API key. The loopback server must live in the Host half — it\n * binds a local port and receives the key — so the page drives it through the\n * Typert Gateway exactly like the usage report.\n *\n * This module is the single source both halves share, deliberately\n * dependency-free (`import type` edges only): the strict status validator the\n * client trusts, the three descriptors both halves register, and the two\n * contribution objects. The state shape mirrors the Host-only flow machine in\n * `src/login.ts` as plain JSON.\n *\n * @module dsh-commandcode-provider/login-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n makeStrictCodec,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** Why a login attempt ended in `failed` (stable across versions for copy). */\nexport type CommandCodeLoginFailureReason =\n /** The Studio page reported the authorization was denied by the user. */\n | 'denied'\n /** No callback arrived within the flow's timeout window. */\n | 'timeout'\n /** The delivered key failed `/alpha/whoami` validation (401). */\n | 'invalid-key'\n /** The validation request could not reach the API. */\n | 'network'\n /** The key could not be stored (credentials seam unavailable). */\n | 'unavailable'\n /** The attempt was cancelled by the user or torn down with the plugin. */\n | 'cancelled'\n /** Anything else. */\n | 'error'\n\n/** One login attempt's full state face, as carried over the wire. */\nexport interface CommandCodeLoginStatus {\n /**\n * `idle` — no attempt; `waiting` — the loopback server is up and the\n * Studio URL is live; `success` — the key validated and was stored;\n * `failed` — see `reason`/`message`.\n */\n state: 'idle' | 'waiting' | 'success' | 'failed'\n /** The Studio authorization URL while `waiting`. */\n authUrl?: string\n /** The account display name reported by the Studio, on `success`. */\n userName?: string\n /** The key's label from the Studio, on `success`. */\n keyName?: string\n /** Why the attempt failed, when `failed`. */\n reason?: CommandCodeLoginFailureReason\n /** Human-readable failure detail, when `failed` (secondary to `reason`). */\n message?: string\n}\n\n/** The canonical endpoint paths of the three login Remotes. */\nexport const LOGIN_BEGIN_ENDPOINT = 'commandcode/loginBegin'\nexport const LOGIN_STATUS_ENDPOINT = 'commandcode/loginStatus'\nexport const LOGIN_CANCEL_ENDPOINT = 'commandcode/loginCancel'\n\nconst REASONS: readonly CommandCodeLoginFailureReason[] = [\n 'denied', 'timeout', 'invalid-key', 'network', 'unavailable', 'cancelled', 'error',\n]\n\n/** The shared read/validate helpers, prefixed with the login endpoint so\n * rejection messages name the offending boundary. */\nconst { reject, record, stringField } =\n makeBoundaryValidator('commandcode/login result:')\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeLoginStatus}.\n * Every field is shape-checked so a malformed frame fails the boundary\n * instead of leaking into the page.\n */\nexport function parseLoginStatus(value: unknown): CommandCodeLoginStatus {\n const source = record(value, 'status')\n const state = source.state\n // The factory's destructured-arrow `reject` is typed never-returning but\n // TS narrows it only in the positive branch — assign inside the guard.\n if (state === 'idle' || state === 'waiting' || state === 'success' || state === 'failed') {\n const status: CommandCodeLoginStatus = { state }\n if (source.authUrl !== undefined) {\n status.authUrl = stringField(source, 'authUrl', 'authUrl')\n }\n if (source.userName !== undefined) {\n status.userName = stringField(source, 'userName', 'userName')\n }\n if (source.keyName !== undefined) {\n status.keyName = stringField(source, 'keyName', 'keyName')\n }\n if (source.reason !== undefined) {\n const reason = source.reason\n if (typeof reason === 'string' && REASONS.includes(reason as CommandCodeLoginFailureReason)) {\n status.reason = reason as CommandCodeLoginFailureReason\n } else {\n reject('reason')\n }\n }\n if (source.message !== undefined) {\n status.message = stringField(source, 'message', 'message')\n }\n return status\n }\n return reject('state')\n}\n\n/** The strict result codec shared by all three login endpoints. */\nexport const loginStatusSchema: TypertSchema<CommandCodeLoginStatus> = {\n parse: parseLoginStatus,\n}\n\n/** Optional account target; the Host still checks it against saved slots. */\nconst loginTargetSchema: TypertSchema<string | undefined> = {\n parse(value: unknown): string | undefined {\n if (value === undefined || typeof value === 'string') return value\n return reject('targetRef')\n },\n}\n\n/** Build one login invocation descriptor. Only begin accepts an account ref. */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n const descriptor = makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n return method === 'loginBegin'\n ? {\n ...descriptor,\n parameters: [{\n name: 'targetRef', wire: 'targetRef', source: 'json',\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#CommandCodeLoginTargetRef`, loginTargetSchema),\n acceptsUndefined: true,\n }],\n }\n : descriptor\n}\n\n/** The three login descriptors, shared verbatim by Host registration and Client mount. */\nexport const LOGIN_DESCRIPTORS: readonly InvocationDescriptor[] = [\n loginDescriptor(LOGIN_BEGIN_ENDPOINT, 'loginBegin'),\n loginDescriptor(LOGIN_STATUS_ENDPOINT, 'loginStatus'),\n loginDescriptor(LOGIN_CANCEL_ENDPOINT, 'loginCancel'),\n]\n\n/** The Host-face contribution fragment registered on `ctx.typert`. */\nexport const LOGIN_HOST_CONTRIBUTION = {\n package: REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n invocations: LOGIN_DESCRIPTORS,\n}\n\n/** The Client-face contribution fragment mounted on `ctx.remote`. */\nexport const LOGIN_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REMOTE_PACKAGE,\n descriptors: LOGIN_DESCRIPTORS,\n}\n","/**\n * The shared login row: one field row that starts the Host-side browser\n * login, links to the Studio authorization page while the attempt is live,\n * and reports the outcome — rendered by BOTH the settings page (`section.tsx`)\n * and the Models-page provider card (`card.tsx`) so the two surfaces share\n * one component and one hint state machine.\n *\n * The hint copy/class logic lives in the JSX-free `./login.ts`\n * (`loginHint`/`loginFailureCopy`) so node tests can drive every phase; this\n * file only renders it.\n *\n * @module dsh-commandcode-provider/client/login-row\n */\n\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport { loginHint, loginStateForTarget } from './login.ts'\nimport type { LoginPageState } from './login.ts'\n\n/** One login row's props (same face both surfaces supply). */\nexport interface LoginRowProps {\n state: LoginPageState\n /** Only the matching attempt appears in this row; omitted means default. */\n targetRef?: string\n disabled: boolean\n disabledHint?: string | undefined\n t: Translate<SettingsCommandCodeKey>\n onBegin(): void\n onCancel(): void\n}\n\n/** The sign-in alternative to pasting a key (settings page + Models card). */\nexport function LoginRow({ state, targetRef, disabled, disabledHint, t, onBegin, onCancel }: LoginRowProps) {\n const { visible: visibleState, busyElsewhere } = loginStateForTarget(state, targetRef)\n const busy = visibleState.phase === 'starting' || visibleState.phase === 'waiting'\n const hint = loginHint(visibleState, t)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <span className=\"cc-label\">{t('loginTitle')}</span>\n <span className=\"cc-badges\">\n {busy ? (\n <button type=\"button\" className=\"cc-reset\" onClick={onCancel}>{t('loginCancel')}</button>\n ) : (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled || busyElsewhere} onClick={onBegin}>{t('loginButton')}</button>\n )}\n </span>\n </div>\n {visibleState.authUrl !== undefined ? (\n <p className=\"cc-hint\">\n <a className=\"cc-loginLink\" href={visibleState.authUrl} target=\"_blank\" rel=\"noreferrer\">{t('loginOpenLink')}</a>\n </p>\n ) : null}\n <p className={hint.className} title={hint.title}>{disabled && !busy && disabledHint !== undefined ? disabledHint : hint.text}</p>\n </div>\n )\n}\n","/**\n * Model-select helpers for the settings page's model editors (browser half).\n *\n * The routing-rule editor and the visible-models filter both pick catalog\n * models through the same checkbox multi-select dropdown (`ModelMultiSelect`\n * in section.tsx). The dropdown's data shaping — search filtering, stale-id\n * detection, tier grouping — lives here, React-free, so node tests can drive\n * it directly.\n *\n * Dependency-free by design: the client bundle may only import platform/seed\n * modules, so the plan snapshot below is a deliberately small vendored copy\n * (tier key → heading label) rather than an import of src/capabilities.ts.\n * When upstream adds a plan tier, extend BOTH tables.\n *\n * @module dsh-commandcode-provider/model-select\n */\n\n/**\n * Minimum plan tier → dropdown section heading. Mirrors the Host-side\n * `KNOWN_PLANS` values + `PLAN_LABELS` in src/capabilities.ts (kept as a\n * vendored copy because the client bundle cannot import host modules).\n * Covers every tier key `KNOWN_PLANS` uses today; an unknown tier key falls\n * back to the raw key rather than vanishing the row.\n */\nconst TIER_HEADINGS: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/**\n * The dropdown section heading for a catalog model id, or undefined for\n * models outside the known plan tiers (unmapped models and stale ids render\n * unheaded). `knownPlans` is the Host-side `KNOWN_PLANS` table, threaded in\n * by the caller so this module stays dependency-free.\n */\nexport function tierHeadingFor(\n modelId: string,\n knownPlans: Readonly<Record<string, string>>,\n): string | undefined {\n const tier = knownPlans[modelId]\n if (tier === undefined) return undefined\n return TIER_HEADINGS[tier] ?? tier\n}\n\n/** One selectable catalog model (mirrors `CatalogModelOption` in settings.ts). */\nexport interface SelectableModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n}\n\n/** One dropdown row: a live catalog model or a stale selection. */\nexport interface ModelSelectOption {\n /** Catalog model id (stale ids keep their raw id as the value). */\n value: string\n /** Display name (stale ids fall back to the raw id). */\n label: string\n /** True when the id is selected but the catalog no longer carries it. */\n stale: boolean\n}\n\n/** One dropdown section: a plan-tier heading plus its rows. */\nexport interface ModelSelectGroup {\n /** Section heading, or undefined for models outside the known plan tiers. */\n heading: string | undefined\n /** Rows in this section, in picker order. */\n options: ModelSelectOption[]\n}\n\n/**\n * Whether `text` matches `query` as a case-insensitive substring over the\n * model id AND display name. An empty/blank query matches everything.\n */\nexport function matchesModelQuery(\n model: SelectableModel,\n query: string,\n): boolean {\n const needle = query.trim().toLowerCase()\n if (needle === '') return true\n return model.id.toLowerCase().includes(needle)\n || model.name.toLowerCase().includes(needle)\n}\n\n/**\n * Build the dropdown options: the catalog (already in picker order) plus\n * any selected ids the catalog no longer carries, flagged stale so the UI\n * can mark them — a saved selection never silently loses an entry, and the\n * user can see which ones went stale upstream.\n *\n * When `query` is non-blank, catalog rows are filtered by\n * {@link matchesModelQuery}; stale rows are kept only while they match too,\n * so a search for a live model does not surface unrelated stale ids.\n */\nexport function buildModelSelectOptions(\n catalog: readonly SelectableModel[],\n selected: readonly string[],\n query = '',\n): ModelSelectOption[] {\n const catalogIds = new Set(catalog.map((model) => model.id))\n const options = catalog\n .filter((model) => matchesModelQuery(model, query))\n .map((model) => ({ value: model.id, label: model.name, stale: false }))\n // Dedupe defensively (order-preserving): hand-edited settings can repeat\n // or blank an id, and duplicate Menu ids would confuse selection state.\n const seen = new Set(catalogIds)\n for (const id of selected) {\n if (id === '' || seen.has(id)) continue\n seen.add(id)\n if (catalogIds.has(id)) continue\n if (!matchesModelQuery({ id, name: id }, query)) continue\n options.push({ value: id, label: id, stale: true })\n }\n return options\n}\n\n/**\n * Group dropdown options under plan-tier headings (`tierOf` maps a model id\n * to its tier heading, or undefined for unmapped models — see\n * {@link tierHeadingFor}). Live rows keep their relative order; stale ids\n * and unmapped live rows share one trailing unheaded group. Groups merge\n * repeats, so a catalog interleaving two tiers still renders one section\n * per tier.\n */\nexport function groupModelSelectOptions(\n options: readonly ModelSelectOption[],\n tierOf: (modelId: string) => string | undefined,\n): ModelSelectGroup[] {\n const groups: ModelSelectGroup[] = []\n const byHeading = new Map<string | undefined, ModelSelectGroup>()\n for (const option of options) {\n // Stale ids always render unheaded (their tier is unknowable); unmapped\n // live rows join the same trailing group so `heading: undefined`\n // appears at most once.\n const heading = option.stale ? undefined : tierOf(option.value)\n let group = byHeading.get(heading)\n if (group === undefined) {\n group = { heading, options: [] }\n byHeading.set(heading, group)\n groups.push(group)\n }\n group.options.push(option)\n }\n return groups\n}\n\n/**\n * Toggle one model id in a selection: remove it when present, append it\n * when absent (append keeps catalog order irrelevant — the picker re-sorts\n * by plan tier on render).\n */\nexport function toggleModelSelection(\n selected: readonly string[],\n modelId: string,\n): string[] {\n return selected.includes(modelId)\n ? selected.filter((value) => value !== modelId)\n : [...selected, modelId]\n}\n\n/** The catalog facts the visible-models card reads (mirrors `SettingsPageState`). */\nexport interface CatalogReadiness {\n /** Catalog model ids the Host reported (`[]` before the first fetch lands). */\n catalogIds: readonly string[]\n /** Whether the catalog fetch failed (or the Remote is unavailable). */\n catalogFailed: boolean\n}\n\n/**\n * Whether the catalog is trustworthy enough to call an unlisted selection\n * \"retired\". FALSE while the first fetch is still in flight and after a\n * failure, because the catalog is empty then and every selected id would look\n * stale — which turns the one-click stale cleanup into a button that silently\n * empties the allowlist. A successfully loaded but empty catalog is treated as\n * untrustworthy too: an empty list is far more likely a Host problem than every\n * model being retired at once, and the explicit \"show all\" entry covers the\n * user who really wants to clear the list.\n */\nexport function catalogIsReady(readiness: CatalogReadiness): boolean {\n return readiness.catalogIds.length > 0 && !readiness.catalogFailed\n}\n\n/**\n * Selected ids the loaded catalog no longer carries, in selection order.\n * Callers gate user-visible \"stale\" affordances on {@link catalogIsReady} —\n * the list itself is informational.\n */\nexport function staleModelIds(\n selected: readonly string[],\n readiness: CatalogReadiness,\n): string[] {\n const catalogIds = new Set(readiness.catalogIds)\n return selected.filter((id) => !catalogIds.has(id))\n}\n","","/**\n * The plugin's own version, read from package.json at build time.\n *\n * The client bundle inlines the JSON import (rolldown resolves it during the\n * tsdown build; node tests read it through tsx), so the rendered value always\n * matches the published package version with no second constant to keep in\n * sync. Rendered as a muted footer line on the settings page so a user can\n * report the exact build they run.\n *\n * @module dsh-commandcode-provider/client/version\n */\n\nimport pkg from '../../package.json'\n\n/** The published package version (e.g. `'0.6.0'`). */\nexport const PLUGIN_VERSION: string = pkg.version\n\n/**\n * This package's GitHub releases page, derived from the repository field so\n * the update hint's link target can never drift from the published home.\n * Tolerates both repository shapes (`{ url }` and the plain string form).\n */\nexport const PLUGIN_RELEASES_URL: string = (() => {\n const repo: unknown = (pkg as { repository?: unknown }).repository\n const url = typeof repo === 'string' ? repo : (repo as { url?: unknown } | undefined)?.url\n return `${typeof url === 'string' ? url.replace(/^git\\+/, '').replace(/\\.git$/, '') : 'https://github.com/Mars-Sea/dsh-commandcode-provider'}/releases`\n})()\n","/**\n * Plugin update hint (browser half).\n *\n * A deliberately small feature: when the \"Command Code\" settings page opens,\n * ask the npm registry for the package's published `latest` version and —\n * only when it is newer than the running build — let the page's footer show a\n * muted \"newer version available\" link to the GitHub releases. Everything\n * here is React-free and side-effect-seamed so node tests can drive it.\n *\n * Behaviour contract:\n *\n * - The registry is queried at most once per {@link UPDATE_CHECK_INTERVAL_MS}\n * per browser profile; the learned version is cached in `localStorage`\n * alongside the attempt time, so re-opening the settings page is free.\n * - A failed check records the attempt time too (an offline browser must not\n * hammer the registry on every page open) but keeps any previously learned\n * version, so the hint survives transient outages until it expires.\n * - Every failure mode (blocked network, non-OK status, malformed payload,\n * unavailable storage) degrades to \"no hint\"; nothing ever throws out of\n * {@link checkForUpdate}.\n *\n * The registry serves `access-control-allow-origin: *`, so the plain browser\n * fetch works from the GUI origin without any Host-side proxying.\n *\n * @module dsh-commandcode-provider/client/update\n */\n\n/** How often the page may hit the registry: once a day. */\nexport const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000\n\n/** Abort a hung registry request rather than keep the footer waiting. */\nexport const FETCH_TIMEOUT_MS = 5000\n\n/**\n * The npm registry document for this package's `latest` dist-tag. The scoped\n * name is path-escaped (`%2F`) so no client normalizes the slash away.\n */\nexport const NPM_LATEST_URL =\n 'https://registry.npmjs.org/@mars-sea%2Fdsh-commandcode-provider/latest'\n\n/**\n * Compare two version strings (`major.minor.patch[-pre]`). Returns a negative\n * number when `a` sorts before `b`, positive when after, zero when equal.\n *\n * Tolerant by design: a leading `v` is stripped, unparsable numeric parts\n * count as `0`, and semver prerelease rules apply (release > prerelease;\n * numeric identifiers compare numerically, everything else lexically, a\n * shorter identifier list sorts first). Enough for release tags; not a full\n * semver validator.\n */\nexport function compareVersions(a: string, b: string): number {\n const left = splitVersion(a)\n const right = splitVersion(b)\n const depth = Math.max(left.core.length, right.core.length)\n for (let index = 0; index < depth; index += 1) {\n const delta = (left.core[index] ?? 0) - (right.core[index] ?? 0)\n if (delta !== 0) return Math.sign(delta)\n }\n // A release outranks any prerelease of the same core version.\n if (left.pre.length === 0 && right.pre.length === 0) return 0\n if (left.pre.length === 0) return 1\n if (right.pre.length === 0) return -1\n const width = Math.max(left.pre.length, right.pre.length)\n for (let index = 0; index < width; index += 1) {\n const l = left.pre[index]\n const r = right.pre[index]\n if (l === undefined) return -1\n if (r === undefined) return 1\n const lNumeric = /^\\d+$/.test(l)\n const rNumeric = /^\\d+$/.test(r)\n let delta: number\n if (lNumeric && rNumeric) delta = Number(l) - Number(r)\n else if (lNumeric) delta = -1 // numeric identifiers sort below alphanumeric\n else if (rNumeric) delta = 1\n else delta = l < r ? -1 : l > r ? 1 : 0\n if (delta !== 0) return Math.sign(delta)\n }\n return 0\n}\n\n/** True when `candidate` is strictly newer than `current`. */\nexport function isNewerVersion(candidate: string, current: string): boolean {\n return compareVersions(candidate, current) > 0\n}\n\n/** Split a tolerant version string into numeric core + prerelease ids. */\nfunction splitVersion(value: string): { core: number[]; pre: string[] } {\n // Split on the FIRST dash only: `1.0.0-alpha-1` has prerelease `alpha-1`,\n // not `alpha` (a split on every dash would drop the `-1`).\n const cleaned = value.trim().replace(/^v/i, '')\n const dash = cleaned.indexOf('-')\n const coreText = dash < 0 ? cleaned : cleaned.slice(0, dash)\n const preText = dash < 0 ? undefined : cleaned.slice(dash + 1)\n const core = coreText === ''\n ? [0]\n : coreText.split('.').map((part) => {\n const parsed = Number.parseInt(part, 10)\n return Number.isFinite(parsed) ? parsed : 0\n })\n const pre = preText === undefined ? [] : preText.split('.')\n return { core, pre }\n}\n\n/**\n * Extract the published version from the registry's `/latest` manifest\n * (`{ name, version, … }`). Throws on anything unexpected so callers treat a\n * shape change as a failed attempt, never as bogus data.\n */\nexport function parseLatestVersion(payload: unknown): string {\n if (typeof payload !== 'object' || payload === null) {\n throw new Error('npm latest payload is not an object')\n }\n const version = (payload as { version?: unknown }).version\n if (typeof version !== 'string' || !/^\\d+\\.\\d+\\./.test(version)) {\n throw new Error('npm latest payload has no usable version')\n }\n return version\n}\n\n/** Fetch and parse the published `latest` version. Rejects on any failure. */\nexport async function fetchLatestVersion(\n fetchImpl: typeof fetch = fetch,\n): Promise<string> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n const response = await fetchImpl(NPM_LATEST_URL, { signal: controller.signal })\n if (!response.ok) {\n throw new Error(`registry responded ${response.status}`)\n }\n return parseLatestVersion(await response.json())\n } finally {\n clearTimeout(timer)\n }\n}\n\n/** What the cache remembers about the last check. */\nexport interface UpdateCheckRecord {\n /** When the last attempt completed (success or failure), epoch ms. */\n at: number\n /** The last successfully learned upstream version, if any. */\n version?: string | undefined\n}\n\n/** Storage seam so tests can stand in for `localStorage`. */\nexport interface UpdateCheckStore {\n read(): UpdateCheckRecord | undefined\n write(record: UpdateCheckRecord): void\n}\n\n/** The `localStorage` key holding {@link UpdateCheckRecord}. */\nexport const UPDATE_CHECK_CACHE_KEY = '@mars-sea/dsh-commandcode-provider/update-check'\n\n/**\n * A {@link UpdateCheckStore} backed by `localStorage`. Tolerates a missing or\n * throwing storage (SSR-ish contexts, private modes): reads yield `undefined`,\n * writes are dropped.\n */\nexport function localStorageUpdateStore(\n storage: Storage | undefined = typeof localStorage === 'undefined' ? undefined : localStorage,\n): UpdateCheckStore {\n return {\n read(): UpdateCheckRecord | undefined {\n if (storage === undefined) return undefined\n try {\n const raw = storage.getItem(UPDATE_CHECK_CACHE_KEY)\n if (raw === null) return undefined\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n const at = (parsed as { at?: unknown }).at\n if (typeof at !== 'number' || !Number.isFinite(at)) return undefined\n const version = (parsed as { version?: unknown }).version\n return {\n at,\n version: typeof version === 'string' && version !== '' ? version : undefined,\n }\n } catch {\n return undefined\n }\n },\n write(record: UpdateCheckRecord): void {\n if (storage === undefined) return\n try {\n storage.setItem(UPDATE_CHECK_CACHE_KEY, JSON.stringify(record))\n } catch {\n // Quota/private-mode failures must never break the page.\n }\n },\n }\n}\n\n/**\n * Run one throttled update check. Resolves with the newest published version\n * when it is newer than `currentVersion`, otherwise `undefined`.\n *\n * Within the throttle window (or on failure) the cached version answers, so\n * the hint keeps working offline; past the window the registry is consulted\n * again and the attempt time is refreshed either way.\n */\nexport async function checkForUpdate(options: {\n currentVersion: string\n now: number\n store: UpdateCheckStore\n fetchImpl?: typeof fetch\n}): Promise<string | undefined> {\n const { currentVersion, now, store } = options\n const hintOf = (version: string | undefined): string | undefined =>\n version !== undefined && isNewerVersion(version, currentVersion) ? version : undefined\n\n const cache = store.read()\n if (cache !== undefined && now - cache.at < UPDATE_CHECK_INTERVAL_MS) {\n return hintOf(cache.version)\n }\n\n let learned: string | undefined\n try {\n learned = await fetchLatestVersion(options.fetchImpl)\n } catch {\n // Degrade silently: record the attempt below and fall back to the cache.\n }\n const version = learned ?? cache?.version\n store.write({ at: now, version })\n return hintOf(version)\n}\n","/**\n * React component for the \"Command Code\" settings page (browser half).\n *\n * Renders as a `settings.section` entry — a page at the same settings-nav\n * level as General / Models / Plugins. The shell supplies the nav row and\n * renders this body inside the content column. All copy comes from the\n * `settings.commandcode` locale namespace; all state comes from the\n * `CommandCodeSettingsController` injected by the slot registration.\n *\n * The layout mirrors the harness's settings pages: a max-width content\n * column, labelled fields with hints, a reset affordance, and a\n * save/discard footer. Rarely touched connection facts (API base, working\n * directory, timeouts, plan filter) fold into a collapsed Advanced card\n * (`AdvancedSection`) so the page leads with the key and the usage facts.\n * Styles are injected once by the client entry\n * (see src/client/index.ts) and class-prefixed `cc-` to stay local.\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { Button, Menu } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { MenuEntry } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { CommandCodeCredits } from '../adapter.ts'\nimport type { CommandCodeAccountUsage, CommandCodeUsageReport } from '../usage-wire.ts'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport type { AccountItemState, CatalogModelOption, RuleItemState, SettingsPageState, StagedField } from './settings.ts'\nimport type { LoginPageState } from './login.ts'\nimport { LoginRow } from './login-row.tsx'\nimport { buildModelSelectOptions, catalogIsReady, groupModelSelectOptions, staleModelIds, tierHeadingFor, toggleModelSelection } from './model-select.ts'\nimport type { UsagePageState } from './usage.ts'\nimport { usageCardState, formatMoney, formatMoneyExact, formatResetAt, formatSuccessRate, formatTokensCompact, windowRatio } from './usage.ts'\nimport { PLUGIN_RELEASES_URL, PLUGIN_VERSION } from './version.ts'\nimport { checkForUpdate, localStorageUpdateStore } from './update.ts'\n\n/** Props composed by the slot registration: locale seat + injected face. */\nexport interface CommandCodeSettingsProps {\n t: Translate<SettingsCommandCodeKey>\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n useCommandCodeUsage<T>(selector: (state: UsagePageState) => T): T\n useCommandCodeLogin<T>(selector: (state: LoginPageState) => T): T\n edit(field: string, text: string): void\n resetField(field: string): void\n save(): void\n discard(): void\n refreshUsage(): void\n beginLogin(targetRef?: string): void\n cancelLogin(): void\n addAccount(): void\n removeAccount(id: string): void\n editAccountLabel(id: string, text: string): void\n editAccountKey(id: string, text: string): void\n toggleKeyClear(id: string): void\n addRule(): void\n removeRule(id: string): void\n editRuleModels(id: string, ids: string[]): void\n editRuleAccount(id: string, text: string): void\n editVisibleModels(ids: string[]): void\n clearVisibleModels(): void\n}\n\n/** The section fields folded into the collapsible Advanced card. */\ntype AdvancedField = 'apiBase' | 'workingDir' | 'requestTimeoutMs' | 'streamIdleTimeoutMs' | 'transportMaxRetries' | 'filterModelsByPlan' | 'webSearch' | 'showSidebarQuota' | 'commandGuard' | 'commandGuardThreshold' | 'commandGuardTimeoutMs' | 'zdr'\nconst ADVANCED_FIELDS: readonly AdvancedField[] = [\n 'apiBase',\n 'workingDir',\n 'requestTimeoutMs',\n 'streamIdleTimeoutMs',\n 'transportMaxRetries',\n 'filterModelsByPlan',\n 'webSearch',\n 'showSidebarQuota',\n 'commandGuard',\n 'commandGuardThreshold',\n 'commandGuardTimeoutMs',\n 'zdr',\n]\n\n/** One labelled field row in the page body. */\nfunction Field({\n id,\n label,\n hint,\n state,\n disabled,\n numeric,\n placeholder,\n onEdit,\n onReset,\n t,\n}: {\n id: string\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n numeric?: boolean\n placeholder?: string | undefined\n onEdit(text: string): void\n onReset(): void\n t: Translate<SettingsCommandCodeKey>\n}) {\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor={id}>{label}</label>\n <span className=\"cc-badges\">\n {state.overridden ? <span className=\"cc-badge\">{t('overridden')}</span> : null}\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onReset} aria-label={`${label} — ${t('reset')}`}>{t('reset')}</button>\n </span>\n </div>\n <input\n id={id}\n className={state.invalid ? 'cc-input cc-inputInvalid' : 'cc-input'}\n type=\"text\"\n inputMode={numeric ? 'numeric' : undefined}\n value={state.text}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.value)}\n />\n <p className={state.invalid ? 'cc-invalid' : 'cc-hint'}>\n {state.invalid ? invalidCopy(state.invalidReason, t) : hint}\n </p>\n </div>\n )\n}\n\n/** The per-field error copy for a staged draft's failure reason. */\nfunction invalidCopy(reason: StagedField['invalidReason'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'tooSmall') return t('numberTooSmall')\n if (reason === 'tooLarge') return t('numberTooLarge')\n return t('invalidNumber')\n}\n\n/**\n * The collapsed \"Advanced\" card: API base, working dir, both timeouts, the\n * plan filter, the web-search backend and the sidebar quota card live here so\n * the page leads with the facts a user actually touches. Starts collapsed on\n * every visit; expands on demand. While collapsed, a badge names the\n * customized count so a nonzero override stays visible (a number field's error\n * blocks save and must be reachable).\n */\nfunction AdvancedSection({\n state,\n disabled,\n t,\n onEdit,\n onReset,\n}: {\n state: SettingsPageState\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onEdit(field: string, text: string): void\n onReset(field: string): void\n}) {\n const [expanded, setExpanded] = useState(false)\n const overridden = ADVANCED_FIELDS.filter((field) => state[field].overridden).length\n const invalid = ADVANCED_FIELDS.some((field) => state[field].invalid)\n return (\n <div className=\"cc-card\">\n <button\n type=\"button\"\n className=\"cc-advancedHead\"\n aria-expanded={expanded}\n aria-controls=\"cc-advanced-body\"\n onClick={() => setExpanded((value) => !value)}\n >\n <span className=\"cc-advancedTitle\">{t('advancedSettings')}</span>\n {overridden > 0 ? (\n <span className=\"cc-badge\">\n {overridden === 1 ? t('advancedOverriddenOne') : t('advancedOverriddenMany', { count: overridden })}\n </span>\n ) : null}\n {/* An invalid number blocks save while collapsed with no visible cue\n — surface it on the header so the blocker is reachable. */}\n {!expanded && invalid ? (\n <span className=\"cc-badge cc-badgeWarn\">{t('advancedInvalid')}</span>\n ) : null}\n <span className=\"cc-advancedSpacer\" />\n <span className={expanded ? 'cc-chevron cc-chevronUp' : 'cc-chevron'} aria-hidden=\"true\" />\n </button>\n {expanded ? (\n <div id=\"cc-advanced-body\" className=\"cc-advancedBody\">\n <p className=\"cc-hint\">{t('advancedSettingsHint')}</p>\n <Field\n id=\"cc-api-base\"\n label={t('apiBase')}\n hint={t('apiBaseHint')}\n state={state.apiBase}\n disabled={disabled}\n onEdit={(text) => onEdit('apiBase', text)}\n onReset={() => onReset('apiBase')}\n t={t}\n />\n <Field\n id=\"cc-working-dir\"\n label={t('workingDir')}\n hint={t('workingDirHint')}\n state={state.workingDir}\n disabled={disabled}\n placeholder={state.defaultWorkingDir}\n onEdit={(text) => onEdit('workingDir', text)}\n onReset={() => onReset('workingDir')}\n t={t}\n />\n <Field\n id=\"cc-request-timeout\"\n label={t('requestTimeoutMs')}\n hint={t('requestTimeoutMsHint')}\n state={state.requestTimeoutMs}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('requestTimeoutMs', text)}\n onReset={() => onReset('requestTimeoutMs')}\n t={t}\n />\n <Field\n id=\"cc-stream-idle-timeout\"\n label={t('streamIdleTimeoutMs')}\n hint={t('streamIdleTimeoutMsHint')}\n state={state.streamIdleTimeoutMs}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('streamIdleTimeoutMs', text)}\n onReset={() => onReset('streamIdleTimeoutMs')}\n t={t}\n />\n <Field\n id=\"cc-transport-max-retries\"\n label={t('transportMaxRetries')}\n hint={t('transportMaxRetriesHint')}\n state={state.transportMaxRetries}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('transportMaxRetries', text)}\n onReset={() => onReset('transportMaxRetries')}\n t={t}\n />\n <ToggleField\n id=\"cc-filter-models-by-plan\"\n label={t('filterModelsByPlan')}\n hint={t('filterModelsByPlanHint')}\n state={state.filterModelsByPlan}\n disabled={disabled}\n defaultChecked\n onEdit={(text) => onEdit('filterModelsByPlan', text)}\n onReset={() => onReset('filterModelsByPlan')}\n t={t}\n />\n <ToggleField\n id=\"cc-web-search\"\n label={t('webSearch')}\n hint={t('webSearchHint')}\n state={state.webSearch}\n disabled={disabled}\n defaultChecked\n onEdit={(text) => onEdit('webSearch', text)}\n onReset={() => onReset('webSearch')}\n t={t}\n />\n {/* Opt-in, and off by default: the sidebar quota card is a display\n surface, so an unset document shows nothing on the left. */}\n <ToggleField\n id=\"cc-show-sidebar-quota\"\n label={t('showSidebarQuota')}\n hint={t('showSidebarQuotaHint')}\n state={state.showSidebarQuota}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('showSidebarQuota', text)}\n onReset={() => onReset('showSidebarQuota')}\n t={t}\n />\n {/* The command guard: also opt-in and off by default. It is the one\n field here whose decision can skip an approval the user would\n otherwise have seen, and it sends the command text to a model\n with no ZDR upstream — so it starts off, and the two knobs that\n bound it sit right under it. */}\n <ToggleField\n id=\"cc-command-guard\"\n label={t('commandGuard')}\n hint={t('commandGuardHint')}\n state={state.commandGuard}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('commandGuard', text)}\n onReset={() => onReset('commandGuard')}\n t={t}\n />\n <Field\n id=\"cc-command-guard-threshold\"\n label={t('commandGuardThreshold')}\n hint={t('commandGuardThresholdHint')}\n state={state.commandGuardThreshold}\n disabled={disabled}\n onEdit={(text: string) => onEdit('commandGuardThreshold', text)}\n onReset={() => onReset('commandGuardThreshold')}\n t={t}\n />\n <Field\n id=\"cc-command-guard-timeout\"\n label={t('commandGuardTimeoutMs')}\n hint={t('commandGuardTimeoutMsHint')}\n state={state.commandGuardTimeoutMs}\n disabled={disabled}\n numeric\n onEdit={(text: string) => onEdit('commandGuardTimeoutMs', text)}\n onReset={() => onReset('commandGuardTimeoutMs')}\n t={t}\n />\n {/* Zero data retention: opt-in and off by default, for the opposite\n reason from the guard — this one protects the request, and the\n lever (which upstream serves it, and what it costs) is invisible\n to the user until the bill arrives. The per-model exclusion list\n lives on the Host, so the toggle needs no model picker. */}\n <ToggleField\n id=\"cc-zdr\"\n label={t('zdr')}\n hint={t('zdrHint')}\n state={state.zdr}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('zdr', text)}\n onReset={() => onReset('zdr')}\n t={t}\n />\n </div>\n ) : null}\n {expanded && invalid ? (\n <p className=\"cc-invalid\" role=\"status\">{t('advancedInvalid')}</p>\n ) : null}\n </div>\n )\n}\n\n/**\n * One boolean field row rendered as a toggle. The staged text is `'true'` /\n * `'false'` / `''` (unset → `defaultChecked`); toggling stages the string the\n * boolean field spec parses back into a real boolean on save.\n */\nfunction ToggleField({\n id,\n label,\n hint,\n state,\n disabled,\n defaultChecked,\n onEdit,\n onReset,\n t,\n}: {\n id: string\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n defaultChecked: boolean\n onEdit(text: string): void\n onReset(): void\n t: Translate<SettingsCommandCodeKey>\n}) {\n const checked = state.text === '' ? defaultChecked : state.text === 'true'\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n {/* Plain text (not a second label): the toggle input below already\n has its accessible name from the wrapping label. */}\n <span className=\"cc-label\" aria-hidden=\"true\">{label}</span>\n <span className=\"cc-badges\">\n {state.overridden ? <span className=\"cc-badge\">{t('overridden')}</span> : null}\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onReset} aria-label={`${label} — ${t('reset')}`}>{t('reset')}</button>\n </span>\n </div>\n <label className=\"cc-toggleRow\">\n <input\n id={id}\n className=\"cc-toggle\"\n type=\"checkbox\"\n role=\"switch\"\n checked={checked}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.checked ? 'true' : 'false')}\n />\n <span className=\"cc-hint\">{hint}</span>\n </label>\n </div>\n )\n}\n\n/**\n * The API-key control: write-only, reports configured state, never echoes the\n * key. The input is masked by default with a Show/Hide toggle so a pasted key\n * can be spot-checked without leaving the field, and a stored key can be\n * staged for removal (the next save unsets it) when it is bad or unwanted.\n */\nfunction SecretKeyField({\n label,\n hint,\n state,\n disabled,\n configured,\n configuredLabel,\n unconfiguredLabel,\n clearStaged,\n showLabel,\n hideLabel,\n clearLabel,\n clearStagedLabel,\n undoClearLabel,\n onEdit,\n onToggleClear,\n}: {\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n configured: boolean\n configuredLabel: string\n unconfiguredLabel: string\n clearStaged: boolean\n showLabel: string\n hideLabel: string\n clearLabel: string\n clearStagedLabel: string\n undoClearLabel: string\n onEdit(text: string): void\n onToggleClear(): void\n}) {\n const [visible, setVisible] = useState(false)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor=\"cc-api-key\">{label}</label>\n <span className=\"cc-badges\">\n <span className={configured ? 'cc-badge' : 'cc-badgeMuted'}>\n {configured ? configuredLabel : unconfiguredLabel}\n </span>\n {clearStaged ? <span className=\"cc-badge cc-badgeWarn\">{clearStagedLabel}</span> : null}\n {configured ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onToggleClear}>\n {clearStaged ? undoClearLabel : clearLabel}\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={disabled}\n onClick={() => setVisible((value) => !value)}\n >\n {visible ? hideLabel : showLabel}\n </button>\n </span>\n </div>\n <input\n id=\"cc-api-key\"\n className=\"cc-input\"\n type={visible ? 'text' : 'password'}\n autoComplete=\"off\"\n spellCheck={false}\n value={state.text}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.value)}\n />\n <p className=\"cc-hint\">{hint}</p>\n </div>\n )\n}\n\n/** One stat tile in the account card's summary grid. */\nfunction UsageStat({ label, value, sub }: { label: string; value: string; sub?: string | undefined }) {\n return (\n <div className=\"cc-usageStat\">\n <span className=\"cc-usageStatLabel\">{label}</span>\n <span className=\"cc-usageStatValue\">{value}</span>\n {sub !== undefined && sub !== '' ? <span className=\"cc-usageStatSub\">{sub}</span> : null}\n </div>\n )\n}\n\n/** One window-limit row: label, used/cap, a fill bar, and the reset time. */\nfunction UsageWindow({\n label,\n limit,\n t,\n}: {\n label: string\n limit: NonNullable<CommandCodeCredits['fiveHour']>\n t: Translate<SettingsCommandCodeKey>\n}) {\n const { used, cap, exceeded, resetAt } = limit\n const ratio = windowRatio(used, cap)\n const reset = formatResetAt(resetAt)\n return (\n <div className=\"cc-usageWindow\">\n <div className=\"cc-usageWindowHead\">\n <span className=\"cc-usageWindowLabel\">{label}</span>\n {exceeded ? <span className=\"cc-usageExceeded\">{t('usageExceeded')}</span> : null}\n <span className=\"cc-usageWindowValue\">{cap > 0 ? `${formatMoney(used)} / ${formatMoney(cap)}` : formatMoney(used)}</span>\n </div>\n <div className=\"cc-usageBar\" role=\"progressbar\" aria-label={label} aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(ratio * 100)}>\n <div className={exceeded ? 'cc-usageBarFill cc-usageBarFillWarn' : 'cc-usageBarFill'} style={{ width: `${ratio * 100}%` }} />\n </div>\n {reset !== '' ? <p className=\"cc-usageWindowReset\">{t('usageReset')} {reset}</p> : null}\n </div>\n )\n}\n\n/** One account's rotation state as a short badge next to its label. */\nfunction AccountMark({ entry, t }: { entry: CommandCodeAccountUsage; t: Translate<SettingsCommandCodeKey> }) {\n if (entry.active) return <span className=\"cc-usagePlan\">{t('usageActive')}</span>\n if (entry.mark === 'invalid-credential') return <span className=\"cc-usagePlanStatus\">{t('usageInvalidKey')}</span>\n if (entry.cooldownUntil > 0) {\n return <span className=\"cc-usagePlanStatus\">{t('usageCooldown')} {formatResetAt(entry.cooldownUntil)}</span>\n }\n if (entry.mark === 'rate-limit') return <span className=\"cc-usagePlanStatus\">{t('usageCooldown')}</span>\n return null\n}\n\n/**\n * One pool account's facts (identity, totals, credits, window limits)\n * rendered inside the account-usage card.\n */\nfunction AccountReport({ entry, fetchedAt, t, onRemove }: {\n entry: CommandCodeAccountUsage\n /**\n * When the shared usage snapshot was fetched — shares the account's bottom\n * meta row with the billing period end so the two timestamps occupy one\n * line (period/partial facts left, fetch freshness right).\n */\n fetchedAt?: number | undefined\n t: Translate<SettingsCommandCodeKey>\n /** Present only for removable (non-default) accounts on a writable page. */\n onRemove?: (() => void) | undefined\n}) {\n const report = entry.report\n const account = report.account\n const accountName = account === undefined ? '' : account.userName || account.name\n const credits = report.credits\n const plan = report.plan\n const planName = plan?.name ?? ''\n const planStatus = plan !== undefined && plan.status !== '' && plan.status !== 'active' ? plan.status : ''\n const showPeriod = plan !== undefined && plan.currentPeriodEnd > 0\n const showPartial = report.failures.length > 0 && report.blocked === undefined\n\n return (\n <div className=\"cc-accountReport\">\n <div className=\"cc-usageHead\">\n <h4 className=\"cc-usageTitle\">{entry.label}</h4>\n <AccountMark entry={entry} t={t} />\n {accountName !== '' ? <span className=\"cc-usageAccount\">{accountName}</span> : null}\n {planName !== '' ? <span className=\"cc-usagePlan\">{planName}</span> : null}\n {planStatus !== '' ? <span className=\"cc-usagePlanStatus\">{planStatus}</span> : null}\n <span className=\"cc-usageMetaSpacer\" />\n {onRemove !== undefined ? (\n <button type=\"button\" className=\"cc-usageRefresh\" onClick={onRemove}>{t('accountRemove')}</button>\n ) : null}\n </div>\n\n {!entry.configured ? <p className=\"cc-usageHint\">{t('usageUnconfigured')}</p> : null}\n\n {report.blocked !== undefined ? (\n <div className=\"cc-usageBlocked\" role=\"alert\">\n <p className=\"cc-usageBlockedTitle\">{blockedTitle(report.blocked, t)}</p>\n <p className=\"cc-usageBlockedHint\">{blockedHint(report.blocked, t)}</p>\n {/* Keep the per-endpoint failures visible alongside the summary:\n they carry the actual status or transport error for diagnosis. */}\n {report.failures.length > 0 ? (\n <p className=\"cc-usageBlockedDetail\" title={report.failures.join('; ')}>\n {report.failures.join(' · ')}\n </p>\n ) : null}\n </div>\n ) : null}\n\n {report.usage !== undefined ? (\n <div className=\"cc-usageStats\">\n <UsageStat\n label={t('usageRequests')}\n value={String(report.usage.completedCount)}\n sub={`${t('usageFailed')} ${report.usage.failedCount}`}\n />\n <UsageStat label={t('usageSuccessRate')} value={`${formatSuccessRate(report.usage.successRate)}%`} />\n <UsageStat\n label={t('usageCost')}\n value={formatMoneyExact(report.usage.totalCost)}\n sub={`${formatMoney(report.usage.totalCredits)} credits`}\n />\n <UsageStat\n label={t('usageTokens')}\n value={formatTokensCompact(report.usage.totalTokensIn + report.usage.totalTokensOut)}\n sub={`${formatTokensCompact(report.usage.totalTokensIn)} ${t('usageTokensIn')} / ${formatTokensCompact(report.usage.totalTokensOut)} ${t('usageTokensOut')}`}\n />\n </div>\n ) : null}\n\n {credits !== undefined ? (\n <div className=\"cc-usageStats\">\n <UsageStat label={t('usageMonthly')} value={credits.monthlyReported === false ? '—' : formatMoney(credits.monthlyCredits)} />\n <UsageStat label={t('usagePurchased')} value={credits.purchasedReported === false ? '—' : formatMoney(credits.purchasedCredits)} />\n <UsageStat label={t('usageFree')} value={credits.freeReported === false ? '—' : formatMoney(credits.freeCredits)} />\n </div>\n ) : null}\n\n {credits?.fiveHour !== undefined || credits?.weekly !== undefined ? (\n <div className=\"cc-usageWindows\">\n {credits.fiveHour !== undefined ? (\n <UsageWindow label={t('usageFiveHour')} limit={credits.fiveHour} t={t} />\n ) : null}\n {credits.weekly !== undefined ? (\n <UsageWindow label={t('usageWeekly')} limit={credits.weekly} t={t} />\n ) : null}\n </div>\n ) : null}\n\n {showPeriod || showPartial || fetchedAt !== undefined ? (\n <div className=\"cc-usageMeta\">\n {showPeriod ? (\n <p className=\"cc-usageUpdated\">{t('usagePeriodEnd')} {new Date(plan.currentPeriodEnd).toLocaleDateString()}</p>\n ) : null}\n {showPartial ? (\n <p className=\"cc-usagePartial\" title={report.failures.join('; ')}>{t('usagePartial')}</p>\n ) : null}\n <span className=\"cc-usageMetaSpacer\" />\n {fetchedAt !== undefined ? (\n <p className=\"cc-usageUpdated\">{t('usageUpdated')} {new Date(fetchedAt).toLocaleTimeString()}</p>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n\n/** The headline copy for a report whose every endpoint failed the same way. */\nfunction blockedTitle(reason: CommandCodeUsageReport['blocked'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'invalid-key') return t('usageKeyInvalid')\n if (reason === 'service-unavailable') return t('usageServiceUnavailable')\n if (reason === 'invalid-response') return t('usageInvalidResponse')\n return t('usageNetworkError')\n}\n\n/** The actionable hint under a blocked report's headline. */\nfunction blockedHint(reason: CommandCodeUsageReport['blocked'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'invalid-key') return t('usageKeyInvalidHint')\n if (reason === 'service-unavailable') return t('usageServiceUnavailableHint')\n if (reason === 'invalid-response') return t('usageInvalidResponseHint')\n return t('usageNetworkHint')\n}\n\n/** The status dot on an account tab: cooling/invalid warn, everything else ok. */\nfunction AccountTabDot({ entry }: { entry: CommandCodeAccountUsage }) {\n const cls = entry.mark === 'invalid-credential'\n ? 'cc-tabDot cc-tabDotError'\n : entry.mark !== '' || entry.cooldownUntil > 0\n ? 'cc-tabDot cc-tabDotWarn'\n : 'cc-tabDot cc-tabDotOk'\n // Decorative: the tab's text label already carries the account identity.\n return <span className={cls} aria-hidden=\"true\" />\n}\n\n/**\n * The account-usage card: the `/commandcode` dashboard's facts rendered as\n * a native settings card. With several accounts the card is a carousel — a\n * tab strip (label + status dot) switches between accounts so the page stays\n * short; each account's report carries its own remove affordance (the\n * default account is not removable). Accounts staged for removal in the\n * management card are hidden here immediately. Data arrives through the\n * `commandcode/report` Remote; the API keys never leave the Host.\n */\nfunction UsageCard({ t, usage, removingIds, removableIds, canManage, onRefresh, onRemoveAccount }: {\n t: Translate<SettingsCommandCodeKey>\n usage: UsagePageState\n /** Ids of accounts staged for removal (hidden from the carousel). */\n removingIds: string[]\n /**\n * Ids of accounts the settings document can actually remove (the stored\n * extra accounts' refs). Composition-only accounts (literal-key slots with\n * positional `account-N` ids) are NOT removable from the page — the\n * settings document cannot name them — so they get no remove button.\n */\n removableIds: string[]\n /** Whether the page accepts writes (the remove affordance follows it). */\n canManage: boolean\n onRefresh(): void\n onRemoveAccount(id: string): void\n}) {\n const { loading, shouldRefresh, noKey } = usageCardState(usage)\n // Ask the Host on first paint: CLI auth and composition keys are not\n // represented by browser credential references. Later failures retry manually.\n useEffect(() => {\n if (shouldRefresh) onRefresh()\n }, [shouldRefresh, onRefresh])\n\n const report = usage.report\n // Locally remembered removals: the usage controller keeps the old report\n // until the post-save refresh lands, and removedRefs clears at save-land —\n // without this the just-removed account would pop back in for one refresh\n // round-trip. Cleared when a fresh report arrives (fetchedAt changes).\n const [locallyRemoved, setLocallyRemoved] = useState<readonly string[]>([])\n useEffect(() => {\n setLocallyRemoved([])\n }, [usage.fetchedAt])\n const hidden = new Set([...removingIds, ...locallyRemoved])\n const seenIds = new Set<string>()\n const entries = (report?.accounts ?? []).filter((entry) => {\n if (hidden.has(entry.id)) return false\n // Hand-edited settings can name the same credential ref twice; dedupe so\n // the tab strip never carries duplicate keys/selections.\n if (seenIds.has(entry.id)) return false\n seenIds.add(entry.id)\n return true\n })\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\n // The selected tab: the explicit choice while it still exists, else the\n // serving (active) account, else the first entry.\n const selected = entries.find((entry) => entry.id === selectedId)\n ?? entries.find((entry) => entry.active)\n ?? entries[0]\n const removeSelected = canManage && selected !== undefined && removableIds.includes(selected.id)\n ? () => {\n const id = selected.id\n setLocallyRemoved((prev) => [...prev, id])\n onRemoveAccount(id)\n }\n : undefined\n\n return (\n <div className=\"cc-usageCard\" aria-label={t('usageTitle')}>\n <div className=\"cc-usageHead\">\n <h3 className=\"cc-usageTitle\">{t('usageTitle')}</h3>\n <span className=\"cc-usageMetaSpacer\" />\n <button type=\"button\" className=\"cc-usageRefresh\" disabled={loading} onClick={onRefresh}>\n {loading ? t('usageRefreshing') : t('usageRefresh')}\n </button>\n </div>\n\n {noKey ? <p className=\"cc-usageHint\">{t('usageNoKey')}</p> : null}\n {report === undefined && loading ? <p className=\"cc-usageHint\">{t('usageLoading')}</p> : null}\n {usage.status === 'error' ? (\n <p className=\"cc-usageError\" role=\"status\">\n <span>{t('usageError')}{usage.error !== undefined && usage.error !== '' ? ` — ${usage.error}` : ''}</span>\n </p>\n ) : null}\n\n {/* Plain buttons, not tabs: each switches the visible account panel\n without a tabpanel/keyboard-tab contract to uphold. */}\n {entries.length > 1 ? (\n <div className=\"cc-tabs\" aria-label={t('accountsTitle')}>\n {entries.map((entry) => (\n <button\n key={entry.id}\n type=\"button\"\n aria-pressed={selected?.id === entry.id}\n className={selected?.id === entry.id ? 'cc-tab cc-tabActive' : 'cc-tab'}\n onClick={() => setSelectedId(entry.id)}\n >\n <AccountTabDot entry={entry} />\n {entry.label}\n </button>\n ))}\n </div>\n ) : null}\n\n {selected !== undefined ? (\n <AccountReport\n key={selected.id}\n entry={selected}\n fetchedAt={usage.fetchedAt}\n t={t}\n onRemove={removeSelected}\n />\n ) : null}\n </div>\n )\n}\n\n/**\n * One extra account row: label, key, configured badge. Saved accounts are\n * removed from the usage card above; a NOT-YET-SAVED addition never appears\n * there (the usage report is Host-side), so it keeps its own remove button —\n * otherwise the only way to undo a mistaken Add would be discarding every\n * other staged edit.\n */\nfunction AccountRow({ account, disabled, t, onLabel, onKey, onToggleClear, onRemove }: {\n account: AccountItemState\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onLabel(text: string): void\n onKey(text: string): void\n onToggleClear(): void\n onRemove(): void\n}) {\n const locked = !account.writable\n const [keyVisible, setKeyVisible] = useState(false)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor={`cc-account-label-${account.id}`}>{t('accountLabel')}</label>\n <span className=\"cc-badges\">\n {account.added ? <span className=\"cc-badge\">{t('unsaved')}</span> : null}\n <span className={account.configured ? 'cc-badge' : 'cc-badgeMuted'}>\n {account.configured ? t('apiKeySet') : t('apiKeyUnset')}\n </span>\n {account.clearStaged ? <span className=\"cc-badge cc-badgeWarn\">{t('usageKeyClearStaged')}</span> : null}\n {account.configured && !account.clearStaged ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onToggleClear}>\n {t('usageKeyClear')}\n </button>\n ) : null}\n {account.clearStaged ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onToggleClear}>\n {t('usageUndoKeyClear')}\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={disabled}\n onClick={() => setKeyVisible((value) => !value)}\n >\n {keyVisible ? t('hide') : t('show')}\n </button>\n {account.added ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onRemove}>{t('accountRemove')}</button>\n ) : null}\n </span>\n </div>\n <input\n id={`cc-account-label-${account.id}`}\n className=\"cc-input\"\n type=\"text\"\n value={account.label}\n disabled={disabled}\n onChange={(event) => onLabel(event.target.value)}\n />\n <input\n id={`cc-account-key-${account.id}`}\n className=\"cc-input\"\n type={keyVisible ? 'text' : 'password'}\n autoComplete=\"off\"\n spellCheck={false}\n placeholder={t('accountKey')}\n value={account.keyText}\n disabled={disabled || locked}\n onChange={(event) => onKey(event.target.value)}\n />\n <p className=\"cc-hint\">{locked ? t('apiKeyLocked') : t('accountKeyHint')}</p>\n </div>\n )\n}\n\n/** The multi-account card: the active-account selector + extra accounts in rotation order + add button. */\nfunction AccountsCard({ t, state, login, disabled, onAdd, onRemove, onLabel, onKey, onToggleClear, onActive, onActiveReset, onBeginLogin, onCancelLogin }: {\n t: Translate<SettingsCommandCodeKey>\n state: SettingsPageState\n login: LoginPageState\n disabled: boolean\n onAdd(): void\n onRemove(id: string): void\n onLabel(id: string, text: string): void\n onKey(id: string, text: string): void\n onToggleClear(id: string): void\n onActive(text: string): void\n onActiveReset(): void\n onBeginLogin(ref: string): void\n onCancelLogin(): void\n}) {\n const active = state.activeAccount\n return (\n <div className=\"cc-card\" aria-label={t('accountsTitle')}>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\">{t('accountsTitle')}</label>\n <span className=\"cc-badges\">\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onAdd}>{t('accountAdd')}</button>\n </span>\n </div>\n <p className=\"cc-hint\">{t('accountsHint')}</p>\n </div>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor=\"cc-active-account\">{t('activeAccount')}</label>\n <span className=\"cc-badges\">\n {active.overridden ? <span className=\"cc-badge\">{t('overridden')}</span> : null}\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onActiveReset}>{t('reset')}</button>\n </span>\n </div>\n <select\n id=\"cc-active-account\"\n className=\"cc-input\"\n value={active.text}\n disabled={disabled}\n onChange={(event) => onActive(event.target.value)}\n >\n <option value=\"\">{t('activeAccountAuto')}</option>\n <option value=\"default\">{t('accountDefault')}</option>\n {state.accounts.filter((account) => !account.added).map((account) => (\n <option key={account.id} value={account.ref}>{account.label}</option>\n ))}\n </select>\n <p className=\"cc-hint\">{t('activeAccountHint')}</p>\n </div>\n {state.accounts.map((account) => (\n <div key={account.id} className=\"cc-accountEditor\">\n <AccountRow\n account={account}\n disabled={disabled || (login.targetRef === account.ref && (login.phase === 'starting' || login.phase === 'waiting'))}\n t={t}\n onLabel={(text) => onLabel(account.id, text)}\n onKey={(text) => onKey(account.id, text)}\n onToggleClear={() => onToggleClear(account.id)}\n onRemove={() => onRemove(account.id)}\n />\n {account.added ? (\n <div className=\"cc-accountLoginHint\">\n <p className=\"cc-hint\">{t('accountLoginAfterSave')}</p>\n </div>\n ) : (\n <LoginRow\n state={login}\n targetRef={account.ref}\n disabled={disabled || !account.writable || state.dirty}\n disabledHint={state.dirty ? t('loginSaveBefore') : undefined}\n t={t}\n onBegin={() => onBeginLogin(account.ref)}\n onCancel={onCancelLogin}\n />\n )}\n </div>\n ))}\n </div>\n )\n}\n\n/** One model → account routing rule row. */\nfunction RuleRow({ rule, accounts, catalog, disabled, t, onModels, onAccount, onRemove }: {\n rule: RuleItemState\n accounts: AccountItemState[]\n catalog: CatalogModelOption[]\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onModels(ids: string[]): void\n onAccount(text: string): void\n onRemove(): void\n}) {\n const targets = [\n { value: 'default', label: t('accountDefault') },\n ...accounts.filter((account) => !account.added).map((account) => ({ value: account.ref, label: account.label })),\n ]\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor={`cc-rule-model-${rule.id}`}>{t('ruleModel')}</label>\n <span className=\"cc-badges\">\n {rule.added ? <span className=\"cc-badge\">{t('unsaved')}</span> : null}\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onRemove}>{t('ruleRemove')}</button>\n </span>\n </div>\n <ModelMultiSelect\n id={`cc-rule-model-${rule.id}`}\n selected={rule.models}\n catalog={catalog}\n disabled={disabled}\n t={t}\n onSelect={onModels}\n />\n <select\n id={`cc-rule-account-${rule.id}`}\n className=\"cc-input\"\n value={rule.account}\n disabled={disabled}\n onChange={(event) => onAccount(event.target.value)}\n aria-label={t('ruleAccount')}\n >\n {targets.map((target) => (\n <option key={target.value} value={target.value}>{target.label}</option>\n ))}\n </select>\n <p className=\"cc-hint\">{t('ruleHint')}</p>\n </div>\n )\n}\n\n/**\n * A checkbox multi-select dropdown for picking catalog models (the\n * routing-rule rows and the visible-models filter share it). The trigger\n * shows the selection count; the Menu lists every catalog model with a\n * checkbox, toggled by clicking the row. A search box under the trigger\n * (inside the Menu anchor, so focusing it never trips the outside-click\n * close) filters the list by id/display-name substring, and items group\n * under plan-tier headings in picker order. Selected ids the catalog no\n * longer carries still render — flagged stale — so a saved selection never\n * silently loses an entry, and the VisibleModelsCard offers a one-click\n * cleanup.\n */\nfunction ModelMultiSelect({ id, selected, catalog, disabled, t, onSelect }: {\n id: string\n selected: string[]\n catalog: CatalogModelOption[]\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onSelect(ids: string[]): void\n}) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n // The search box must not inherit a stale query from a previous open.\n useEffect(() => {\n if (open) setQuery('')\n }, [open])\n // Tier headings come from the catalog entries themselves (the Host stamps\n // each entry's plan-tier key on the Remote); rebuild only when the catalog\n // changes.\n const tiers = useMemo(\n () => Object.fromEntries(\n catalog.flatMap((model) => model.tier === undefined ? [] : [[model.id, model.tier] as const]),\n ),\n [catalog],\n )\n // The catalog is sorted for picking; append any selected ids the catalog no\n // longer carries (removed upstream) so the current selection stays visible.\n const options = buildModelSelectOptions(catalog, selected, query)\n const groups = groupModelSelectOptions(options, (modelId) => tierHeadingFor(modelId, tiers))\n const items: MenuEntry[] = groups.flatMap((group) => [\n ...(group.heading === undefined\n ? []\n : [{ type: 'label' as const, id: `cc-tier-${group.heading}`, text: group.heading }]),\n ...group.options.map((option) => ({\n id: option.value,\n label: (\n <span className=\"cc-checkRow\">\n <input\n type=\"checkbox\"\n className=\"cc-check\"\n checked={selected.includes(option.value)}\n readOnly\n tabIndex={-1}\n />\n <span className=\"cc-checkName\">{option.label}</span>\n {option.stale ? <span className=\"cc-badge\">{t('modelStale')}</span> : null}\n </span>\n ),\n })),\n ])\n // The search box lives INSIDE the Menu anchor (which renders in place\n // inside the Menu's root span): a pointerdown there counts as \"inside\",\n // so focusing/typing never trips the Menu's outside-click close. A box\n // rendered as a sibling would close the Menu on the first click.\n return (\n <Menu\n open={open}\n onClose={() => setOpen(false)}\n onSelect={(modelId) => {\n onSelect(toggleModelSelection(selected, modelId))\n }}\n selectedIds={selected}\n items={items}\n footer={options.length === 0 ? [{\n type: 'label' as const,\n id: 'cc-model-search-empty',\n text: t('modelSearchEmpty'),\n }] : []}\n portal\n anchor={\n <span className=\"cc-modelSelectAnchor\">\n <button\n id={id}\n type=\"button\"\n className=\"cc-input cc-ruleTrigger\"\n disabled={disabled || catalog.length === 0}\n onClick={() => setOpen((value) => !value)}\n >\n <span className=\"cc-ruleTriggerText\">\n {selected.length === 0 ? t('ruleModelPick') : t('ruleModelCount', { count: selected.length })}\n </span>\n <span className=\"cc-ruleCaret\" aria-hidden=\"true\" />\n </button>\n {open ? (\n <input\n type=\"search\"\n className=\"cc-input cc-modelSearch\"\n placeholder={t('modelSearchPlaceholder')}\n aria-label={t('modelSearchPlaceholder')}\n value={query}\n disabled={disabled}\n autoFocus\n onChange={(event) => setQuery(event.target.value)}\n />\n ) : null}\n </span>\n }\n />\n )\n}\n\n/** The model → account routing card: rules in list order (first match wins). */\nfunction RulesCard({ t, state, disabled, onAdd, onRemove, onModels, onAccount }: {\n t: Translate<SettingsCommandCodeKey>\n state: SettingsPageState\n disabled: boolean\n onAdd(): void\n onRemove(id: string): void\n onModels(id: string, ids: string[]): void\n onAccount(id: string, text: string): void\n}) {\n return (\n <div className=\"cc-card\" aria-label={t('rulesTitle')}>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\">{t('rulesTitle')}</label>\n <span className=\"cc-badges\">\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onAdd}>{t('ruleAdd')}</button>\n </span>\n </div>\n <p className=\"cc-hint\">{t('rulesHint')}</p>\n {state.catalogFailed ? <p className=\"cc-invalid\">{t('rulesCatalogFailed')}</p> : null}\n </div>\n {state.rules.map((rule) => (\n <RuleRow\n key={rule.id}\n rule={rule}\n accounts={state.accounts}\n catalog={state.catalogModels}\n disabled={disabled}\n t={t}\n onModels={(ids) => onModels(rule.id, ids)}\n onAccount={(text) => onAccount(rule.id, text)}\n onRemove={() => onRemove(rule.id)}\n />\n ))}\n {state.rules.length === 0 ? <p className=\"cc-hint\">{t('rulesEmpty')}</p> : null}\n </div>\n )\n}\n\n/** The visible-model filter card: an allowlist over the catalog. Empty = show all. */\nfunction VisibleModelsCard({ t, state, disabled, onSelect, onClear }: {\n t: Translate<SettingsCommandCodeKey>\n state: SettingsPageState\n disabled: boolean\n onSelect(ids: string[]): void\n onClear(): void\n}) {\n const count = state.visibleModels.length\n const pickT: Translate<SettingsCommandCodeKey> = (key, params) => {\n if (key === 'ruleModelPick') return t('visibleModelsPick')\n if (key === 'ruleModelCount') return t('visibleModelsCount', params)\n return t(key, params)\n }\n // Selected ids the live catalog no longer carries (retired upstream):\n // kept, flagged stale in the dropdown, removable in one click. Never\n // auto-dropped — an empty catalog (fetch failure) must not wipe the list.\n // \"Stale\" is only meaningful against a catalog we actually hold, so both the\n // cleanup button and its hint are gated on catalogIsReady: before the first\n // fetch lands (and after a failure) the empty catalog makes every selection\n // look retired, turning the one-click cleanup into a button that silently\n // empties the allowlist. The explicit \"show all\" entry stays available\n // either way — clearing the list is then the user's stated intent rather\n // than an inference from missing data.\n const readiness = { catalogIds: state.catalogModels.map((model) => model.id), catalogFailed: state.catalogFailed }\n const staleIds = staleModelIds(state.visibleModels, readiness)\n const catalogReady = catalogIsReady(readiness)\n return (\n <div className=\"cc-card\" aria-label={t('visibleModelsTitle')}>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\">{t('visibleModelsTitle')}</label>\n <span className=\"cc-badges\">\n {catalogReady && staleIds.length > 0 ? (\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={disabled}\n onClick={() => onSelect(state.visibleModels.filter((id) => !staleIds.includes(id)))}\n >\n {t('visibleModelsCleanStale', { count: staleIds.length })}\n </button>\n ) : null}\n {count > 0 ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={onClear}>\n {t('visibleModelsShowAll')}\n </button>\n ) : null}\n </span>\n </div>\n <p className=\"cc-hint\">{t('visibleModelsHint')}</p>\n {state.catalogFailed ? <p className=\"cc-invalid\">{t('rulesCatalogFailed')}</p> : null}\n {staleIds.length > 0 && catalogReady ? (\n <p className=\"cc-hint\">{t('visibleModelsStaleHint', { count: staleIds.length })}</p>\n ) : null}\n <ModelMultiSelect\n id=\"cc-visible-models\"\n selected={state.visibleModels}\n catalog={state.catalogModels}\n disabled={disabled}\n t={pickT}\n onSelect={onSelect}\n />\n </div>\n </div>\n )\n}\n\n/**\n * Show the \"Saved ✓\" affordance for a short window after each accepted save.\n * The controller only counts saves (`savedCount`); the flash timing lives\n * here so the state machine stays timer-free.\n */\nfunction useSavedFlash(tick: number): boolean {\n const [visible, setVisible] = useState(false)\n useEffect(() => {\n if (tick === 0) return\n setVisible(true)\n const timer = setTimeout(() => setVisible(false), 2500)\n return () => clearTimeout(timer)\n }, [tick])\n return visible\n}\n\n/**\n * The update hint: one throttled npm-registry check per page open (the\n * throttle and all failure handling live in ./update.ts). Resolves to the\n * newest published version when it is newer than this build, else undefined —\n * every failure mode degrades to no hint at all.\n */\nfunction usePluginUpdate(): string | undefined {\n const [available, setAvailable] = useState<string | undefined>(undefined)\n useEffect(() => {\n let cancelled = false\n void checkForUpdate({\n currentVersion: PLUGIN_VERSION,\n now: Date.now(),\n store: localStorageUpdateStore(),\n }).then((version) => {\n if (!cancelled) setAvailable(version)\n // A rejected checkForUpdate would be a bug (it catches internally);\n // swallow it regardless — the footer must never break the page.\n }, () => {})\n return () => {\n cancelled = true\n }\n }, [])\n return available\n}\n\n/** The settings page body: connection facts for the Command Code provider. */\nexport function CommandCodeSettingsPage(props: CommandCodeSettingsProps) {\n const { t } = props\n const footerMarker = useRef<HTMLSpanElement>(null)\n const [footerFloating, setFooterFloating] = useState(false)\n const state = props.useCommandCodeSettings((snapshot) => snapshot)\n const usage = props.useCommandCodeUsage((snapshot) => snapshot)\n const login = props.useCommandCodeLogin((snapshot) => snapshot)\n const disabled = !state.writable\n const keyLocked = !state.apiKeyWritable\n const savedVisible = useSavedFlash(state.savedCount)\n const updateVersion = usePluginUpdate()\n useEffect(() => {\n const marker = footerMarker.current\n if (!marker || typeof IntersectionObserver === 'undefined') return\n const observer = new IntersectionObserver(([entry]) => {\n if (entry) setFooterFloating(!entry.isIntersecting)\n })\n observer.observe(marker)\n return () => observer.disconnect()\n }, [])\n return (\n <section className=\"cc-section\" aria-label={t('title')}>\n <h2 className=\"cc-title\">{t('title')}</h2>\n <p className=\"cc-intro\">{t('intro')}</p>\n {!state.writable ? <p className=\"cc-readOnly\" role=\"status\">{t('readOnly')}</p> : null}\n <UsageCard\n t={t}\n usage={usage}\n removingIds={state.accountsRemoving}\n removableIds={state.accounts.map((account) => account.id)}\n canManage={state.writable}\n onRefresh={props.refreshUsage}\n onRemoveAccount={props.removeAccount}\n />\n <AccountsCard\n t={t}\n state={state}\n login={login}\n disabled={disabled}\n onAdd={props.addAccount}\n onRemove={props.removeAccount}\n onLabel={props.editAccountLabel}\n onKey={props.editAccountKey}\n onToggleClear={(id) => props.toggleKeyClear(id)}\n onActive={(text) => props.edit('activeAccount', text)}\n onActiveReset={() => props.resetField('activeAccount')}\n onBeginLogin={props.beginLogin}\n onCancelLogin={props.cancelLogin}\n />\n <RulesCard\n t={t}\n state={state}\n disabled={disabled}\n onAdd={props.addRule}\n onRemove={props.removeRule}\n onModels={props.editRuleModels}\n onAccount={props.editRuleAccount}\n />\n <VisibleModelsCard\n t={t}\n state={state}\n disabled={disabled}\n onSelect={props.editVisibleModels}\n onClear={props.clearVisibleModels}\n />\n <div className=\"cc-card\">\n <SecretKeyField\n label={t('apiKey')}\n hint={keyLocked ? t('apiKeyLocked') : t('apiKeyHint')}\n state={state.apiKey}\n disabled={disabled || keyLocked || (login.targetRef === undefined && (login.phase === 'starting' || login.phase === 'waiting'))}\n configured={state.apiKeyConfigured}\n configuredLabel={t('apiKeySet')}\n unconfiguredLabel={t('apiKeyUnset')}\n clearStaged={state.apiKeyClearStaged}\n showLabel={t('show')}\n hideLabel={t('hide')}\n clearLabel={t('usageKeyClear')}\n clearStagedLabel={t('usageKeyClearStaged')}\n undoClearLabel={t('usageUndoKeyClear')}\n onEdit={(text) => props.edit('apiKey', text)}\n onToggleClear={() => props.toggleKeyClear('default')}\n />\n <LoginRow\n state={login}\n disabled={disabled || keyLocked || state.dirty}\n disabledHint={state.dirty ? t('loginSaveBefore') : undefined}\n t={t}\n onBegin={props.beginLogin}\n onCancel={props.cancelLogin}\n />\n </div>\n <AdvancedSection\n state={state}\n disabled={disabled}\n t={t}\n onEdit={props.edit}\n onReset={props.resetField}\n />\n <span ref={footerMarker} className=\"cc-footerMarker\" aria-hidden=\"true\" />\n <div className={`cc-footer cc-footerSticky${footerFloating ? ' cc-footerFloating' : ''}`}>\n <div className=\"cc-footerActions\">\n {state.failed ? <p className=\"cc-failed\" role=\"status\">{t('saveFailed')}</p> : null}\n {savedVisible ? <p className=\"cc-saved\" role=\"status\">{t('saved')}</p> : null}\n <Button variant=\"ghost\" size=\"sm\" disabled={!state.dirty || state.saving} onClick={props.discard}>\n {t('discard')}\n </Button>\n <Button\n variant=\"primary\"\n size=\"sm\"\n disabled={!state.dirty || state.invalid || state.saving}\n onClick={props.save}\n >\n {t(state.saving ? 'saving' : 'save')}\n </Button>\n </div>\n </div>\n <p className=\"cc-version\">\n Command Code Provider v{PLUGIN_VERSION}\n {updateVersion !== undefined ? (\n <>\n {' · '}\n <a\n className=\"cc-versionLink\"\n href={PLUGIN_RELEASES_URL}\n target=\"_blank\"\n rel=\"noreferrer\"\n title={t('updateHint')}\n >\n v{updateVersion} {t('updateAvailable')}\n </a>\n </>\n ) : null}\n </p>\n </section>\n )\n}\n","/**\n * The Command Code configuration panel inside the harness Models settings page\n * (browser half). Rendered through the `settings.models.provider-card` keyed\n * slot available in dsh 0.1.2 (rc.1), registered with\n * `entryKey = 'llm-commandcode'` (the plugin's settings namespace, the key the\n * Models page dispatches for every Command Code provider row).\n *\n * The official Models page opens one editor card per provider row through its\n * own 编辑 button. For a namespace the page does not curate a layout for\n * (`llm-commandcode`), that editor is a bare shell — a pointer to\n * `settings.yaml` above a permanently disabled apply button. This panel takes\n * its place: the slot outlet renders right beside the official editor inside\n * the same row card, so the component watches the outlet's siblings and, while\n * the official editor is open, hides the useless shell and shows the real\n * controls in its slot — the credential/route badges, the API-key field,\n * official sign-in, and the discard/save footer. Closed, it renders nothing\n * and the row looks exactly like any other provider row.\n *\n * The slot's owner props (`configured`, `keyConfigured`) mirror what the\n * Models page already knows; the authoritative credential facts still come\n * from this plugin's `CommandCodeSettingsController` shared with the dedicated\n * settings page, so the two surfaces can never disagree about whether a key\n * is stored.\n *\n * A controller-less render (panel mounted before the section registered its\n * inject face — the composition runs one apply) degrades to the stateless\n * registration notice inside the opened panel.\n *\n * Styles ride the page stylesheet the client entry injects once (`cc-`\n * prefixed classes); the card adds no CSS of its own.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport type { SettingsPageState, StagedField } from './settings.ts'\nimport type { LoginPageState } from './login.ts'\nimport { LoginRow } from './login-row.tsx'\n\n/**\n * The Models-page extension slots, merged into the SlotMap with the exact\n * declarations dsh 0.1.2 (rc.1)'s ui-settings-models ships. The merge must\n * stay structurally identical to upstream's (kind/scope/owner), or a future\n * dsh carrying its own declaration would fail the duplicate-merge check at\n * compile time.\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** One provider card's adapter extension area, keyed by the row's settingsNs. */\n 'settings.models.provider-card': { kind: 'keyed'; scope: 'root'; owner: ProviderCardExtrasOwnerProps }\n /** Ordered extension area after the provider rows and the add controls. */\n 'settings.models.footer': { kind: 'list'; scope: 'root'; owner: ModelsFooterOwnerProps }\n }\n}\n\n/** The provider directory row as the Models page dispatches it. */\nexport interface ProviderDirectoryRow {\n /** The provider route id (`commandcode` for this plugin). */\n readonly provider: string\n /** The row's display name. */\n readonly displayName: string\n /** The settings namespace the row configures (the slot's dispatch key). */\n readonly settingsNs: string\n /** The settings path the row's profile lives at. */\n readonly settingsPath: readonly string[]\n /** Whether the provider route is live. */\n readonly active: boolean\n /** Whether the adapter declares the route as shipped. */\n readonly declared?: boolean\n}\n\n/** Owner share of one provider-card extension occurrence (upstream's shape). */\nexport interface ProviderCardExtrasOwnerProps {\n /** The card's directory row. */\n readonly provider: ProviderDirectoryRow\n /** Whether any layer configures this provider (its profile resolves). */\n readonly configured: boolean\n /** The row's referenced api-key credential, confirmed configured by the page's join. */\n readonly keyConfigured: boolean\n}\n\n/** Owner share of the footer area (the section supplies nothing). */\nexport interface ModelsFooterOwnerProps {\n /** Marker field: footer owner props are intentionally empty. */\n children?: never\n}\n\n/** Owner props the Models page supplies at its dispatch sites. */\nexport type ProviderCardOwnerProps = ProviderCardExtrasOwnerProps\n\n/**\n * The slot whose outlet anchors this panel inside the Models row — the\n * renderer's own `data-slot` attribute value, stable across builds (unlike\n * CSS-module class hashes).\n */\nexport const CARD_SLOT_KEY = 'settings.models.provider-card'\n\n/** The DOM facts the sibling lookup reads (satisfied by real Elements). */\nexport interface SlotWrapperSiblings {\n previousElementSibling: { className: string } | null\n nextElementSibling: { className: string } | null\n}\n\n/**\n * Find the official editor card among the slot outlet's siblings, or null\n * while it is closed. The Models page renders the editor as an immediate\n * sibling of the outlet wrapper — after it in a provider row (the target of\n * the row's 编辑 toggle), before it in the first-run setup card and the\n * add-provider card, where it is always open. The editor is the only such\n * sibling whose CSS module class carries the `editor` stem\n * (`<hash>_editor`); the row header and the add card's provider select\n * never do, so the lookup needs no hash knowledge.\n */\nexport function adjacentEditorCard(wrapper: SlotWrapperSiblings | null): { className: string } | null {\n if (wrapper === null) return null\n for (const sibling of [wrapper.previousElementSibling, wrapper.nextElementSibling]) {\n if (sibling !== null && typeof sibling.className === 'string' && sibling.className.includes('editor')) {\n return sibling\n }\n }\n return null\n}\n\n/** The closed-panel style: the outlet stays mounted as the detection anchor. */\nconst HIDDEN_STYLE = { display: 'none' } as const\n\n/** Injected face the card's slot registration supplies. */\nexport interface CommandCodeCardProps {\n t: Translate<SettingsCommandCodeKey>\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n useCommandCodeLogin<T>(selector: (state: LoginPageState) => T): T\n edit(field: string, text: string): void\n save(): void\n discard(): void\n beginLogin(): void\n cancelLogin(): void\n}\n\n/** The card's two postures. */\ntype CardMode =\n | { kind: 'registration' }\n | { kind: 'live'; ready: boolean; controllerConfigured: boolean; writable: boolean; apiKeyWritable: boolean }\n\n/**\n * Decide the card's posture from one settings snapshot. Pure: the component\n * subscribes once and passes the snapshot in, so hook order never depends\n * on the registration→live transition. (The owner facts stay on the\n * component — only the snapshot decides the posture.)\n */\nexport function cardMode(\n snapshot: SettingsPageState | undefined,\n): CardMode {\n if (snapshot === undefined) return { kind: 'registration' }\n return {\n kind: 'live',\n ready: snapshot.available,\n controllerConfigured: snapshot.apiKeyConfigured,\n writable: snapshot.writable,\n apiKeyWritable: snapshot.apiKeyWritable,\n }\n}\n\n/** Status badge for the credential state (green when configured). */\nfunction StatusBadge({ ok, okLabel, pendingLabel }: {\n ok: boolean\n okLabel: string\n pendingLabel: string\n}) {\n return <span className={ok ? 'cc-badge' : 'cc-badgeMuted'}>{ok ? okLabel : pendingLabel}</span>\n}\n\n/** Compact key field for the not-configured card. */\nfunction CardKeyField({ state, disabled, t, onEdit }: {\n state: StagedField\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onEdit(text: string): void\n}) {\n const [visible, setVisible] = useState(false)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor=\"cc-card-api-key\">{t('apiKey')}</label>\n <span className=\"cc-badges\">\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={() => setVisible((value) => !value)}>\n {visible ? t('hide') : t('show')}\n </button>\n </span>\n </div>\n <input\n id=\"cc-card-api-key\"\n className=\"cc-input\"\n type={visible ? 'text' : 'password'}\n autoComplete=\"off\"\n spellCheck={false}\n value={state.text}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.value)}\n />\n <p className=\"cc-hint\">{t('apiKeyHint')}</p>\n </div>\n )\n}\n\n/**\n * The slot component body. Dispatched on every Command Code provider card of\n * the Models page (saved row, first-run setup posture, and add-provider\n * draft).\n *\n * Closed (the official 编辑 toggle off) the panel renders nothing: the row\n * head the Models page owns already names the provider and shows the\n * credential dot, so a page full of providers stays compact. Opening the\n * official editor mounts the editor shell as the outlet's sibling; the panel\n * watches for it, hides the shell (it carries only the settings.yaml hint and\n * a disabled apply for this namespace), and shows the real controls — badges,\n * API-key field, sign-in, discard/save.\n */\nexport function CommandCodeProviderCard(props: CommandCodeCardProps & ProviderCardOwnerProps) {\n const { t } = props\n // Single subscription: the whole snapshot drives posture + body together.\n const state = props.useCommandCodeSettings !== undefined\n ? props.useCommandCodeSettings((snapshot) => snapshot)\n : undefined\n const mode = cardMode(state)\n const login = props.useCommandCodeLogin !== undefined\n ? props.useCommandCodeLogin((snapshot) => snapshot)\n : undefined\n const dirty = state?.dirty ?? false\n const saving = state?.saving ?? false\n const invalid = state?.invalid ?? false\n const failed = state?.failed ?? false\n const savingBlocked = !dirty || invalid\n const configured = mode.kind === 'live' && mode.ready ? mode.controllerConfigured : props.keyConfigured\n const disabled = mode.kind === 'live' && (!mode.writable || (state !== undefined && !mode.apiKeyWritable))\n const showBody = mode.kind === 'live' && mode.ready && state !== undefined\n // The official editor's open state lives in the Models page's own component\n // state and never reaches this slot's props; the outlet wrapper is the\n // stable neighbor, so watch its siblings for the editor's mount/unmount.\n // The outlet stays mounted either way — it is the observation anchor — so\n // the closed panel hides its own root instead of unmounting.\n const rootRef = useRef<HTMLDivElement | null>(null)\n const [editorOpen, setEditorOpen] = useState(false)\n useEffect(() => {\n const root = rootRef.current\n if (root === null || typeof MutationObserver === 'undefined') return\n const wrapper = root.closest(`[data-slot=\"${CARD_SLOT_KEY}\"]`) ?? root.parentElement\n if (wrapper === null) return\n const row = wrapper.parentElement\n if (row === null) return\n let hiddenEditor: HTMLElement | null = null\n const sync = () => {\n const editor = adjacentEditorCard(wrapper) as HTMLElement | null\n setEditorOpen(editor !== null)\n if (editor !== null) {\n // React pins no inline style on the editor shell, so this survives\n // the shell's own re-renders; a shell that unmounts and remounts is\n // re-hidden by the next observation.\n editor.style.display = 'none'\n hiddenEditor = editor\n }\n }\n sync()\n const observer = new MutationObserver(sync)\n observer.observe(row, { childList: true })\n return () => {\n observer.disconnect()\n // If the shell outlives the panel (plugin reload), give it back: the\n // settings.yaml hint is the honest fallback face again.\n if (hiddenEditor !== null) hiddenEditor.style.display = ''\n }\n }, [])\n return (\n <div\n ref={rootRef}\n className=\"cc-providerCard\"\n data-cc-models-card=\"true\"\n style={editorOpen ? undefined : HIDDEN_STYLE}\n >\n {editorOpen && mode.kind === 'registration' ? <p className=\"cc-hint\">{t('cardRegistrationHint')}</p> : null}\n {editorOpen && mode.kind === 'live' && !mode.ready ? <p className=\"cc-hint\">{t('cardLoadingHint')}</p> : null}\n {editorOpen && showBody ? (\n <>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <span className=\"cc-label\">{t('cardTitle')}</span>\n <span className=\"cc-badges\">\n <StatusBadge ok={configured} okLabel={t('apiKeySet')} pendingLabel={t('apiKeyUnset')} />\n {props.provider.active ? <span className=\"cc-badge\">{t('cardRouteActive')}</span> : null}\n </span>\n </div>\n </div>\n <CardKeyField\n state={state.apiKey}\n disabled={disabled}\n t={t}\n onEdit={(text) => props.edit('apiKey', text)}\n />\n {login !== undefined ? (\n <LoginRow\n state={login}\n disabled={disabled}\n t={t}\n onBegin={props.beginLogin}\n onCancel={props.cancelLogin}\n />\n ) : null}\n <div className=\"cc-footer\">\n {failed ? <p className=\"cc-failed\" role=\"status\">{t('saveFailed')}</p> : null}\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={!dirty || saving}\n onClick={props.discard}\n >\n {t('discard')}\n </button>\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={savingBlocked || saving}\n onClick={props.save}\n >\n {t(saving ? 'saving' : 'save')}\n </button>\n </div>\n </>\n ) : null}\n </div>\n )\n}\n","/**\n * Bilingual copy for the Command Code **plans & quota panel** (the sidebar\n * footer card and the center-column dashboard it opens).\n *\n * The panel follows the harness's active language: `PANEL_LOCALE_NS` is a\n * registered locale namespace (`ctx.locale.register`), both panel slot\n * registrations declare it, and the renderer hands the component a `t` seat\n * whose identity changes on a language switch (so a memoized panel re-renders).\n * {@link buildPanelView} takes that translator as an input and builds every\n * string through it — the projection stays React-free and testable, and no\n * component carries copy of its own.\n *\n * The settings page keeps its own `settings.commandcode` namespace (see\n * `./locales.ts`); the two never mix.\n *\n * @module dsh-commandcode-provider/client/panel-copy\n */\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Copy of the plans & quota panel (footer card + dashboard). */\n 'panel.commandcode': PanelKey\n }\n}\n\n/**\n * The plans & quota panel key set. `zh` is the source of truth for the key set\n * (repo convention); en must carry the exact same keys — a mismatch is a\n * compile error at the register site.\n */\nexport type PanelKey =\n /** Footer card title and panel heading. */\n | 'nav'\n /** Panel sub-heading under the title. */\n | 'subtitle'\n /** Refresh button / in-flight label. */\n | 'refresh'\n | 'refreshing'\n /** Dashboard exit: the button's accessible name and its tooltip. */\n | 'close'\n | 'closeHint'\n /** First-paint fetch. */\n | 'loading'\n /** No credential at all: how to get one. */\n | 'noKey'\n | 'noKeyHint'\n /** Report section headings. */\n | 'plan'\n | 'credits'\n | 'limits'\n | 'usage'\n /** Monthly credit state and its tiles. */\n | 'monthly'\n | 'monthlyLimit'\n | 'monthlyUsed'\n | 'remaining'\n | 'purchased'\n | 'free'\n /** Usage-window rows (long labels in the dashboard, short in the footer). */\n | 'fiveHour'\n | 'weekly'\n | 'fiveHourShort'\n | 'weeklyShort'\n | 'windowUnlimited'\n | 'exceeded'\n | 'exhausted'\n | 'resets'\n /** Usage tiles. */\n | 'requests'\n | 'failed'\n | 'successRate'\n | 'spend'\n | 'tokens'\n | 'tokensIn'\n | 'tokensOut'\n /** Meta line. */\n | 'periodEnds'\n | 'updated'\n | 'partial'\n /** Rotation state on an account. */\n | 'active'\n | 'coolingDown'\n | 'invalidKey'\n /** Footer-card plan fallbacks. */\n | 'unconfigured'\n | 'unavailable'\n /** Whole-report failures (mirrors the settings card's blocked taxonomy). */\n | 'errorInvalidKey'\n | 'errorInvalidKeyHint'\n | 'errorServiceUnavailable'\n | 'errorServiceUnavailableHint'\n | 'errorNetwork'\n | 'errorNetworkHint'\n | 'errorInvalidResponse'\n | 'errorInvalidResponseHint'\n /** A fetch that failed for any other reason. */\n | 'errorGeneric'\n\n/** The locale namespace both panel slots bind their `t` seat to. */\nexport const PANEL_LOCALE_NS = 'panel.commandcode'\n\n/** A panel translator: one key in, one localized string out. */\nexport type PanelTranslator = (key: PanelKey) => string\n\n/** The panel's Simplified Chinese string table (the key-set source of truth). */\nexport const PANEL_COPY_ZH: Record<PanelKey, string> = {\n nav: 'Command Code',\n subtitle: '套餐、额度与配额窗口',\n refresh: '刷新',\n refreshing: '刷新中…',\n close: '关闭',\n closeHint: '返回会话',\n loading: '正在获取账户用量…',\n noKey: '尚未配置 API 密钥',\n noKeyHint: '在 设置 → Command Code 中粘贴密钥或登录后,点击刷新。',\n plan: '套餐',\n credits: '额度',\n limits: '配额窗口',\n usage: '用量',\n monthly: '月额度',\n monthlyLimit: '月额度上限',\n monthlyUsed: '本月已用',\n remaining: '剩余',\n purchased: '已购',\n free: '赠送',\n fiveHour: '5 小时窗口',\n weekly: '每周窗口',\n fiveHourShort: '5 小时',\n weeklyShort: '每周',\n windowUnlimited: '不限',\n exceeded: '已超限',\n exhausted: '已用尽',\n resets: '重置于',\n requests: '请求',\n failed: '失败',\n successRate: '成功率',\n spend: '花费',\n tokens: 'Token',\n tokensIn: '入',\n tokensOut: '出',\n periodEnds: '账期截止',\n updated: '更新于',\n partial: '部分端点数据不可用',\n active: '当前使用',\n coolingDown: '限额冷却中',\n invalidKey: '密钥无效',\n unconfigured: '未配置',\n unavailable: '无数据',\n errorInvalidKey: 'API 密钥无效或已过期',\n errorInvalidKeyHint: '服务端拒绝了全部请求(401)。请检查该账户的密钥,或到 commandcode.ai 控制台重新生成。',\n errorServiceUnavailable: 'Command Code 服务暂时不可用',\n errorServiceUnavailableHint: '服务端返回错误(5xx),请稍后点击刷新重试。',\n errorNetwork: '无法连接 Command Code 服务',\n errorNetworkHint: '所有请求都没有到达服务端。请检查网络连接或 API 地址设置。',\n errorInvalidResponse: 'Command Code 响应无法读取',\n errorInvalidResponseHint: '请求已收到响应,但内容无法解析。请检查宿主的 HTTP 代理或响应解压配置。',\n errorGeneric: '用量获取失败',\n}\n\n/** The panel's English string table (must mirror {@link PANEL_COPY_ZH}). */\nexport const PANEL_COPY_EN: Record<PanelKey, string> = {\n nav: 'Command Code',\n subtitle: 'Plans, credits and quota windows',\n refresh: 'Refresh',\n refreshing: 'Refreshing…',\n close: 'Close',\n closeHint: 'Back to the conversation',\n loading: 'Loading account usage…',\n noKey: 'No API key configured',\n noKeyHint: 'Paste a key — or sign in — under Settings → Command Code, then refresh.',\n plan: 'Plan',\n credits: 'Credits',\n limits: 'Quota windows',\n usage: 'Usage',\n monthly: 'Monthly',\n monthlyLimit: 'Monthly limit',\n monthlyUsed: 'Monthly used',\n remaining: 'Remaining',\n purchased: 'Purchased',\n free: 'Free',\n fiveHour: '5-hour window',\n weekly: 'Weekly window',\n fiveHourShort: '5-hour',\n weeklyShort: 'Weekly',\n windowUnlimited: 'unlimited',\n exceeded: 'Exceeded',\n exhausted: 'Used up',\n resets: 'Resets',\n requests: 'Requests',\n failed: 'failed',\n successRate: 'Success rate',\n spend: 'Spend',\n tokens: 'Tokens',\n tokensIn: 'in',\n tokensOut: 'out',\n periodEnds: 'Period ends',\n updated: 'Updated',\n partial: 'Some endpoint data unavailable',\n active: 'Active',\n coolingDown: 'Cooling down',\n invalidKey: 'Invalid key',\n unconfigured: 'Not configured',\n unavailable: 'No data',\n errorInvalidKey: 'API key invalid or expired',\n errorInvalidKeyHint: 'The server rejected every request (401). Check the key for this account, or generate a new one in the commandcode.ai console.',\n errorServiceUnavailable: 'The Command Code service is temporarily unavailable',\n errorServiceUnavailableHint: 'The server returned errors (5xx). Try Refresh again in a moment.',\n errorNetwork: 'Could not reach the Command Code service',\n errorNetworkHint: 'No request reached the server. Check your network connection or the API base setting.',\n errorInvalidResponse: 'Could not read the Command Code response',\n errorInvalidResponseHint: 'The requests received responses, but their bodies could not be parsed. Check the host HTTP proxy or response decoding.',\n errorGeneric: 'Could not fetch account usage',\n}\n\n/** Every panel key, in the English table's declaration order. */\nexport const PANEL_KEYS: readonly PanelKey[] = Object.keys(PANEL_COPY_EN) as PanelKey[]\n\n/**\n * The English translator. Used as the fallback when no locale seat is\n * available (a defensive path: every supported engine supplies one) and as the\n * default in tests that only assert the projection's figures.\n */\nexport function panelTextEN(key: PanelKey): string {\n return PANEL_COPY_EN[key] ?? key\n}\n","/**\n * View layer for the Command Code plans & quota panel (the sidebar footer card\n * and the dashboard it opens in the center column).\n *\n * Deliberately JSX-free and React-free, mirroring `./settings.ts` and\n * `./usage.ts`: it turns the shared usage snapshot into one presentation\n * tree that both React components render, and it owns the one shared side\n * effect (the throttled background refresh that keeps the sidebar card\n * current). Node tests drive everything here without a DOM.\n *\n * Every displayed string is decided here, as a `PanelKey` plus a `text`\n * record resolved through the injected translator — so the components carry no\n * formatting, pluralization, or copy of their own, and the panel follows the\n * harness's active language (`./panel-copy.ts` owns both dictionaries and the\n * `panel.commandcode` locale namespace; the slots hand the translator in).\n *\n * @module dsh-commandcode-provider/client/panel\n */\n\nimport type { CommandCodeUsageReport } from '../adapter.ts'\nimport type { CommandCodeAccountUsage } from '../usage-wire.ts'\nimport type { UsagePageState } from './usage.ts'\nimport {\n formatMoney,\n formatMoneyExact,\n formatSuccessRate,\n formatTokensCompact,\n} from './usage.ts'\nimport { PANEL_KEYS, panelTextEN } from './panel-copy.ts'\nimport type { PanelKey, PanelTranslator } from './panel-copy.ts'\n\n/** One quota window (5-hour or weekly) in display form. */\nexport interface PanelWindowView {\n /** Row-label key into the view's `text` record. */\n label: PanelKey\n /** `used / cap`, or just `used` when the window is uncapped. */\n value: string\n /** The window reports a cap, so `percent` is meaningful. */\n capped: boolean\n /** Percentage actually consumed (may exceed 100 when over the cap). */\n percent: number\n /** Fill width for the bar, clamped to [0, 100]. */\n barPercent: number\n /** Window is over its cap. */\n exceeded: boolean\n /** Local reset time, empty when the endpoint reported none. */\n resetsAt: string\n}\n\n/**\n * Monthly credit state, derived exactly the way the official CLI derives it\n * (`getCreditDepletionPct` in `command-code/dist/cli.mjs`): the plan's credit\n * total is the LIMIT, and the billing endpoint's `credits.monthlyCredits` is\n * the REMAINING balance, so consumption is `limit - remaining`. The CLI's own\n * wording for the same two numbers is `Plan: N% used, X credits left`.\n *\n * Purchased and free credits are separate balances that extend what an account\n * can spend, so they are reported as their own tiles rather than folded into\n * the limit.\n */\nexport interface PanelMonthlyView {\n /**\n * A ratio is meaningful — the plan published a credit total AND the billing\n * endpoint published the balance left of it. When false the view draws no\n * bar: a percentage needs both halves, and inventing either one is how a\n * failed billing call turns into a confident \"100% used\".\n */\n known: boolean\n /** Plan credit total for the period (the limit); a dash when unreported. */\n limit: string\n /** Consumed this period (`limit - remaining`); a dash until both are known. */\n used: string\n /** Credits still available; a dash when the balance was not reported. */\n remaining: string\n /** Purchased top-up balance. */\n purchased: string\n /** Promotional balance. */\n free: string\n /** Consumption as a percentage of the limit; 0 when there is no ratio. */\n percent: number\n /** Fill width for the bar, clamped to [0, 100]. */\n barPercent: number\n /** The plan's credits are used up. */\n exhausted: boolean\n /** Billing period end, local date; empty when unreported. */\n periodEnds: string\n}\n\n/** One compact bar in the sidebar footer card. */\nexport interface PanelFooterBar {\n /** Row label key (short forms: `Monthly`, `5-hour`, `Weekly`). */\n label: PanelKey\n /** Printed right-hand percentage, e.g. `32%`; empty when there is no ratio. */\n percent: string\n /** Fill width, clamped to [0, 100]. */\n barPercent: number\n /** Render in the warning colour. */\n warn: boolean\n /**\n * This window's own spend against its limit, e.g. `$1.32 / $6.00`. RENDERED,\n * not just a tooltip: the card exists to show these figures, and the\n * magnitudes are small dollar amounts (the endpoint reports a Pro account's\n * five-hour cap as `3` and its weekly cap as `6`).\n */\n detail: string\n}\n\n/** One usage tile. */\nexport interface PanelStatView {\n label: PanelKey\n value: string\n /** Secondary line, empty when there is none. */\n sub: string\n}\n\n/** One pool account's report, ready to render. */\nexport interface PanelAccountView {\n id: string\n label: string\n /** The account's display name (user name, else account name); empty when unreported. */\n owner: string\n /** Subscription display name; empty when unreported. */\n planName: string\n /** Subscription status when it is not a plain `active`; empty otherwise. */\n planStatus: string\n /** Rotation/credential state ('invalidKey' / 'coolingDown'); undefined when plain. */\n mark: PanelKey | undefined\n /** Known cooldown end, appended to the cooling-down badge; empty otherwise. */\n cooldownUntil: string\n /** No credential resolved for this slot. */\n unconfigured: boolean\n /** Billing period end, empty when unreported. */\n periodEnds: string\n /** Whether the account currently serves requests. */\n active: boolean\n /** Monthly credit state; undefined when neither endpoint reported it. */\n monthly: PanelMonthlyView | undefined\n windows: PanelWindowView[]\n stats: PanelStatView[]\n}\n\n/** What actually went wrong, once — for the alert box. */\nexport interface PanelFailureView {\n title: PanelKey\n /** The actionable line under the title. */\n hint: PanelKey\n /** The underlying transport message, shown small; empty when there is none. */\n detail: string\n}\n\n/** The whole panel, in render order. */\nexport interface PanelView {\n /** Every localized string this view references, by key. */\n text: Partial<Record<PanelKey, string>>\n /** Footer-card plan text (`Go`, `Pro`, …), or a state word. */\n planName: string\n /** Footer-card rotation/credential state line; empty when nothing to say. */\n status: string\n /**\n * The compact bars the sidebar footer card stacks: the two quota windows an\n * account actually runs into, 5-hour first then weekly. The monthly\n * limit/usage bar belongs to the DASHBOARD alone — it moves once a billing\n * period, whereas these two are what stop a session — so it is deliberately\n * absent here. A window with no cap is left out: there is no ratio to draw.\n */\n footerBars: PanelFooterBar[]\n /**\n * This period's spend in dollars, formatted; empty when the usage endpoint\n * reported nothing. NOT drawn as its own row — the card's visible figures are\n * the two windows' own spend (see {@link PanelFooterBar.detail}), and a\n * separate period total would sit next to the weekly window's near-identical\n * figure — so it rides the tooltip and the accessible name instead.\n */\n cost: string\n /**\n * The footer card's accessible name and tooltip: `Command Code · Pro ·\n * 5-hour $0.04 / $3.00 (1%) · Weekly $1.32 / $6.00 (22%) · Spend $1.32`.\n * Always starts with the visible title, so the accessible name contains the\n * visible label.\n */\n footTitle: string\n /** Every account, in rotation order (empty when there is nothing to show). */\n accounts: PanelAccountView[]\n /** Id of the account the panel opens on (the serving one), if any. */\n selectedId: string | undefined\n /** That account's view, for the footer card; undefined with no accounts. */\n selected: PanelAccountView | undefined\n /** A fetch is in flight and no data has landed for this paint. */\n loading: boolean\n /** No credential is configured at all. */\n noKey: boolean\n /** Report-level failure box; undefined when the report is usable. */\n failure: PanelFailureView | undefined\n /** A fetch failed while data is still on screen. */\n staleError: string | undefined\n /** Endpoint-level partial failure note; undefined when every endpoint answered. */\n partial: PanelKey | undefined\n /** Freshness line, empty when nothing has been fetched. */\n updatedAt: string\n}\n\n/** Inputs {@link buildPanelView} needs beyond the usage snapshot. */\nexport interface PanelViewInput {\n usage: UsagePageState\n /** Whether any account holds a credential (the settings controller's fact). */\n apiKeyConfigured: boolean\n /** Account ids staged for removal; hidden here immediately, like the settings card. */\n removingIds?: readonly string[]\n /**\n * Locale translator for every label the view composes. The panel slots bind\n * their `t` seat to the `panel.commandcode` namespace and pass it here, so\n * the projection follows the harness language; omitting it falls back to\n * English (the tests' default, and the defensive path when no locale face is\n * installed).\n */\n t?: PanelTranslator\n}\n\n/** A quota window's state as the wire carries it. */\ninterface WindowInput {\n used: number\n cap: number\n exceeded: boolean\n resetAt: number\n}\n\n/** `$1.23`, and `$0.0123` only when the amount is too small for cents to show it. */\nfunction money(value: number): string {\n if (value === 0) return formatMoney(0)\n return Math.abs(value) < 0.01 ? formatMoneyExact(value) : formatMoney(value)\n}\n\n/**\n * What a figure shows when the endpoint that carries it did not report one.\n * A dash, never a zero: the panel exists to state what the account has spent,\n * so \"we were not told\" has to look different from \"nothing\".\n */\nconst UNREPORTED = '—'\n\n/** Local reset time; empty when the endpoint reported none. */\nfunction resetText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleString()\n}\n\n/** Local short date; empty when unset. */\nfunction dateText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleDateString()\n}\n\n/** Local time-of-day; empty when unset. */\nfunction timeText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleTimeString()\n}\n\n/**\n * Consumption as a percentage, NOT clamped at 100 — an over-quota window\n * reports its real overshoot (150%), which is what the printed figure should\n * say. Bar widths clamp separately via {@link barPercent}.\n */\nfunction rawPercent(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.round((used / cap) * 100)\n}\n\n/** A percentage usable as a CSS width, clamped into [0, 100]. */\nfunction barPercent(percent: number): number {\n return Math.min(100, Math.max(0, percent))\n}\n\n/** Build one quota-window view. */\nfunction windowView(label: PanelKey, limit: WindowInput): PanelWindowView {\n const percent = rawPercent(limit.used, limit.cap)\n const capped = limit.cap > 0\n return {\n label,\n // Spend only: an uncapped window has no denominator, so its row pairs this\n // figure with the \"unlimited\" label instead of a `used / cap` it lacks.\n value: capped ? `${money(limit.used)} / ${money(limit.cap)}` : money(limit.used),\n capped,\n percent,\n barPercent: barPercent(percent),\n exceeded: limit.exceeded,\n resetsAt: resetText(limit.resetAt),\n }\n}\n\n/**\n * Build the monthly credit view from the two endpoints that carry it.\n *\n * The limit is the PLAN's credit total, not the billing endpoint's\n * `monthlyCredits` — that field is a remaining balance (see\n * {@link PanelMonthlyView}). Unknown plans (no `monthlyCredits` on the plan\n * record) therefore still show their balances, just without a ratio.\n *\n * The trap this guards: a MISSING balance is not a consumed one. The billing\n * endpoint is one of four the report fetches in parallel, so it fails on its\n * own while the plan still arrives — and reading the absent balance as 0 would\n * turn that partial failure into `limit - 0 = limit`, i.e. a confident \"100%\n * used, quota exhausted\" for an account that may have spent nothing. The\n * official CLI draws no meter unless the credits payload is present at all\n * (`hasCreditsInfo`), so \"unreported\" is the upstream-faithful reading here\n * too. Every derived figure stays a placeholder until the balance reported.\n */\nfunction monthlyView(report: CommandCodeUsageReport): PanelMonthlyView | undefined {\n const credits = report.credits\n const plan = report.plan\n if (credits === undefined && plan === undefined) return undefined\n\n const limitValue = plan?.monthlyCredits ?? null\n // Only an EXPLICIT `false` means the balance was omitted. An unset flag comes\n // from a Host half older than the field, which always sent a real number, so\n // it must keep rendering instead of turning into a dash everywhere.\n const remainingReported = credits !== undefined && credits.monthlyReported !== false\n const remaining = remainingReported ? Math.max(0, credits.monthlyCredits) : 0\n // A ratio needs BOTH halves: the plan's total and the balance left of it.\n const known = limitValue !== null && limitValue > 0 && remainingReported\n const used = known ? Math.max(0, limitValue - remaining) : 0\n const percent = known ? rawPercent(used, limitValue) : 0\n\n return {\n known,\n limit: limitValue !== null ? money(limitValue) : UNREPORTED,\n used: known ? money(used) : UNREPORTED,\n remaining: remainingReported ? money(remaining) : UNREPORTED,\n purchased: credits !== undefined && credits.purchasedReported !== false ? money(Math.max(0, credits.purchasedCredits)) : UNREPORTED,\n free: credits !== undefined && credits.freeReported !== false ? money(Math.max(0, credits.freeCredits)) : UNREPORTED,\n percent,\n barPercent: barPercent(percent),\n exhausted: known && remaining <= 0,\n periodEnds: dateText(plan?.currentPeriodEnd ?? 0),\n }\n}\n\n/** Build one account's view. */\nfunction accountView(entry: CommandCodeAccountUsage, t: PanelTranslator): PanelAccountView {\n const { report } = entry\n const account = report.account\n const plan = report.plan\n const credits = report.credits\n const usage = report.usage\n\n const stats: PanelStatView[] = []\n if (usage !== undefined) {\n stats.push({\n label: 'requests',\n value: String(usage.completedCount),\n sub: `${usage.failedCount} ${t('failed')}`,\n })\n stats.push({ label: 'successRate', value: `${formatSuccessRate(usage.successRate)}%`, sub: '' })\n stats.push({\n label: 'spend',\n value: formatMoneyExact(usage.totalCost),\n sub: `${formatMoney(usage.totalCredits)} credits`,\n })\n stats.push({\n label: 'tokens',\n value: formatTokensCompact(usage.totalTokensIn + usage.totalTokensOut),\n sub: `${formatTokensCompact(usage.totalTokensIn)} ${t('tokensIn')} / ${formatTokensCompact(usage.totalTokensOut)} ${t('tokensOut')}`,\n })\n }\n\n const windows: PanelWindowView[] = []\n // One row per window the endpoint actually REPORTED. An account on an\n // unlimited plan reports none, and drawing two zero-cap rows for it would\n // invent a limit the account does not have; a window that reported\n // `cap === 0` is uncapped spend and does get a row, labelled as such.\n if (credits?.fiveHour !== undefined) windows.push(windowView('fiveHour', credits.fiveHour))\n if (credits?.weekly !== undefined) windows.push(windowView('weekly', credits.weekly))\n\n // Rotation/credential state: the serving account first, then the two marks\n // the pool can carry, then a cooldown whose end time is known.\n let mark: PanelKey | undefined\n if (entry.active) mark = 'active'\n else if (entry.mark === 'invalid-credential') mark = 'invalidKey'\n else if (entry.cooldownUntil > 0 || entry.mark === 'rate-limit') mark = 'coolingDown'\n\n return {\n id: entry.id,\n label: entry.label,\n owner: account === undefined ? '' : account.userName || account.name,\n planName: plan?.name ?? '',\n planStatus: plan !== undefined && plan.status !== '' && plan.status !== 'active' ? plan.status : '',\n mark,\n cooldownUntil: entry.cooldownUntil > 0 ? resetText(entry.cooldownUntil) : '',\n unconfigured: !entry.configured,\n periodEnds: dateText(plan?.currentPeriodEnd ?? 0),\n active: entry.active,\n monthly: monthlyView(report),\n windows,\n stats,\n }\n}\n\n/** The report-level failure box, or undefined when the report is usable. */\nfunction failureView(state: UsagePageState): PanelFailureView | undefined {\n const blockedEntry = state.report?.accounts.find((entry) => entry.report.blocked !== undefined)\n const blocked = blockedEntry?.report.blocked\n // Preserve each endpoint's status or transport error beside the summary.\n const detail = (blockedEntry?.report.failures ?? []).join(' · ')\n if (blocked === 'invalid-key') {\n return { title: 'errorInvalidKey', hint: 'errorInvalidKeyHint', detail }\n }\n if (blocked === 'service-unavailable') {\n return { title: 'errorServiceUnavailable', hint: 'errorServiceUnavailableHint', detail }\n }\n if (blocked === 'network') {\n return { title: 'errorNetwork', hint: 'errorNetworkHint', detail }\n }\n if (blocked === 'invalid-response') {\n return { title: 'errorInvalidResponse', hint: 'errorInvalidResponseHint', detail }\n }\n // A transport-level failure (unmounted Remote, offline browser) arrives as\n // the controller's own error rather than as a blocked report.\n if (state.status === 'error' && state.report === undefined) {\n return { title: 'errorGeneric', hint: 'errorGeneric', detail: state.error ?? '' }\n }\n return undefined\n}\n\n/**\n * Every panel string, resolved once per projection through the translator.\n * One object with all keys (rather than per-field lookups in the components)\n * keeps the copy table and the render sites in lockstep: a key cannot be read\n * from `text` unless {@link PANEL_KEYS} declares it.\n */\nfunction panelStrings(t: PanelTranslator): Record<PanelKey, string> {\n const out = {} as Record<PanelKey, string>\n for (const key of PANEL_KEYS) out[key] = t(key)\n return out\n}\n\n/**\n * Project the shared usage snapshot into the panel's render tree.\n *\n * Deduplication matches the settings card: hand-edited settings can name one\n * credential twice, and removal staging hides an account before the post-save\n * refresh lands.\n */\nexport function buildPanelView(input: PanelViewInput): PanelView {\n const { usage } = input\n const t = input.t ?? panelTextEN\n const hidden = new Set(input.removingIds ?? [])\n const seen = new Set<string>()\n const entries = (usage.report?.accounts ?? []).filter((entry) => {\n if (hidden.has(entry.id)) return false\n if (seen.has(entry.id)) return false\n seen.add(entry.id)\n return true\n })\n const accounts = entries.map((entry) => accountView(entry, t))\n const selectedEntry = entries.find((entry) => entry.active) ?? entries[0]\n const selectedView = accounts.find((view) => view.id === selectedEntry?.id)\n\n // The footer card stacks BOTH quota windows — the two limits an account\n // actually runs into — 5-hour first (the tighter and nearer one), then\n // weekly. `barPercent` clamps the fill; the printed percentage keeps the true\n // consumption, so an over-cap window still reads 150%.\n const footerBars: PanelFooterBar[] = []\n const windowBars: Array<[PanelKey, WindowInput | undefined]> = [\n ['fiveHourShort', selectedEntry?.report.credits?.fiveHour],\n ['weeklyShort', selectedEntry?.report.credits?.weekly],\n ]\n for (const [label, window] of windowBars) {\n if (window === undefined || window.cap <= 0) continue\n const percent = rawPercent(window.used, window.cap)\n footerBars.push({\n label,\n percent: `${percent}%`,\n barPercent: barPercent(percent),\n warn: window.exceeded,\n detail: `${money(window.used)} / ${money(window.cap)}`,\n })\n }\n\n // The card's one non-ratio figure: what this period has cost in dollars.\n const totalCost = selectedEntry?.report.usage?.totalCost\n const cost = totalCost === undefined ? '' : money(totalCost)\n\n let status = ''\n if (entries.length > 0 && !entries.some(entry => entry.configured)) status = t('unconfigured')\n else if (selectedView?.mark !== undefined && selectedView.mark !== 'active') status = t(selectedView.mark)\n else if (selectedEntry === undefined) status = t('unavailable')\n\n const planName = selectedView !== undefined && selectedView.planName !== '' ? selectedView.planName : t('nav')\n // `planName` falls back to the panel name, so it is only a second part when it\n // actually names a plan — otherwise the title would read `Command Code ·\n // Command Code`.\n const titleParts = planName === t('nav') ? [planName] : [t('nav'), planName]\n for (const bar of footerBars) {\n const figures = bar.detail === '' ? '' : ` ${bar.detail}`\n titleParts.push(`${t(bar.label)}${figures} (${bar.percent})`)\n }\n if (cost !== '') titleParts.push(`${t('spend')} ${cost}`)\n\n return {\n text: panelStrings(t),\n planName,\n status,\n footerBars,\n cost,\n footTitle: titleParts.join(' · '),\n accounts,\n selectedId: selectedEntry?.id,\n selected: selectedView,\n loading: usage.status === 'loading' && usage.report === undefined,\n noKey: entries.length > 0 && !entries.some(entry => entry.configured),\n failure: failureView(usage),\n staleError: usage.status === 'error' && usage.report !== undefined ? usage.error ?? '' : undefined,\n partial: (usage.report?.accounts.some((entry) => entry.report.failures.length > 0 && entry.report.blocked === undefined) ?? false)\n ? 'partial'\n : undefined,\n updatedAt: timeText(usage.fetchedAt ?? 0),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auto refresh (one shared loop, started by whichever surface mounts first)\n// ---------------------------------------------------------------------------\n\n/**\n * How often the panel re-reads the report while a surface is mounted. The\n * quota windows move slowly and one report costs four upstream calls, so this\n * is a background freshness tick, not a live meter.\n */\nexport const PANEL_AUTO_REFRESH_MS = 120_000\n\n/** The narrow face of `CommandCodeUsageController` this module drives. */\nexport interface RefreshSource {\n state(): UsagePageState\n refresh(): Promise<void>\n}\n\n/** Timer seam: injectable so tests never wait on real time. */\nexport interface AutoRefreshTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\n\n/** The default timer (the client bundle runs in a browser; node tests inject one). */\nconst REAL_TIMER: AutoRefreshTimer = {\n set: (callback, ms) => setTimeout(callback, ms),\n clear: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n}\n\n/** Live mount count of {@link startPanelAutoRefresh}. */\nlet references = 0\n/** Owner ticket of the running loop, if any. */\nlet activeTicket: number | undefined\n/** Ticket handed to the next starter. */\nlet ticketSeq = 0\n/** Pending timer handle of the running loop. */\nlet handle: unknown\n\n/**\n * Start the shared auto refresh. One fetch when the surface appears (the\n * sidebar row is the point of the panel — it must be current, not wait for a\n * click), then a tick every {@link PANEL_AUTO_REFRESH_MS} while a surface\n * stays mounted.\n *\n * Reference-counted: the sidebar entry and the dashboard can be mounted at\n * once, so only the first start fetches and only the last stop halts the loop.\n * Every tick goes through `usage.refresh()`, which already collapses a\n * concurrent fetch onto the in-flight one — a tick never double-fetches\n * against the settings page's own refresh.\n *\n * @param usage - the shared usage controller.\n * @param isConfigured - whether a credential exists right now (re-read per tick).\n * @param timer - timer seam for tests.\n * @returns the disposer that drops this surface's reference.\n */\nexport function startPanelAutoRefresh(\n usage: RefreshSource,\n isConfigured: () => boolean,\n timer: AutoRefreshTimer = REAL_TIMER,\n): () => void {\n references += 1\n const ticket = ++ticketSeq\n const tick = (): void => {\n if (activeTicket !== ticket) return\n if (isConfigured()) void usage.refresh()\n handle = timer.set(tick, PANEL_AUTO_REFRESH_MS)\n }\n\n if (activeTicket === undefined) {\n activeTicket = ticket\n handle = timer.set(tick, PANEL_AUTO_REFRESH_MS)\n // First paint: refresh immediately so the row is never blank on arrival.\n if (isConfigured()) void usage.refresh()\n }\n\n let stopped = false\n return () => {\n if (stopped) return\n stopped = true\n references -= 1\n // Still mounted elsewhere: drop this reference only. Note the check is the\n // REFCOUNT, not this surface's ticket — the surface that started the loop\n // is not necessarily the last one to unmount, and a first-unmounted owner\n // must not be the reason a tick keeps firing.\n if (references > 0) return\n activeTicket = undefined\n if (handle !== undefined) {\n timer.clear(handle)\n handle = undefined\n }\n }\n}\n\n/**\n * Drop every live reference and halt the loop without a timer.\n *\n * Exported for tests only: the loop's state is module-level on purpose (two\n * surfaces, one upstream poll), so a test that mounts a surface must be able\n * to start from a clean slate. Production code releases through the disposer\n * {@link startPanelAutoRefresh} returns — the plugin's fiber unwinds it.\n */\nexport function resetPanelAutoRefresh(): void {\n references = 0\n activeTicket = undefined\n handle = undefined\n}\n","/**\n * React components for the Command Code plans & quota panel (browser half):\n * the sidebar footer card and the dashboard it opens in the center column.\n *\n * Both render one {@link PanelView} projected by `./panel.ts` — no fact is\n * derived here. Strings arrive already localized in `view.text`: the slots\n * declare the `panel.commandcode` locale namespace, so the renderer hands this\n * component a `t` seat that is passed into `buildPanelView` — the panel follows\n * the harness's active language (a language switch mints a new `t`, so the\n * surfaces re-render without an extra channel).\n *\n * The footer card is the panel's home: the sidebar shell renders it in the foot\n * area directly above the Settings seat, so each quota window's own spend and\n * limit — the 5-hour and the weekly one — are on screen without opening\n * anything. Clicking it selects the `main` panel this file also renders — and\n * unlike a `sidebar.panellist` row, whose button chrome and label the SHELL\n * owns, this entry owns its whole surface and therefore calls `open()` itself.\n *\n * Styles ride the stylesheet `./panel-styles.ts` returns, injected once by\n * the client entry; classes are `ccp-` prefixed to stay clear of the settings\n * page's `cc-` set.\n *\n * @module dsh-commandcode-provider/client/panel-view\n */\n\nimport { useEffect, useState } from 'react'\nimport { Button } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SnapshotStore } from './snapshot-store.ts'\nimport type { UsagePageState } from './usage.ts'\nimport type { SettingsPageState } from './settings.ts'\nimport { buildPanelView } from './panel.ts'\nimport type { PanelAccountView, PanelStatView, PanelView, PanelWindowView } from './panel.ts'\nimport { panelTextEN } from './panel-copy.ts'\nimport type { PanelKey } from './panel-copy.ts'\n// SlotMap merge for `main` / `sidebar.footer.action` (load-bearing: the slots\n// this file's components register into are typed only by that augmentation).\nimport './panel-slots.ts'\n\n/**\n * Owner share of the sidebar-foot action hole: the shell renders the foot area\n * and hands each action only the column fold state. There is no button chrome\n * and no `label` seat — the entry is the whole surface.\n */\nexport interface SidebarFooterActionOwnerProps {\n /** Whether the sidebar renders wide content (false = 56px rail). */\n wide: boolean\n}\n\n/**\n * The injected face both panel slots carry. Bound by the client entry so the\n * components stay unaware of the settings controller, the login controller,\n * the layout service and the module-level auto-refresh loop.\n *\n * NOTE the split from {@link PanelComponentProps}: this is the face the\n * registration's `inject` factory RETURNS, and the renderer does not hand it to\n * the component verbatim. `bindInjectSources` destructures the `hooks`\n * compartment OUT of the face and re-exposes each member as a `use<Name>` prop\n * (`commandCodeUsage` → `useCommandCodeUsage`). A component that reads\n * `props.hooks.*` therefore finds `undefined` at runtime and crashes on render\n * — which the slot renderer contains by ABDICATING the entry, so the surface\n * vanishes with no visible error. Read the `useX` seats instead.\n */\nexport interface PanelInjected {\n hooks: {\n commandCodeUsage: SnapshotStore<UsagePageState>\n commandCodeSettings: SnapshotStore<SettingsPageState>\n }\n /** Fetch the report now (the dashboard's Refresh action). */\n refresh(): void\n /**\n * Leave the dashboard and show the Conversation again\n * (`ctx.layout.selectPanel(null)`; the current Session is untouched).\n */\n close(): void\n /** Start the shared background poll for this mount; returns its disposer. */\n startAutoRefresh(): () => void\n /** Select this panel in the center column (`ctx.layout.selectPanel`). */\n open(): void\n}\n\n/**\n * The props a panel component actually receives: the bound `useX` seats (what\n * {@link PanelInjected}'s `hooks` compartment becomes), the pass-through\n * actions, and no raw `hooks` key.\n *\n * `buildPanelView` is cheap (one pass over the account list) and recomputing it\n * per notification is what keeps a store update from ever rendering a stale\n * quota, so the selector is deliberately the whole snapshot.\n */\nexport interface PanelComponentProps {\n useCommandCodeUsage<T>(selector: (state: UsagePageState) => T): T\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n /**\n * Locale seat for the `panel.commandcode` namespace, bound by the\n * registration's own `locale` declaration. Optional so a missing locale face\n * degrades to English instead of crashing the surface.\n */\n t?: Translate<PanelKey>\n refresh(): void\n close(): void\n startAutoRefresh(): () => void\n open(): void\n}\n\n/** Props of the sidebar footer card: the panel face plus the shell's fold state. */\nexport interface CommandCodeFooterEntryProps extends PanelComponentProps, SidebarFooterActionOwnerProps {}\n\n/** The panel's view, recomputed from both seats on every notification. */\nfunction usePanelView(props: PanelComponentProps): PanelView {\n const usage = props.useCommandCodeUsage((state) => state)\n const settings = props.useCommandCodeSettings((state) => state)\n return buildPanelView({\n usage,\n apiKeyConfigured: settings.anyAccountConfigured,\n removingIds: settings.accountsRemoving,\n t: props.t ?? panelTextEN,\n })\n}\n\n/**\n * The quota ring. One glyph serves the rail button, the footer card's top row\n * and the dashboard header: a faint track plus an arc whose sweep is the\n * consumption, drawn from 12 o'clock. Circumference 2πr = 45.55 at r = 7.25.\n */\nfunction Ring({ percent, warn, size }: { percent: number; warn: boolean; size: number }) {\n const clamped = Math.min(100, Math.max(0, percent))\n const circumference = 45.55\n // Rounded to three decimals: the raw product lands on floats like\n // 34.162499999999994, which is a needless DOM diff churn.\n const dashoffset = Math.round(circumference * (1 - clamped / 100) * 1000) / 1000\n return (\n <span className=\"ccp-glyph\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" width={size} height={size} focusable=\"false\">\n <circle cx=\"10\" cy=\"10\" r=\"7.25\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" opacity=\"0.4\" />\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"7.25\"\n fill=\"none\"\n stroke={warn ? 'var(--dsw-alias-state-error-primary)' : 'currentColor'}\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeDasharray={String(circumference)}\n strokeDashoffset={String(dashoffset)}\n transform=\"rotate(-90 10 10)\"\n />\n </svg>\n </span>\n )\n}\n\n/** One labelled bar. `compact` drops the reset line; the footer draws its own. */\nfunction QuotaBar({ label, value, percent, barPercent, warn, resetsAt, resetsLabel }: {\n label: string\n value: string\n percent: string\n barPercent: number\n warn: string\n resetsAt: string\n resetsLabel: string\n}) {\n const clamped = Math.min(100, Math.max(0, barPercent))\n return (\n <div className=\"ccp-window\">\n <div className=\"ccp-windowHead\">\n <span className=\"ccp-windowLabel\">{label}</span>\n {warn !== '' ? <span className=\"ccp-warnTag\">{warn}</span> : null}\n <span className=\"ccp-spacer\" />\n {value !== '' ? <span className=\"ccp-windowValue\">{value}</span> : null}\n <span className=\"ccp-windowPct\">{percent}</span>\n </div>\n <div className=\"ccp-bar\" role=\"progressbar\" aria-label={label} aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <div className={warn !== '' ? 'ccp-barFill ccp-barFillWarn' : 'ccp-barFill'} style={{ width: `${clamped}%` }} />\n </div>\n {resetsAt !== '' ? <p className=\"ccp-windowReset\">{resetsLabel} {resetsAt}</p> : null}\n </div>\n )\n}\n\n/** A labelled figure. */\nfunction Tile({ label, value, sub }: { label: string; value: string; sub?: string }) {\n return (\n <div className=\"ccp-tile\">\n <span className=\"ccp-tileLabel\">{label}</span>\n <span className=\"ccp-tileValue\">{value}</span>\n {sub !== undefined && sub !== '' ? <span className=\"ccp-tileSub\">{sub}</span> : null}\n </div>\n )\n}\n\n/** One usage tile. */\nfunction StatTile({ stat, label }: { stat: PanelStatView; label: string }) {\n return <Tile label={label} value={stat.value} sub={stat.sub} />\n}\n\n/** The rotation/credential badge line for one account. */\nfunction markText(account: PanelAccountView, text: (key: PanelKey) => string): string {\n if (account.mark === undefined) return ''\n if (account.mark === 'coolingDown' && account.cooldownUntil !== '') {\n return `${text('coolingDown')} · ${account.cooldownUntil}`\n }\n return text(account.mark)\n}\n\n/** `Default account` → `D`; used for the card's monogram chip. */\nfunction initial(label: string): string {\n const trimmed = label.trim()\n return trimmed === '' ? '?' : trimmed[0]!.toUpperCase()\n}\n\n/**\n * One account's full report: the monthly limit/usage bar, the two quota\n * windows, then the credit and usage totals.\n */\nfunction AccountCard({ account, view }: { account: PanelAccountView; view: PanelView }) {\n const text = (key: PanelKey): string => view.text[key] ?? key\n const mark = markText(account, text)\n const monthly = account.monthly\n\n return (\n <section className=\"ccp-card\" aria-label={account.label}>\n <header className=\"ccp-cardHead\">\n <span className=\"ccp-avatar\" aria-hidden=\"true\">{initial(account.label)}</span>\n <span className=\"ccp-cardIdentity\">\n <span className=\"ccp-cardTitle\">{account.label}</span>\n {account.owner !== '' ? <span className=\"ccp-cardOwner\">{account.owner}</span> : null}\n </span>\n <span className=\"ccp-spacer\" />\n {account.planName !== '' ? <span className=\"ccp-badge\">{account.planName}</span> : null}\n {account.planStatus !== '' ? <span className=\"ccp-badge ccp-badgeWarn\">{account.planStatus}</span> : null}\n {mark !== '' ? (\n <span className={account.mark === 'invalidKey' ? 'ccp-badge ccp-badgeError' : 'ccp-badgeMuted'}>{mark}</span>\n ) : null}\n {account.periodEnds !== '' ? (\n <span className=\"ccp-meta\">{text('periodEnds')} {account.periodEnds}</span>\n ) : null}\n </header>\n\n {account.unconfigured ? <p className=\"ccp-hint\">{text('unconfigured')}</p> : null}\n\n {monthly !== undefined && monthly.known ? (\n <QuotaBar\n label={text('monthly')}\n value={`${monthly.used} / ${monthly.limit}`}\n percent={`${monthly.percent}%`}\n barPercent={monthly.barPercent}\n warn={monthly.exhausted ? text('exhausted') : ''}\n resetsAt=\"\"\n resetsLabel=\"\"\n />\n ) : (\n <div className=\"ccp-planRow\">\n {/* The plan is a fact the card already shows in its header badge; what\n is missing here is the RATIO, so the row names the plan whenever\n the report carries one and falls back to a placeholder only when\n the report itself is silent. */}\n <span className=\"ccp-fieldLabel\">{text('plan')}</span>\n <span className=\"ccp-planName\">{account.planName !== '' ? account.planName : text('unavailable')}</span>\n </div>\n )}\n\n {/* A balance the billing endpoint DID report, so a card without a ratio\n still states something true instead of nothing. */}\n {monthly !== undefined && monthly.remaining !== '—' ? (\n <div className=\"ccp-planRow\">\n <span className=\"ccp-fieldLabel\">{text('remaining')}</span>\n <span className=\"ccp-planName\">{monthly.remaining}</span>\n </div>\n ) : null}\n\n {account.windows.length > 0 ? (\n <div className=\"ccp-windows\">\n {account.windows.map((window: PanelWindowView) => (\n <QuotaBar\n key={window.label}\n label={text(window.label)}\n value={window.value}\n percent={window.capped ? `${window.percent}%` : text('windowUnlimited')}\n barPercent={window.barPercent}\n warn={window.exceeded ? text('exceeded') : ''}\n resetsAt={window.resetsAt}\n resetsLabel={text('resets')}\n />\n ))}\n </div>\n ) : null}\n\n {monthly !== undefined ? (\n <div className=\"ccp-block\">\n <h4 className=\"ccp-blockTitle\">{text('credits')}</h4>\n <div className=\"ccp-tiles\">\n <Tile label={text('monthlyLimit')} value={monthly.limit} />\n <Tile label={text('monthlyUsed')} value={monthly.used} />\n <Tile label={text('remaining')} value={monthly.remaining} />\n <Tile label={text('purchased')} value={monthly.purchased} />\n <Tile label={text('free')} value={monthly.free} />\n </div>\n </div>\n ) : null}\n\n {account.stats.length > 0 ? (\n <div className=\"ccp-block\">\n <h4 className=\"ccp-blockTitle\">{text('usage')}</h4>\n <div className=\"ccp-tiles\">\n {account.stats.map((stat) => (\n <StatTile key={stat.label} stat={stat} label={text(stat.label)} />\n ))}\n </div>\n </div>\n ) : null}\n </section>\n )\n}\n\n/**\n * The center-column dashboard, registered into the layout's keyed `main` slot\n * under the same id the footer card selects, so the two are one navigation\n * entry: the card shows the plan, the monthly bar and the quota window; the\n * panel shows everything, including the per-account breakdown.\n */\nexport function CommandCodePanel(props: PanelComponentProps) {\n const view = usePanelView(props)\n const text = (key: PanelKey): string => view.text[key] ?? key\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\n\n const startAutoRefresh = props.startAutoRefresh\n useEffect(() => startAutoRefresh(), [startAutoRefresh])\n\n const accounts = view.accounts\n const selected = accounts.find((account) => account.id === selectedId)\n ?? view.selected\n ?? accounts[0]\n\n return (\n <div className=\"ccp-main\" role=\"region\" aria-label={text('nav')}>\n <div className=\"ccp-mainInner\">\n <header className=\"ccp-header\">\n <div className=\"ccp-headerText\">\n <h2 className=\"ccp-title\">{text('nav')}</h2>\n <p className=\"ccp-subtitle\">{text('subtitle')}</p>\n </div>\n <span className=\"ccp-spacer\" />\n {view.updatedAt !== '' ? <span className=\"ccp-meta\">{text('updated')} {view.updatedAt}</span> : null}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={view.loading}\n onClick={() => props.refresh()}\n >\n {view.loading ? text('refreshing') : text('refresh')}\n </Button>\n {/* The dashboard REPLACES the conversation in the center column, and\n this panel is the only surface that selects it — without an exit\n the user cannot get back to the session at all (issue #41), since\n clicking the sidebar card only re-selects this same panel. The\n glyph is the button's whole content, so its accessible name and\n tooltip carry the meaning. */}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ccp-close\"\n aria-label={text('close')}\n title={text('closeHint')}\n onClick={() => props.close()}\n >\n <span aria-hidden=\"true\">×</span>\n </Button>\n </header>\n\n {view.noKey ? (\n <div className=\"ccp-notice\">\n <p className=\"ccp-noticeTitle\">{text('noKey')}</p>\n <p className=\"ccp-noticeHint\">{text('noKeyHint')}</p>\n </div>\n ) : null}\n\n {view.failure !== undefined ? (\n <div className=\"ccp-notice ccp-noticeError\" role=\"alert\">\n <p className=\"ccp-noticeTitle\">{text(view.failure.title)}</p>\n <p className=\"ccp-noticeHint\">{text(view.failure.hint)}</p>\n {view.failure.detail !== '' ? <p className=\"ccp-noticeDetail\">{view.failure.detail}</p> : null}\n </div>\n ) : null}\n\n {!view.noKey && view.failure === undefined && accounts.length === 0 && view.loading ? (\n <p className=\"ccp-hint\">{text('loading')}</p>\n ) : null}\n\n {view.staleError !== undefined && view.staleError !== '' ? (\n <p className=\"ccp-hint\" role=\"status\">{text('errorGeneric')} — {view.staleError}</p>\n ) : null}\n\n {accounts.length > 1 ? (\n <div className=\"ccp-tabs\" role=\"tablist\" aria-label={text('nav')}>\n {accounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected?.id === account.id}\n className={selected?.id === account.id ? 'ccp-tab ccp-tabActive' : 'ccp-tab'}\n onClick={() => setSelectedId(account.id)}\n >\n {account.label}\n </button>\n ))}\n </div>\n ) : null}\n\n {selected !== undefined ? <AccountCard account={selected} view={view} /> : null}\n\n {view.partial !== undefined ? <p className=\"ccp-hint\">{text(view.partial)}</p> : null}\n </div>\n </div>\n )\n}\n\n/**\n * The sidebar footer card, registered into `sidebar.footer.action` — the list\n * the shell renders in the sidebar's foot area directly ABOVE the Settings\n * seat, so the panel reads as a bottom-pinned sibling of Settings rather than\n * a global panel icon at the top of the column.\n *\n * The shell wraps nothing here, so this component owns the surface: the\n * button, its chrome and its accessible name. In the expanded column it draws\n * the title row, then one block per quota window (5-hour, then weekly) — the\n * window's own spend and limit (`$1.32 / $6.00`), its percentage and its bar —\n * and nothing else: the card's figures are the two windows the account runs\n * into, so the period total stays in the tooltip rather than taking a third\n * line. In the 56px rail it collapses to a 36px icon button carrying the ring,\n * matching the shell's own rail geometry. `wide` comes from the shell as an\n * owner prop — unlike the old `sidebar.panellist` row, this slot really does\n * supply it.\n *\n * Rendering is gated on the settings page's `showSidebarQuota` toggle, which\n * defaults OFF: a fresh install shows no quota surface in the sidebar and runs\n * no background poll. The gate reads the STORED document (the settings\n * controller's `sidebarQuota` fact), so an unsaved draft cannot show the card,\n * while a landed save flips it live. The entry is still REGISTERED — this is a\n * render decision, not a slot registration, so nothing churns the slot ledger.\n */\nexport function CommandCodeFooterEntry(props: CommandCodeFooterEntryProps) {\n // The card is opt-in (`showSidebarQuota`, default off) and follows the\n // STORED document, never the settings page's staged draft — see\n // `SettingsPageState.sidebarQuota`. While it is hidden this component renders\n // NOTHING — no expanded card, no rail icon — and starts no background usage\n // poll; the dashboard cell stays registered but has no trigger, which is\n // exactly what \"hide the quota display\" means.\n const visible = props.useCommandCodeSettings((snapshot) => snapshot.sidebarQuota)\n const view = usePanelView(props)\n\n const startAutoRefresh = props.startAutoRefresh\n useEffect(() => {\n if (!visible) return undefined\n return startAutoRefresh()\n }, [visible, startAutoRefresh])\n\n if (!visible) return null\n\n const text = (key: PanelKey): string => view.text[key] ?? key\n // The ring tracks the tightest window — the 5-hour one whenever it is capped,\n // which is the limit an account actually runs into first. `footerBars` is\n // ordered that way, so the leading bar is the headline.\n const headline = view.footerBars[0]\n // The tooltip doubles as the accessible name; it always begins with the\n // visible title, so the label the user reads is contained in the name.\n const title = view.footTitle\n\n if (!props.wide) {\n return (\n <button\n type=\"button\"\n className=\"ccp-railButton\"\n aria-label={title}\n title={title}\n onClick={() => props.open()}\n >\n <Ring percent={headline?.barPercent ?? 0} warn={headline?.warn ?? false} size={18} />\n </button>\n )\n }\n\n return (\n <button\n type=\"button\"\n className=\"ccp-foot\"\n aria-label={title}\n title={title}\n onClick={() => props.open()}\n >\n <span className=\"ccp-footTop\">\n <Ring percent={headline?.barPercent ?? 0} warn={headline?.warn ?? false} size={16} />\n <span className=\"ccp-footName\">{text('nav')}</span>\n <span className=\"ccp-spacer\" />\n {view.status !== '' ? (\n <span className=\"ccp-badgeMuted\">{view.status}</span>\n ) : view.planName !== text('nav') ? (\n <span className=\"ccp-badge\">{view.planName}</span>\n ) : null}\n </span>\n\n {view.footerBars.map((bar) => (\n <span className=\"ccp-footRow\" key={bar.label}>\n <span className=\"ccp-footHead\">\n <span className=\"ccp-footLabel\">{text(bar.label)}</span>\n <span className=\"ccp-spacer\" />\n {bar.detail !== '' ? <span className=\"ccp-footAmount\">{bar.detail}</span> : null}\n <span className=\"ccp-footPct\">{bar.percent}</span>\n </span>\n <span className=\"ccp-footBar\">\n <span\n className={bar.warn ? 'ccp-footFill ccp-footFillWarn' : 'ccp-footFill'}\n style={{ width: `${bar.barPercent}%` }}\n />\n </span>\n </span>\n ))}\n </button>\n )\n}\n","/** Shared, JSON-only billing facts. No Host or browser runtime imports. */\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\n\nexport interface CostTokens {\n uncachedInputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n}\n\n/** Requests with identical model/rates are folded into one group. */\nexport interface CostUsageGroup {\n provider: string\n model: string\n at: number | null\n contextTokens: number\n tokens: CostTokens\n}\n\nexport interface SessionCostFacts {\n pricingKey: number\n groups: CostUsageGroup[]\n}\n\nexport const zeroCostTokens = (): CostTokens => ({ uncachedInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })\nexport const COST_TOKEN_KEYS = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\n\nexport function peakHour(at: number, windows: ReadonlyArray<readonly [number, number]>): boolean {\n const time = new Date(at)\n return time.getUTCDay() !== 0 && time.getUTCDay() !== 6\n && windows.some(([start, end]) => time.getUTCHours() >= start && time.getUTCHours() < end)\n}\n\n/**\n * All prompt billing buckets determine a request's band, never cumulative session input.\n *\n * A tiered model returns the matching band and does NOT then apply `peak`: the\n * page publishes those two dimensions independently, no row carries both today,\n * and the generator would report a tiered row on every sync — so the combination\n * becoming real is visible before it reaches a user. This ordering is a latent\n * choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // The first band whose bound accepts the prompt. ORDER IS LOAD-BEARING, and\n // both producers enforce it: the generator refuses non-ascending bounds or a\n // bounded last band, and the wire parser rejects the same shapes — so a\n // conforming table cannot present bands out of order, and this `find` cannot\n // select a band a later one should have won.\n const tier = price.contextTiers?.find(tier => tier.maxContext === undefined || contextTokens <= tier.maxContext)\n if (tier !== undefined) return tier\n return price.peak !== undefined && at !== null && peakHour(at, table.peakHours) ? price.peak : price\n}\n\n/** Cache version and wire guard: changing bands/rates must refold historical groups. */\nexport function pricingKey(table: CommandCodePriceTable): number {\n const rates = (r: CommandCodeModelRates) => [r.inputCost, r.outputCost, r.cacheReadCost, r.cacheWriteCost ?? null]\n const canonical = JSON.stringify(['commandCodeCost-v1', table.peakHours, table.models.map(p => [p.id, p.slug, p.free === true, rates(p), p.peak ? rates(p.peak) : null, p.contextTiers?.map(t => [t.maxContext ?? null, rates(t)]) ?? null])])\n let hash = 2166136261\n for (const c of canonical) hash = Math.imul(hash ^ c.charCodeAt(0), 16777619) >>> 0\n return hash\n}\n\n/** Only safe to merge requests whose billing classification is identical. */\nexport function costGroupKey(group: CostUsageGroup, table: CommandCodePriceTable): string {\n const price = table.models.find(p => p.id === group.model || p.slug === group.model)\n return JSON.stringify([group.provider, group.model, price === undefined ? null : requestRates(price, group.at, group.contextTokens, table), group.at === null])\n}\n","/**\n * Session-cost view model for the composer readout.\n *\n * Deliberately JSX-free and React-free, mirroring `./panel.ts`: it turns the\n * session's token accounting plus the Host's price table into one presentation\n * value AND the exact text the two surfaces of the harness's token-usage UI\n * receive — the amount appended to the shipped pill, and the rows appended to\n * the shipped usage dialog. Node tests therefore drive the whole calculation,\n * and every user-visible string, without a DOM.\n *\n * The figures it prices are the session's DURABLE cumulative buckets, which is\n * what the composer's own \"N tokens\" pill reads too (`tokenUsage`), so the two\n * surfaces can never disagree about how much was used. Dollars are computed\n * here because Command Code publishes per-token rates and bills against\n * dollar-denominated windows; the account's own reported `totalCost` is a\n * billing PERIOD figure, not this session's.\n *\n * Three rules are load-bearing:\n *\n * 1. **Only Command Code usage is priced.** A session served by another\n * provider must render nothing, never a Command Code estimate.\n * 2. **A missing rate is never invented.** The pricing page publishes\n * input/output/cache-read rates for every model but a cache-WRITE rate for\n * only some, so unpriced cache-write tokens are surfaced as such rather than\n * charged at a guessed multiple of the input rate.\n * 3. **Unpriceable means invisible.** No usage, no model, no table, an unknown\n * model, or all-zero buckets renders nothing at all — a confident `$0.00`\n * would be a lie, and this module never returns one.\n *\n * @module dsh-commandcode-provider/client/session-cost\n */\n\nimport { COST_TOKEN_KEYS, pricingKey, requestRates, peakHour, zeroCostTokens, type SessionCostFacts } from '../cost-facts.ts'\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from '../usage-wire.ts'\nimport { formatMoney, formatMoneyExact, formatTokensCompact } from './usage.ts'\n\n/** Tokens per published rate unit — the pricing page quotes USD per million. */\nconst TOKENS_PER_RATE_UNIT = 1_000_000\n\n/** The provider route whose usage this surface prices. */\nconst COMMANDCODE_PROVIDER = 'commandcode'\n\n/**\n * The English copy for this surface.\n *\n * A plain constant, NOT the `settings.commandcode` locale namespace: like the\n * plans & quota panel, the readout stays English on a Chinese harness. Do not\n * route it through `ctx.locale`.\n */\nexport const SESSION_COST_COPY = {\n /** Shown instead of an amount when the model costs nothing on every plan. */\n free: 'Free',\n /**\n * The separator the readout prefixes itself with, so the cost reads as the\n * last item of the token-usage pill's text run rather than a control beside\n * it. Rendered with the same colour and margins the shipped pill uses\n * between its own items.\n */\n separator: '·',\n /** The heading the tooltip leads with. */\n panelTitle: 'Session cost',\n /** Marks an estimate from published rates rather than an invoice. */\n approximate: '≈',\n /** Tooltip line for the unpriced cache-write tokens. */\n unpricedCacheWrite: 'cache write tokens have no published rate',\n /** Tooltip line naming the rate half in force. */\n peakRates: 'peak rates',\n /** Tooltip line naming the rate half in force. */\n offPeakRates: 'off-peak rates',\n /** Tooltip line explaining the approximate marker. */\n approximateNote: 'estimate from published rates, not the provider invoice',\n /** Row/tooltip label for uncached prompt tokens. */\n uncachedInput: 'uncached input',\n /** Row/tooltip label for completion tokens. */\n output: 'output',\n /** Row/tooltip label for cache-served input tokens. */\n cacheRead: 'cache read',\n /** Row/tooltip label for cache-written input tokens. */\n cacheWrite: 'cache write',\n} as const\n\n/**\n * The session's cumulative token buckets, as the `tokenUsage` projection\n * carries them. Declared structurally and defensively: this bundle does not\n * depend on the session-controller package, and a bucket the provider never\n * reported is absent rather than zero.\n */\nexport interface SessionUsageBuckets {\n readonly uncachedInputTokens?: number\n readonly outputTokens?: number\n readonly cacheReadTokens?: number\n readonly cacheWriteTokens?: number\n}\n\n/** One entry of the `modelSelection` projection. */\nexport interface SessionModelSelection {\n readonly provider: string\n readonly model: string\n}\n\n/**\n * The `modelSelection` projection: the selection the latest request consumed,\n * and the one the next request will use (falling back to the former).\n */\nexport interface SessionModelSelectionProjection {\n readonly lastUsed: SessionModelSelection | null\n readonly next: SessionModelSelection | null\n}\n\n/** Everything the view needs, already read off the seats by the component. */\nexport interface SessionCostInput {\n /** Durable billing groups; absent on older Hosts means no trustworthy estimate. */\n facts?: SessionCostFacts | undefined\n /** The durable cumulative token buckets, or undefined before any request. */\n usage: SessionUsageBuckets | undefined\n /** The session's model selection fold, or undefined on an older Host. */\n selection: SessionModelSelectionProjection | undefined\n /** The Host's price table, or undefined until it lands. */\n table: CommandCodePriceTable | undefined\n /** Legacy caller field; historical request timestamps alone determine rates. */\n now: number\n}\n\n/** One bucket's line in the usage dialog. */\nexport interface SessionCostBucketRow {\n /** Stable key. */\n key: 'uncachedInput' | 'cacheRead' | 'cacheWrite' | 'output'\n /** Row label. */\n label: string\n /** Tokens charged in this bucket; a bucket that charged nothing withholds its\n * row rather than printing a meaningless zero. */\n tokens: number\n /** What this bucket cost, or undefined when the table has no rate for it. */\n costText: string | undefined\n}\n\n/** The composer readout's presentation value. */\nexport interface SessionCostView {\n /** Priced total in dollars. */\n total: number\n /** Visible amount text, e.g. `$0.0123` (or the free word, when free). */\n value: string\n /** Full tooltip/accessible text, including the bucket breakdown. */\n title: string\n /** Per-bucket lines for the usage dialog, in reading order. */\n rows: SessionCostBucketRow[]\n /** Caveat lines for the pill's tooltip (rate half, approximation, unpriced). */\n notes: string[]\n /** The model costs nothing on every plan right now. */\n free: boolean\n /** The model's `peak` rates are in force. */\n peak: boolean\n /** Cache-write tokens the table has no rate for (never guessed, so the\n * total is a floor rather than an estimate). */\n unpricedCacheWriteTokens: number\n /** Published-rate totals are estimates rather than provider invoices. */\n approximate: boolean\n}\n\n/** A finite, non-negative count — anything else reads as absent. */\nfunction count(value: number | undefined): number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0\n}\n\n/**\n * Whether `now` falls inside a peak-pricing window, per the windows that travel\n * with the price table. Monday–Friday (UTC) only, and each window is\n * end-exclusive — the same rule the Host snapshot applies when it labels the\n * model picker. The schedule is read from the wire rather than restated so\n * there is one definition of the windows, on the Host.\n */\nexport function isPeakHour(now: number, peakHours: ReadonlyArray<readonly [number, number]>): boolean {\n const at = new Date(now)\n const day = at.getUTCDay()\n if (day === 0 || day === 6) return false\n const hour = at.getUTCHours()\n return peakHours.some(([start, end]) => hour >= start && hour < end)\n}\n\n/**\n * Index a price table for lookup. Rows are keyed by catalog id and by pricing\n * slug, both exact and lowercased, because a session reports a catalog id while\n * a row no catalog model claims is served under the page's slug.\n */\nfunction indexTable(table: CommandCodePriceTable): Map<string, CommandCodeModelPrice> {\n const index = new Map<string, CommandCodeModelPrice>()\n for (const price of table.models) {\n for (const key of [price.id, price.slug]) {\n if (typeof key !== 'string' || key === '') continue\n if (!index.has(key)) index.set(key, price)\n const lower = key.toLowerCase()\n if (!index.has(lower)) index.set(lower, price)\n }\n }\n return index\n}\n\n/**\n * The dollar cost of each bucket, plus the total and the unpriced remainder.\n *\n * Every bucket is charged at its own published rate; the cache-write bucket\n * contributes only when the model publishes a rate for it, otherwise its tokens\n * are returned as {@link SessionCostView.unpricedCacheWriteTokens} and its own\n * cost stays undefined so the panel can say so instead of printing a zero.\n */\ninterface SessionCostBreakdown {\n uncachedInput: number\n cacheRead: number\n cacheWrite: number | undefined\n output: number\n total: number\n unpricedCacheWriteTokens: number\n}\n\nfunction costOf(\n usage: SessionUsageBuckets,\n rates: CommandCodeModelRates,\n free: boolean,\n): SessionCostBreakdown {\n if (free) {\n return { uncachedInput: 0, cacheRead: 0, cacheWrite: 0, output: 0, total: 0, unpricedCacheWriteTokens: 0 }\n }\n const perUnit = (tokens: number, rate: number): number => (tokens * rate) / TOKENS_PER_RATE_UNIT\n const uncachedInput = perUnit(count(usage.uncachedInputTokens), rates.inputCost)\n const output = perUnit(count(usage.outputTokens), rates.outputCost)\n const cacheRead = perUnit(count(usage.cacheReadTokens), rates.cacheReadCost)\n const cacheWriteTokens = count(usage.cacheWriteTokens)\n const cacheWrite = rates.cacheWriteCost === undefined\n ? undefined\n : perUnit(cacheWriteTokens, rates.cacheWriteCost)\n return {\n uncachedInput,\n cacheRead,\n cacheWrite,\n output,\n total: uncachedInput + output + cacheRead + (cacheWrite ?? 0),\n unpricedCacheWriteTokens: rates.cacheWriteCost === undefined ? cacheWriteTokens : 0,\n }\n}\n\n/**\n * Amount text for a session cost.\n *\n * The panel's `money()` convention (2 decimals, 4 below a cent) is right for\n * billing windows, but a live session total starts far below a cent, where\n * `toFixed(4)` would print a flat `$0.0000` — which reads as broken rather than\n * as small. So a total under $0.0001 is stated as a bound instead.\n */\nexport function sessionCostAmount(total: number): string {\n if (!Number.isFinite(total) || total <= 0) return formatMoney(0)\n if (total < 0.0001) return `<$0.0001`\n return total < 0.01 ? formatMoneyExact(total) : formatMoney(total)\n}\n\n/** One `label value` clause of the tooltip. */\nfunction clause(label: string, tokens: number): string | undefined {\n return tokens > 0 ? `${label} ${formatTokensCompact(tokens)}` : undefined\n}\n\n/**\n * Build the composer readout, or undefined when there is nothing honest to show.\n *\n * Undefined is the correct answer for a session with no usage yet, a session\n * another provider served, a model the price table does not know, and a table\n * that has not landed — the pill simply is not there.\n */\nexport function buildSessionCostView(input: SessionCostInput): SessionCostView | undefined {\n const { usage, table, facts } = input\n if (!usage || !table || !facts || facts.pricingKey !== pricingKey(table)) return undefined\n const totals = zeroCostTokens()\n const index = indexTable(table)\n const breakdown: SessionCostBreakdown = { uncachedInput: 0, cacheRead: 0, cacheWrite: 0, output: 0, total: 0, unpricedCacheWriteTokens: 0 }\n let free = true\n let peak = false\n let partial = false\n let priced = false\n const notes: string[] = []\n for (const group of facts.groups) {\n for (const key of COST_TOKEN_KEYS) totals[key] += group.tokens[key]\n if (group.provider !== COMMANDCODE_PROVIDER) { partial = true; continue }\n const price = index.get(group.model)\n if (!price) { partial = true; continue }\n const isFree = price.free === true\n free &&= isFree\n if (price.peak && group.at === null) {\n partial = true\n notes.push('request time unavailable; off-peak lower bound')\n }\n const rates = requestRates(price, group.at, group.contextTokens, table)\n const part = costOf(group.tokens, rates, isFree)\n priced ||= isFree || part.total > 0\n for (const key of ['uncachedInput', 'cacheRead', 'output', 'total', 'unpricedCacheWriteTokens'] as const) breakdown[key] += part[key]\n breakdown.cacheWrite = (breakdown.cacheWrite ?? 0) + (part.cacheWrite ?? 0)\n if (price.peak) {\n const isPeak = group.at !== null && peakHour(group.at, table.peakHours)\n peak ||= isPeak\n notes.push(isPeak ? SESSION_COST_COPY.peakRates : SESSION_COST_COPY.offPeakRates)\n }\n }\n // Both projections must describe the same durable cut. Never decorate token\n // rows from a newer/older fold, and never price an old Host's cumulative usage.\n if (COST_TOKEN_KEYS.some(key => totals[key] !== count(usage[key])) || !priced) return undefined\n const { total, unpricedCacheWriteTokens } = breakdown\n partial ||= unpricedCacheWriteTokens > 0\n free &&= !partial\n if (partial) notes.push('Command Code priced subtotal only; unpriced or other-provider usage excluded')\n notes.push(SESSION_COST_COPY.approximateNote)\n const uncachedInput = totals.uncachedInputTokens\n const output = totals.outputTokens\n const cacheRead = totals.cacheReadTokens\n const cacheWrite = totals.cacheWriteTokens\n // No billed token of any kind means there is nothing to report yet: a `$0.00`\n // pill on a session that has not made a request would be noise, not\n // information, and on a free model it would be redundant.\n if (uncachedInput === 0 && output === 0 && cacheRead === 0 && cacheWrite === 0) return undefined\n\n // Free priced groups do not establish zero spending for unpriced groups.\n // Keep the pure-Free label and real sub-cent amounts, but never a zero subtotal.\n if (!free && total <= 0) return undefined\n\n const value = free\n ? SESSION_COST_COPY.free\n : `${partial ? '≥' : SESSION_COST_COPY.approximate}${sessionCostAmount(total)}`\n const money = (amount: number | undefined): string | undefined =>\n amount === undefined ? undefined : sessionCostAmount(amount)\n // Reading order mirrors the prompt's own order: what was charged at the input\n // rate, then the two cache buckets, then what the model produced.\n const rows: SessionCostBucketRow[] = [\n { key: 'uncachedInput', label: SESSION_COST_COPY.uncachedInput, tokens: uncachedInput, costText: money(breakdown.uncachedInput) },\n { key: 'cacheRead', label: SESSION_COST_COPY.cacheRead, tokens: cacheRead, costText: money(breakdown.cacheRead) },\n { key: 'cacheWrite', label: SESSION_COST_COPY.cacheWrite, tokens: cacheWrite, costText: unpricedCacheWriteTokens === cacheWrite && cacheWrite > 0 ? undefined : money(breakdown.cacheWrite) },\n { key: 'output', label: SESSION_COST_COPY.output, tokens: output, costText: money(breakdown.output) },\n ]\n if (unpricedCacheWriteTokens > 0) notes.push(SESSION_COST_COPY.unpricedCacheWrite)\n // Empty clauses are dropped BEFORE joining: `clause()` returns undefined for a\n // bucket with no tokens, and joining the raw list would leave a `· ·` gap for\n // every absent bucket — a tooltip that reads as a rendering bug.\n const title = ([\n `${SESSION_COST_COPY.panelTitle} ${free ? SESSION_COST_COPY.free : sessionCostAmount(total)}`,\n clause(SESSION_COST_COPY.uncachedInput, uncachedInput),\n clause(SESSION_COST_COPY.output, output),\n clause(SESSION_COST_COPY.cacheRead, cacheRead),\n clause(SESSION_COST_COPY.cacheWrite, cacheWrite),\n ...notes,\n ] as Array<string | undefined>).filter((part): part is string => part !== undefined).join(' · ')\n\n return {\n total,\n value,\n title,\n rows,\n notes: [...new Set(notes)],\n free,\n peak,\n unpricedCacheWriteTokens,\n approximate: !free,\n }\n}\n\n/**\n * The two nodes the text appended to the harness's token-usage pill is made of.\n *\n * The separator is a node of its own because it carries the shipped pill's\n * SEPARATOR colour rather than its label colour; the pill is a flex row whose\n * `gap` already spaces the appended item, so the separator is what makes the\n * result read as one continuous run (`1.2M tokens · Cache hit 87% · $0.0123`)\n * rather than as a value parked at the end of it.\n */\nexport interface SessionCostPillRun {\n /** The shipped pill's own separator glyph. */\n separator: string\n /** The amount, `≈` marker and free word included. */\n value: string\n}\n\n/** Split the appended run into the two nodes the display creates. */\nexport function sessionCostPillRun(view: SessionCostView): SessionCostPillRun {\n return { separator: SESSION_COST_COPY.separator, value: view.value }\n}\n\n/**\n * How the harness's own usage dialog is decorated: one entry per row the\n * shipped component renders, IN ITS OWN ORDER.\n *\n * The price goes on the right of the row it belongs to (`3,206,544 tok $0.07`)\n * rather than in a block of our own rows beneath them, so the dialog keeps the\n * harness's layout and gains nothing to read past.\n *\n * Two rows are special. `cacheHit` carries a percentage, not a count, so it is\n * never priced. `cacheWrite` is HIDDEN and never priced: the pricing page\n * publishes a cache-write rate for a minority of models, so its cell read\n * `unpriced` far more often than a number; its tokens still count toward the\n * total the pill shows.\n */\nexport type SessionCostShippedRow = 'cacheHit' | 'uncachedInput' | 'cacheRead' | 'cacheWrite' | 'output'\n\n/** One shipped dialog row and what to do with it. */\nexport interface SessionCostRowDecoration {\n /** Which shipped row this is. */\n row: SessionCostShippedRow\n /**\n * The exact token count that row must be showing, or undefined for a row that\n * carries no count. The display layer verifies it before decorating anything:\n * the shipped labels are the `chat` locale's own strings (never English), so\n * rows are matched POSITIONALLY and this is what proves the position is right.\n */\n tokens: number | undefined\n /** The price to append to the row's value, or undefined to leave it alone. */\n amount: string | undefined\n /** Whether the row is dropped from the dialog entirely. */\n hidden: boolean\n}\n\n/**\n * Decorate the harness's usage dialog, row by row.\n *\n * The row sequence mirrors the shipped component's conditions exactly — the\n * cache-hit row exists while there is billed prompt input, the cache-write row\n * while those tokens are non-zero — because the display layer matches what it\n * finds positionally. A shape it cannot confirm is a shape it does not touch.\n *\n * A free model decorates nothing: every row's cost is zero by definition, the\n * pill already says `Free`, and a column of `$0.00` would be noise. A bucket\n * whose rate the page does not publish is likewise left unfilled rather than\n * filled with an invented number.\n */\nexport function sessionCostRowDecorations(view: SessionCostView): SessionCostRowDecoration[] {\n const bucket = (key: SessionCostBucketRow['key']): number =>\n view.rows.find((row) => row.key === key)?.tokens ?? 0\n const price = (key: SessionCostBucketRow['key']): string | undefined => {\n if (view.free) return undefined\n return view.rows.find((row) => row.key === key)?.costText\n }\n const uncachedInput = bucket('uncachedInput')\n const cacheRead = bucket('cacheRead')\n const cacheWrite = bucket('cacheWrite')\n const output = bucket('output')\n const plan: SessionCostRowDecoration[] = []\n if (uncachedInput + cacheRead + cacheWrite > 0) {\n plan.push({ row: 'cacheHit', tokens: undefined, amount: undefined, hidden: false })\n }\n plan.push({ row: 'uncachedInput', tokens: uncachedInput, amount: price('uncachedInput'), hidden: false })\n plan.push({ row: 'cacheRead', tokens: cacheRead, amount: price('cacheRead'), hidden: false })\n if (cacheWrite !== 0) {\n // Hidden only when the page publishes NO cache-write rate: those tokens are\n // genuinely unpriced, the note says so, and the row would otherwise show a\n // blank cell. When the rate IS known its price is part of the total, so the\n // row must stay — hiding a row whose cost the pill already counts leaves the\n // visible rows unable to explain the figure above them.\n const amount = price('cacheWrite')\n plan.push({ row: 'cacheWrite', tokens: cacheWrite, amount, hidden: amount === undefined })\n }\n plan.push({ row: 'output', tokens: output, amount: price('output'), hidden: false })\n return plan\n}\n","/**\n * The DOM half of the composer's session-cost figure (browser only).\n *\n * The cost is not a surface of its own any more: it is injected INTO the two\n * surfaces the harness already draws under the composer — the token-usage pill\n * (`1.2M tokens · Cache hit 87%`) and the usage dialog that pill opens. This\n * module owns that injection; `./session-cost.ts` owns every number and every\n * string, and `./session-cost-view.tsx` owns the two seats the figures come\n * from.\n *\n * Why inject rather than take the pill's cell over (registering a `stats` entry\n * REPLACES the shipped readout, it does not extend it): the shipped row is one\n * component owning its tokens / cache-hit / duration figures through the `chat`\n * locale namespace, and its cache-hit percentage obeys an exact-integer rule\n * this plugin must not re-derive. Owning that cell would mean reproducing all of\n * it in English, and every upstream change to it would stop reaching users. So\n * the shipped markup stays the harness's, and this module adds exactly two\n * things to it.\n *\n * Four properties make that safe, all verified against the shipped build:\n *\n * 1. **The dialog's rows are styled by ELEMENT.** `dsh-client-ui-chat`'s\n * `stat-dialog` module styles its `dl` as a two-column grid and then\n * `.details dt` / `.details dd` — not by class. A price node appended INSIDE a\n * shipped value cell therefore inherits that cell's tabular numerals and right\n * alignment for free, and this plugin ships no CSS at all.\n * 2. **The dialog's rows are matched by POSITION and confirmed by value.** Their\n * labels are the `chat` locale's own strings (`Uncached input` in English,\n * `未缓存输入` in Chinese), so no label is ever read. Instead the shape is\n * predicted from the session's buckets — the cache-hit row exists while there\n * is billed prompt input, the cache-write row while those tokens are non-zero\n * — and each value cell must then carry exactly the token count predicted for\n * it. A dialog that does not confirm is left alone.\n * 3. **The pill keeps the cost visible when space runs out.** The button is an\n * inline flex row with `gap`, and its label carries `min-width:0` plus\n * ellipsis; our appended span keeps the default `min-width:auto`, so the\n * LABEL is what truncates. The cost also inherits the button's `font:inherit`\n * and `tabular-nums` typography and its hover/expanded tint.\n * 4. **React owns those value cells' text, so a price is re-attached, never\n * assumed.** The shipped component renders each count as a single string, and\n * React rewrites such a cell through `textContent` when the count changes —\n * which drops every child with it, our price included. Every sync therefore\n * re-checks that the node is still where it was put; the cost of that is a\n * read, and the alternative is a price that silently disappears mid-session.\n *\n * A `MutationObserver` on `document.body` with `childList` (deliberately NOT\n * `subtree`, so streaming text never wakes it) is the only way to learn that the\n * dialog — which is portaled straight onto `body`, with no slot of ours inside\n * it — has opened or closed. That observer is also what decorates a newly opened\n * dialog from the last view this module was handed.\n *\n * @module dsh-commandcode-provider/client/session-cost-display\n */\n\nimport type { SessionCostPillRun, SessionCostRowDecoration, SessionCostShippedRow, SessionCostView } from './session-cost.ts'\nimport {\n SESSION_COST_COPY,\n sessionCostPillRun,\n sessionCostRowDecorations,\n} from './session-cost.ts'\n\n/**\n * The shipped composer stats row (dsh-client-ui-chat `StatsPills`).\n *\n * A PREFERENCE, not a requirement: 0.1.6-alpha.2 dropped this attribute from the\n * row's root while leaving the rest of the markup identical, so a lookup that\n * insisted on it would silently stop finding the row on that engine. When it is\n * absent the search falls back to the dock OUTLET — deliberately the outlet and\n * never the outlet's parent, because from 0.1.6-alpha.2 the parent is the new\n * composer footer, which holds the `ContextMeter` as well, and that meter's\n * trigger is itself a `button[aria-haspopup=\"dialog\"]` rendered AFTER the dock.\n * A parent-scoped \"last trigger wins\" would therefore append the cost to the\n * context ring instead of the token pill.\n */\nconst STATS_ROOT = '[data-composer-stats]'\n\n/**\n * The shipped token-usage dialog's `<dl>`. Unique WITHIN one `StatsPills`\n * render: the per-message turn-usage panel has its own dialog with different\n * markup, so a single composer's usage dialog is unambiguous. It is not unique\n * across the document once two composers are live — see {@link resolveDialog}.\n */\nconst USAGE_DIALOG = '[data-session-stats-usage]'\n\n/**\n * The usage dialog's trigger. Both pills announce a dialog, but the token one is\n * rendered LAST — and when no step carries timing the time pill is not a button\n * at all, so \"last\" still selects the token pill in both cases.\n */\nconst DIALOG_TRIGGER = 'button[aria-haspopup=\"dialog\"]'\n\n/**\n * Stable id for the hidden node the appended cost is described by. The pill's\n * own `aria-label` is computed by the harness on every render and cannot be\n * extended, so a description is how the cost reaches assistive technology.\n */\nconst A11Y_ID = 'dsh-commandcode-session-cost'\n\n/** How many consecutive misses before the missing anchor is worth a console line. */\nconst MISSES_BEFORE_WARNING = 3\n\n/**\n * How the display learns that the shipped usage dialog opened or closed.\n *\n * `target` is `document.body`, and the returned function detaches. The default\n * is a `MutationObserver`; the seam exists so tests can announce the dialog\n * without a global observer (the repository's usual injected-seam shape).\n */\nexport type SessionCostObserverFactory = (target: Node, listener: () => void) => (() => void) | undefined\n\n/**\n * The default observer: `childList` on `body`, and deliberately NOT `subtree`, so\n * streaming text inside the page never wakes it while the panel the harness\n * portals straight onto `body` does.\n */\nconst observeBodyChildren: SessionCostObserverFactory = (target, listener) => {\n if (typeof MutationObserver === 'undefined') return undefined\n const observer = new MutationObserver(listener)\n observer.observe(target, { childList: true })\n return () => observer.disconnect()\n}\n\n/** What the display layer reads: the injected document and where to look in it. */\nexport interface SessionCostDisplayOptions {\n /** The document to inject into (injected so node tests can drive a double). */\n doc: Document\n /**\n * The composer that owns this entry — our own outlet wrapper's parent, so a\n * session-scoped composer looks in its OWN card rather than at whichever\n * `[data-composer-stats]` happens to come first in the document.\n */\n scope: () => ParentNode | null\n /** Observer seam; defaults to a `childList` `MutationObserver` on `body`. */\n observe?: SessionCostObserverFactory\n}\n\n/**\n * Owns the nodes injected into the shipped token-usage UI.\n *\n * One instance per mounted entry. `sync()` is cheap and idempotent: it re-reads\n * both targets on every call, which is what lets it self-heal when React\n * remounts the row or replaces the dialog, and it rewrites a node only when its\n * text actually changed.\n */\nexport class SessionCostDisplay {\n private readonly doc: Document\n private readonly scope: () => ParentNode | null\n private readonly observe: SessionCostObserverFactory\n private view: SessionCostView | undefined = undefined\n /** Detaches the observer installed by `start()`. */\n private detach: (() => void) | undefined = undefined\n /** The button we appended into, while it is still connected. */\n private pillHost: Element | undefined = undefined\n /** Our appended root, and the two nodes whose text changes. */\n private pillRoot: HTMLElement | undefined = undefined\n private pillValue: HTMLElement | undefined = undefined\n private pillA11y: HTMLElement | undefined = undefined\n /** Whether WE set `aria-describedby` on the button (so only we take it back). */\n private described = false\n /** The dialog we decorated, the price nodes we own, and the cells we hid. */\n private dialogHost: Element | undefined = undefined\n private dialogPrices = new Map<HTMLElement, HTMLElement>()\n private dialogHidden = new Set<HTMLElement>()\n private pillMisses = 0\n\n constructor(options: SessionCostDisplayOptions) {\n this.doc = options.doc\n this.scope = options.scope\n this.observe = options.observe ?? observeBodyChildren\n }\n\n /** Begin watching for the shipped usage dialog opening and closing. */\n start(): void {\n if (this.detach !== undefined) return\n const body = this.doc.body\n if (body === null || body === undefined) return\n this.detach = this.observe(body, () => this.apply())\n }\n\n /**\n * Hand the display the current figure.\n *\n * Undefined — nothing priceable about this session — removes everything this\n * module injected, leaving both shipped surfaces exactly as they ship.\n */\n sync(view: SessionCostView | undefined): void {\n this.view = view\n this.apply()\n }\n\n /** Remove every injected node and stop observing. Safe to call twice. */\n dispose(): void {\n this.detach?.()\n this.detach = undefined\n this.removePill()\n this.clearDialog()\n this.view = undefined\n }\n\n /** Re-apply the last known view to whatever both targets are right now. */\n private apply(): void {\n this.applyPill()\n this.applyDialog()\n }\n\n // -------------------------------------------------------------------------\n // The pill: the cost as the last item of the shipped token pill's text run\n // -------------------------------------------------------------------------\n\n private applyPill(): void {\n const view = this.view\n if (view === undefined) {\n this.removePill()\n return\n }\n if (this.pillHost?.isConnected !== true) {\n const button = this.resolvePillButton()\n if (button === null) {\n this.pillMisses += 1\n if (this.pillMisses === MISSES_BEFORE_WARNING) {\n console.warn(\n '[dsh-commandcode-provider] no shipped token pill in this composer\\'s dock outlet to append the session cost to; the figure stays in the usage dialog only',\n )\n }\n return\n }\n this.pillMisses = 0\n this.removePill()\n this.buildPill(button, sessionCostPillRun(view))\n }\n if (this.pillValue !== undefined) {\n const amount = sessionCostPillRun(view).value\n if (this.pillValue.textContent !== amount) this.pillValue.textContent = amount\n }\n if (this.pillRoot !== undefined) {\n if (this.pillRoot.title !== view.title) this.pillRoot.title = view.title\n const approximate = view.approximate ? 'true' : null\n if (this.pillRoot.getAttribute('data-approximate') !== approximate) {\n if (approximate === null) this.pillRoot.removeAttribute('data-approximate')\n else this.pillRoot.setAttribute('data-approximate', approximate)\n }\n }\n if (this.pillA11y !== undefined) {\n const described = `${SESSION_COST_COPY.panelTitle} ${view.value}`\n if (this.pillA11y.textContent !== described) this.pillA11y.textContent = described\n }\n }\n\n /**\n * The shipped token pill, scoped to this entry's own composer.\n *\n * The scope is the dock OUTLET (`display: contents`, one per slot), which holds\n * exactly that slot's entries — the shipped `stats` cell and ours, in their\n * registration order. {@link STATS_ROOT} narrows that to the stats row on the\n * engines that still mark it; on the engines that do not, the outlet is\n * already the narrowest correct container, because the composer footer's\n * `ContextMeter` sits BESIDE the outlet rather than inside it.\n *\n * A missing scope is \"no pill\", never a document-wide search: the outlet is\n * what makes this lookup per-composer, and a second composer can be live at\n * once (0.1.6-alpha.2 mounts an embedded Conversation in the sidebar).\n */\n private resolvePillButton(): Element | null {\n const scope = this.scope()\n if (scope === null) return null\n const root = scope.querySelector(STATS_ROOT) ?? scope\n const triggers = root.querySelectorAll(DIALOG_TRIGGER)\n return triggers.length === 0 ? null : (triggers[triggers.length - 1] ?? null)\n }\n\n /**\n * Create and append the cost run. The button's child list is static\n * (`[svg, label]`), so appending once is enough for it to stay last.\n */\n private buildPill(button: Element, run: SessionCostPillRun): void {\n const doc = this.doc\n const root = doc.createElement('span')\n root.setAttribute('data-composer-session-cost', '')\n // The separator is its own node so it can carry the shipped pill's separator\n // colour. Its LEFT spacing comes from the button's flex gap; the right margin\n // reproduces the shipped separator's `margin:0 6px` rhythm, so the run reads\n // `tokens · Cache hit 87% · $0.0123` at one consistent rhythm.\n const separator = doc.createElement('span')\n separator.textContent = run.separator\n separator.setAttribute('aria-hidden', 'true')\n separator.style.color = 'var(--dsw-alias-separator-primary)'\n separator.style.margin = '0 6px 0 0'\n const value = doc.createElement('span')\n value.textContent = run.value\n value.style.fontWeight = '500'\n // Referenced by the button's `aria-describedby`: a hidden node named by id is\n // still read out, which is how the cost survives the aria-label override.\n const a11y = doc.createElement('span')\n a11y.id = A11Y_ID\n a11y.style.display = 'none'\n root.appendChild(separator)\n root.appendChild(value)\n root.appendChild(a11y)\n button.appendChild(root)\n // Only ever claim the attribute when the button has none of its own: a\n // shipped `aria-describedby` is the harness's, and overwriting it would\n // delete a description we cannot restore.\n if (!button.hasAttribute('aria-describedby')) {\n button.setAttribute('aria-describedby', A11Y_ID)\n this.described = true\n }\n this.pillHost = button\n this.pillRoot = root\n this.pillValue = value\n this.pillA11y = a11y\n }\n\n private removePill(): void {\n if (this.pillRoot !== undefined && this.pillRoot.parentNode !== null) {\n this.pillRoot.parentNode.removeChild(this.pillRoot)\n }\n if (this.described) {\n this.pillHost?.removeAttribute('aria-describedby')\n this.described = false\n }\n this.pillHost = undefined\n this.pillRoot = undefined\n this.pillValue = undefined\n this.pillA11y = undefined\n }\n\n // -------------------------------------------------------------------------\n // The dialog: a price on the right of each token row the harness already draws\n // -------------------------------------------------------------------------\n\n private applyDialog(): void {\n const view = this.view\n const host = view === undefined ? null : this.resolveDialog()\n if (host === null || view === undefined) {\n this.clearDialog()\n return\n }\n this.pruneDialog(host)\n const plan = sessionCostRowDecorations(view)\n const pairs = dialogPairs(host)\n if (!dialogShapeMatches(pairs, plan, this.dialogPrices)) {\n // The dialog is not the shape this session's buckets predict — a different\n // build, or a projection carrying values the counts cannot explain. Leave\n // it exactly as the harness drew it rather than pricing the wrong row.\n this.clearDialog()\n return\n }\n const hidden = new Set<HTMLElement>()\n for (const [index, row] of plan.entries()) {\n const pair = pairs[index]\n if (pair === undefined) continue\n const span = this.dialogPrices.get(pair.dd)\n if (row.hidden) {\n // The row is dropped: both cells, or the grid leaves an empty label\n // behind. An inline `display` survives the harness's own re-renders\n // (React pins no style on these nodes) and is given back on disposal.\n if (pair.dt.style.display !== 'none') pair.dt.style.display = 'none'\n if (pair.dd.style.display !== 'none') pair.dd.style.display = 'none'\n hidden.add(pair.dt)\n hidden.add(pair.dd)\n this.removeDialogPrice(pair.dd, span)\n continue\n }\n if (pair.dt.style.display === 'none') pair.dt.style.display = ''\n if (pair.dd.style.display === 'none') pair.dd.style.display = ''\n if (row.amount === undefined) {\n this.removeDialogPrice(pair.dd, span)\n continue\n }\n const price = span ?? this.createDialogPrice(pair.dd, row.row)\n // React owns this cell's text and rewrites it through `textContent` when\n // the count changes, which drops every child with it — so the price is\n // re-attached on a miss rather than assumed to still be there.\n if (price.parentNode !== pair.dd) pair.dd.appendChild(price)\n if (price.textContent !== row.amount) price.textContent = row.amount\n }\n // Cells hidden by an earlier shape (a cache-write row React then rewrote) go\n // back to the harness.\n for (const cell of [...this.dialogHidden]) {\n if (hidden.has(cell)) continue\n if (cell.style.display === 'none') cell.style.display = ''\n this.dialogHidden.delete(cell)\n }\n for (const cell of hidden) this.dialogHidden.add(cell)\n this.dialogHost = host\n }\n\n /** Forget the cells and prices a re-rendered dialog took with it. */\n private pruneDialog(host: Element): void {\n for (const [dd, price] of [...this.dialogPrices]) {\n if (dd.parentNode === host) continue\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n this.dialogPrices.delete(dd)\n }\n for (const cell of [...this.dialogHidden]) {\n if (cell.parentNode === host) continue\n // The dialog was re-rendered and this cell went with the old tree. Give\n // the style back BEFORE dropping the reference: a detached node can be\n // recycled by the next render (React reuses DOM nodes across a remount of\n // the same shape), and a surviving `display: none` would hide a row of a\n // dialog we are no longer decorating — with nothing left tracking it to\n // restore it later.\n if (cell.style.display === 'none') cell.style.display = ''\n this.dialogHidden.delete(cell)\n }\n }\n\n /** The price node for one shipped value cell, appended as its last child. */\n private createDialogPrice(dd: HTMLElement, row: SessionCostShippedRow): HTMLElement {\n const price = this.doc.createElement('span')\n price.setAttribute('data-session-cost-price', row)\n // The cell is right-aligned over tabular numerals, so a fixed-width\n // inline-block lines the prices up as a column of their own to the right of\n // the counts instead of trailing each count raggedly.\n price.style.marginLeft = '6px'\n price.style.display = 'inline-block'\n price.style.minWidth = '56px'\n price.style.textAlign = 'right'\n price.style.fontWeight = '500'\n dd.appendChild(price)\n this.dialogPrices.set(dd, price)\n return price\n }\n\n private removeDialogPrice(dd: HTMLElement, price: HTMLElement | undefined): void {\n if (price === undefined) return\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n this.dialogPrices.delete(dd)\n }\n\n /**\n * The shipped usage dialog, or null while it is closed (or ambiguous).\n *\n * The dialog is portaled onto `body`, so unlike the pill it cannot be scoped\n * from this entry, and the attribute is unique per DIALOG rather than per\n * document. While one composer was guaranteed, a document-level lookup was\n * exact. 0.1.6-alpha.2 ends that guarantee: it mounts an embedded Conversation\n * in the sidebar, so a second composer — with its own session, its own dock\n * and its own dialog — can be live and open at the same time.\n *\n * There is no DOM link from a dialog back to its trigger (the portaled panel\n * carries no id and no `aria-controls`), so with two dialogs open document\n * order says nothing about ownership. The shape confirmation in\n * {@link dialogShapeMatches} would usually reject the stranger, but it compares\n * against THIS entry's counts, so a coincidentally matching dialog would be\n * priced with another session's figures. Ambiguity is therefore answered by\n * declining to decorate at all — the same rule the shape check already\n * follows, applied one level up: a dialog we cannot prove is ours is left\n * alone.\n */\n private resolveDialog(): Element | null {\n if (this.dialogHost?.isConnected === true) return this.dialogHost\n // The dialog we injected into is gone: our nodes went with it, so only the\n // bookkeeping is left to drop.\n this.clearDialog()\n const dialogs = this.doc.querySelectorAll(USAGE_DIALOG)\n return dialogs.length === 1 ? (dialogs[0] ?? null) : null\n }\n\n /** Give the dialog back: every price removed, every hidden row restored. */\n private clearDialog(): void {\n for (const price of this.dialogPrices.values()) {\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n }\n this.dialogPrices.clear()\n for (const cell of this.dialogHidden) {\n if (cell.style.display === 'none') cell.style.display = ''\n }\n this.dialogHidden.clear()\n this.dialogHost = undefined\n }\n}\n\n/** The shipped dialog's `dt`/`dd` pairs, in document order. */\nfunction dialogPairs(host: Element): Array<{ dt: HTMLElement; dd: HTMLElement }> {\n const pairs: Array<{ dt: HTMLElement; dd: HTMLElement }> = []\n let label: HTMLElement | null = null\n for (const node of Array.from(host.childNodes)) {\n const tag = tagNameOf(node)\n if (tag === 'DT') label = node as HTMLElement\n else if (tag === 'DD' && label !== null) {\n pairs.push({ dt: label, dd: node as HTMLElement })\n label = null\n }\n }\n return pairs\n}\n\n/** `tagName` upper-cased, or an empty string for a non-element node. */\nfunction tagNameOf(node: Node): string {\n const tag = (node as Element).tagName\n return typeof tag === 'string' ? tag.toUpperCase() : ''\n}\n\n/**\n * Whether the dialog really holds the rows this session's buckets predict.\n *\n * The shipped labels belong to the `chat` locale — they are `Uncached input` in\n * English and something else entirely in Chinese — so rows are matched by\n * POSITION, and this is what makes that safe: the row count must agree, the\n * cache-hit row must be the percentage it is, and every other value must carry\n * exactly the token count of the bucket predicted for it. A mismatch means the\n * dialog is not what this view describes, and nothing is decorated.\n */\nfunction dialogShapeMatches(\n pairs: ReadonlyArray<{ dt: HTMLElement; dd: HTMLElement }>,\n plan: readonly SessionCostRowDecoration[],\n prices: ReadonlyMap<HTMLElement, HTMLElement>,\n): boolean {\n if (pairs.length !== plan.length) return false\n return plan.every((row, index) => {\n const pair = pairs[index]\n if (pair === undefined) return false\n const text = hostValueText(pair.dd, prices.get(pair.dd))\n if (row.tokens === undefined) return text.includes('%')\n return digitsOf(text) === String(row.tokens)\n })\n}\n\n/**\n * A value cell's own text, without the price this module appended to it — the\n * digits of `3,206,544 tok` are the host's, the digits of `$0.07` are ours.\n */\nfunction hostValueText(dd: HTMLElement, price: HTMLElement | undefined): string {\n let text = ''\n for (const node of Array.from(dd.childNodes)) {\n if (node === price) continue\n text += node.textContent ?? ''\n }\n return text\n}\n\n/** Every digit of a display string, so locale grouping cannot break the match. */\nfunction digitsOf(text: string): string {\n return text.replace(/\\D/g, '')\n}\n","/**\n * The composer's live session-cost figure (browser half).\n *\n * This component renders NO surface of its own. The cost lives inside the\n * harness's own token-usage UI: the amount becomes the last item of the shipped\n * pill's text run (`1.2M tokens · Cache hit 87% · $0.0123`) and the per-bucket\n * breakdown becomes extra rows in the usage dialog that pill opens.\n * `./session-cost-display.ts` owns that injection and `./session-cost.ts` owns\n * every number and every string; this file owns nothing but the two seats the\n * figures come from and the lifetime of the injection.\n *\n * It is still registered as an entry in `conversation.composer.dock`, because\n * that registration is what delivers the seats: `useProjection` is a standard\n * prop the composer hands every dock occupant, so there is no other way to read\n * the session's token accounting. Registering under the shipped `stats` cell's\n * id instead would REPLACE the harness's readout rather than extend it;\n * `./session-cost-display.ts` records why that trade is refused.\n *\n * The rendered node is a hidden marker — `display:none`, so it can add neither a\n * box nor a flex gap to the composer card. It exists to locate THIS composer\n * from the entry (`closest()` on the dock's outlet anchor), so a session-scoped\n * composer reads its own card rather than whichever row comes first in the\n * document. It is rendered only while there is something to show, so a session\n * with nothing priceable contributes no markup at all.\n *\n * Two seats are read, from two different owners: `useProjection` comes from the\n * composer (a standard prop of the dock, not part of this registration), and\n * `useCommandCodePrices` comes from our own registration's `inject` face, which\n * `bindInjectSources` re-exposes from the `hooks` compartment. Reading\n * `props.hooks.*` instead finds `undefined` at runtime and crashes the render,\n * which the slot renderer contains by ABDICATING the entry — a surface that\n * vanishes with no visible error.\n *\n * Both effects are `useEffect`, never `useLayoutEffect`: there is nothing on\n * screen to align with (the injection is a text run and a hidden marker), and a\n * layout effect would log a warning from the server render the tests use.\n *\n * @module dsh-commandcode-provider/client/session-cost-view\n */\n\nimport type { SessionCostFacts } from '../cost-facts.ts'\nimport { useEffect, useRef } from 'react'\nimport type { SnapshotStore } from './snapshot-store.ts'\nimport type { SessionCostPricesState } from './prices.ts'\nimport { SessionCostDisplay } from './session-cost-display.ts'\nimport {\n buildSessionCostView,\n type SessionModelSelectionProjection,\n type SessionUsageBuckets,\n} from './session-cost.ts'\n\n/**\n * The dock outlet this entry renders inside, i.e. what it scopes itself from.\n *\n * The OUTLET itself, not its parent. The outlet is one `display:contents` div\n * holding exactly this slot's entries (the shipped `stats` cell and ours), so it\n * is the narrowest container that is still per-composer. Its parent is NOT:\n * from 0.1.6-alpha.2 the composer stacks the dock inside a footer that also\n * holds the `ContextMeter`, whose trigger is another\n * `button[aria-haspopup=\"dialog\"]` rendered after the dock — scoping to the\n * parent would let the cost land on the context ring.\n */\nconst DOCK_ANCHOR = '[data-slot=\"conversation.composer.dock\"]'\n\n/** Module-level constant so the marker's `style` prop never diffs. */\nconst HIDDEN_STYLE = { display: 'none' } as const\n\n/**\n * The injected face this registration carries. Bound by the client entry so the\n * component stays unaware of the Remote, the controller, and its caching.\n *\n * NOTE the split from {@link SessionCostComponentProps}: the renderer\n * destructures this face's `hooks` compartment and re-exposes each member as a\n * `use<Name>` prop (`commandCodePrices` → `useCommandCodePrices`); it does not\n * hand the component this object verbatim.\n */\nexport interface SessionCostInjected {\n hooks: {\n commandCodePrices: SnapshotStore<SessionCostPricesState>\n }\n}\n\n/**\n * The projection keys this readout reads, declared structurally because the\n * plugin bundle does not depend on the session-controller package (whose\n * `UseProjection` this mirrors).\n */\ninterface ProjectionSeats {\n commandCodeCost: SessionCostFacts\n tokenUsage: SessionUsageBuckets\n modelSelection: SessionModelSelectionProjection\n}\n\n/** The projection reader the composer supplies to every dock occupant. */\nexport interface UseProjectionLike {\n <K extends keyof ProjectionSeats>(key: K): ProjectionSeats[K] | undefined\n <K extends keyof ProjectionSeats, S>(\n key: K,\n selector: (value: ProjectionSeats[K] | undefined) => S,\n eq?: (a: S, b: S) => boolean,\n ): S\n}\n\n/** The props this component actually receives. */\nexport interface SessionCostComponentProps {\n useCommandCodePrices<T>(selector: (state: SessionCostPricesState) => T): T\n useProjection: UseProjectionLike\n}\n\n/** Log a missing seat once per page, so a silent no-op stays diagnosable. */\nlet warnedMissingSeat = false\n\n/**\n * The composer's session-cost entry. Guards the two seats before rendering the\n * mount: a dsh that does not supply the projection seat to dock occupants gets\n * an absent cost and one console line, never a render crash — which the renderer\n * would answer by abdicating the entry with no visible trace.\n */\nexport function CommandCodeSessionCost(props: SessionCostComponentProps) {\n if (typeof props.useProjection !== 'function' || typeof props.useCommandCodePrices !== 'function') {\n if (!warnedMissingSeat) {\n warnedMissingSeat = true\n console.error(\n '[dsh-commandcode-provider] the composer does not supply the projection/hook seats the session-cost readout needs; the readout stays hidden',\n )\n }\n return null\n }\n return <SessionCostEntry {...props} />\n}\n\n/** The mount: one injection lifetime, one hidden marker. Every hook lives here. */\nfunction SessionCostEntry(props: SessionCostComponentProps) {\n const markerRef = useRef<HTMLSpanElement | null>(null)\n const displayRef = useRef<SessionCostDisplay | null>(null)\n const prices = props.useCommandCodePrices((state) => state)\n const usage = props.useProjection('tokenUsage')\n const selection = props.useProjection('modelSelection')\n const facts = props.useProjection('commandCodeCost')\n const view = buildSessionCostView({ usage, selection, facts, table: prices.table, now: Date.now() })\n\n useEffect(() => {\n // No DOM outside a browser: the server render used by the tests, and a\n // node-hosted assembly, must both stay no-ops.\n if (typeof document === 'undefined') return\n const display = new SessionCostDisplay({\n doc: document,\n scope: () => markerRef.current?.closest(DOCK_ANCHOR) ?? null,\n })\n displayRef.current = display\n display.start()\n return () => {\n displayRef.current = null\n display.dispose()\n }\n }, [])\n\n // Every render: the projection is a fresh fold, so there is nothing cheaper to\n // compare than the plan the display derives from it — and the display rewrites\n // a node only when that node's own text actually moved.\n useEffect(() => {\n displayRef.current?.sync(view)\n })\n\n if (view === undefined) return null\n return <span ref={markerRef} style={HIDDEN_STYLE} data-ccp-session-cost-anchor=\"\" />\n}\n","/**\n * Stylesheet for the Command Code settings page — and the Models-page provider\n * card, which shares its `cc-` classes.\n *\n * Returned as a string rather than injected here so the modules stay free of\n * DOM side effects at import time: `./index.ts` installs it once, keyed by\n * `PAGE_CSS_ID`. It is a module of its own rather than a literal inside the\n * client entry so `tests/styles.test.ts` can audit every rule without importing\n * the React tree (which pulls `*.module.css` through the primitives package and\n * needs a loader registered first).\n *\n * Every colour comes from a harness theme alias with a neutral fallback, so the\n * page follows the active theme (light/dark and any brand pack) without\n * hardcoded values. Classes are `cc-` prefixed to stay clear of the panel's\n * `ccp-` set.\n *\n * @module dsh-commandcode-provider/client/page-styles\n */\n\n/**\n * Stylesheet id (the `data-plugin-css` value that makes injection idempotent).\n *\n * The package prefix must match the one the panel stylesheet uses\n * (`PANEL_CSS_ID` in `./panel-styles.ts`) and this package's real name: an id is\n * the injection's identity, so a stale fork prefix would let a second copy of\n * the plugin inject the same rules twice and would misreport the owner in the\n * DOM. The two ids must also stay distinct from each other — they key two\n * separate style tags, and a shared id would make the second injection a no-op\n * that silently drops one stylesheet.\n */\nexport const PAGE_CSS_ID = '@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css'\n\n/** The settings-page stylesheet. */\nexport const PAGE_CSS = `\n.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}\n.cc-title{margin:0;font-size:18px;font-weight:600}\n.cc-intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}\n.cc-readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.cc-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:4px 16px}\n.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}\n.cc-field+.cc-field{border-top:1px solid var(--dsw-alias-border-l2)}\n.cc-fieldHead{align-items:center;gap:8px;display:flex}\n.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}\n.cc-badges{align-items:center;gap:8px;display:inline-flex}\n.cc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}\n.cc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}\n.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}\n.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}\n.cc-reset:disabled{cursor:default;opacity:.5}\n.cc-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}\n.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}\n.cc-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n/* The routing-rule model multi-select: a button trigger that opens an\n * anchored Menu of checkbox rows. The trigger mirrors .cc-input sizing so it\n * sits flush with the sibling account select. */\n.cc-ruleTrigger{align-items:center;gap:8px;display:flex;width:100%;text-align:left;cursor:pointer}\n.cc-ruleTrigger:disabled{cursor:default}\n.cc-ruleTriggerText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.cc-ruleCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg)}\n.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}\n.cc-checkRow:hover{cursor:pointer}\n.cc-check{appearance:none;flex-shrink:0;width:15px;height:15px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-bg-layer-1);position:relative}\n.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}\n.cc-check:checked::after{content:'';position:absolute;top:2px;left:5px;width:3px;height:7px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}\n.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* The model multi-select search box: stacked under the trigger while the\n * dropdown is open, same input sizing so the pair reads as one control. The\n * box lives inside the Menu anchor (which renders inside the Menu's root\n * span), so focusing/typing it never trips the Menu's outside-click close. */\n.cc-modelSelectAnchor{flex-direction:column;gap:6px;display:flex;width:100%}\n.cc-modelSearch{width:100%}\n.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}\n/* Selects need their own treatment to sit flush with the text inputs:\n * the UA stylesheet renders <select> border-box (34px total vs the inputs'\n * 36px) and forces its own menulist text metrics, so drop the native\n * chrome entirely (appearance:none), restore content-box so the outer box\n * matches the inputs again, and draw the chevron ourselves. Longhand\n * background-* only — the shorthand would reset .cc-input's background. */\nselect.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box-sizing:content-box;padding-right:32px;background-image:url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23888f98' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 11px center}\n.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}\n.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}\n/* The Advanced card: its header row is one full-width toggle button; the\n * chevron is two borders on a rotated square (no icon dependency). */\n.cc-advancedHead{align-items:center;gap:8px;display:flex;width:100%;padding:12px 0;background:0 0;border:none;cursor:pointer;font:inherit;text-align:left}\n.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}\n.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}\n.cc-advancedSpacer{flex:1}\n.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:8px;height:8px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg);transition:transform .15s ease}\n.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}\n.cc-advancedBody{flex-direction:column;display:flex}\n.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}\n.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}\n/* Keep the original footer in flow and inside the settings scrollport. */\n.cc-footerMarker{height:1px;margin:-6px 0 -7px;pointer-events:none}\n.cc-footerSticky{position:sticky;bottom:0;z-index:2;flex-shrink:0;min-height:48px;pointer-events:none}\n.cc-footerActions{align-items:center;gap:8px;display:flex;pointer-events:auto}\n.cc-footerFloating .cc-footerActions{padding:6px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2));box-shadow:0 8px 24px rgba(0,0,0,.12)}\n.cc-accountEditor{border-top:1px solid var(--dsw-alias-border-l2)}\n.cc-accountLoginHint{padding:0 0 12px}\n.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}\n.cc-toggleRow:has(.cc-toggle:disabled){cursor:default}\n.cc-toggle{appearance:none;flex-shrink:0;background:var(--dsw-alias-border-l2);border-radius:999px;width:30px;height:18px;margin:0;cursor:pointer;position:relative;transition:background .15s ease}\n.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}\n.cc-toggle::after{content:'';background:#fff;border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px;transition:left .15s ease}\n.cc-toggle:checked::after{left:14px}\n.cc-toggle:disabled{cursor:default;opacity:.5}\n.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}\n.cc-usageCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:14px 16px;flex-direction:column;gap:12px;display:flex}\n.cc-usageHead{align-items:center;gap:8px;display:flex}\n.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}\n.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}\n.cc-usagePlan{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}\n.cc-usagePlanStatus{white-space:nowrap;color:var(--dsw-alias-label-error);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}\n.cc-usageRefresh{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}\n.cc-usageRefresh:hover:not(:disabled){color:var(--dsw-alias-label-primary)}\n.cc-usageRefresh:disabled{cursor:default;opacity:.5}\n.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.cc-usageError{align-items:center;gap:8px;color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5;display:flex}\n.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}\n.cc-usageStat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex}\n.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}\n.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}\n.cc-usageWindows{flex-direction:column;gap:16px;display:flex}\n.cc-usageWindow{flex-direction:column;gap:6px;display:flex}\n.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}\n.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;font-weight:500;line-height:1.5}\n.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:1.5}\n.cc-usageExceeded{color:var(--dsw-alias-label-error);font-size:11px;font-weight:500;line-height:1.5}\n.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:6px}\n.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.cc-usageBarFillWarn{background:var(--dsw-alias-label-error)}\n@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle,.cc-toggle::after,.cc-usageBarFill{transition:none}}.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}\n.cc-usageMeta{align-items:center;gap:8px;display:flex}\n.cc-accountReport{flex-direction:column;gap:12px;display:flex}\n.cc-tabs{flex-wrap:wrap;gap:6px;display:flex}\n.cc-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}\n.cc-tab:hover:not(.cc-tabActive){color:var(--dsw-alias-label-primary)}\n.cc-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}\n.cc-tabDotOk{background:var(--dsw-alias-brand-primary);border-radius:50%;width:6px;height:6px}\n.cc-tabDotWarn{background:#d97706;border-radius:50%;width:6px;height:6px}\n.cc-tabDotError{background:var(--dsw-alias-label-error);border-radius:50%;width:6px;height:6px}\n.cc-usageMetaSpacer{flex:1}\n.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}\n.cc-usagePartial{color:var(--dsw-alias-label-error);margin:0;font-size:11px;line-height:1.5}\n.cc-usageBlocked{border:1px solid var(--dsw-alias-label-error);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}\n.cc-usageBlockedTitle{color:var(--dsw-alias-label-error);margin:0;font-size:13px;font-weight:600;line-height:1.5}\n.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}\n.cc-usageBlockedDetail{color:var(--dsw-alias-label-secondary);margin:0;font-size:11px;line-height:1.5;word-break:break-word;opacity:.85}\n.cc-version{margin:4px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}\n/* The Models-page provider panel root: unstyled by design — the row card the\n * Models page owns supplies the surface, the panel only stacks its controls. */\n.cc-providerCard{flex-direction:column;display:flex}\n/* The update hint rides the footer version line: warning-tinted (with a\n * muted fallback for themes without the alias), quiet until hovered. */\n.cc-versionLink{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));text-decoration:none}\n.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}\n/* The login panel rides the connection card as one more field row; the\n * authorization link is the only branded element on it. */\n.cc-loginLink{color:var(--dsw-alias-brand-primary);text-decoration:none;font-size:12px;line-height:1.5}\n.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}\n.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}\n.cc-loginError{color:var(--dsw-alias-label-error)}\n.cc-saved{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;font-weight:500;line-height:1.5}\n.cc-badgeWarn{background:var(--dsw-alias-state-warning-secondary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary))}\n`\n","/**\n * Stylesheet for the Command Code plans & quota panel (the sidebar footer card\n * and the dashboard it opens).\n *\n * Returned as a string rather than injected here so the modules stay free of\n * DOM side effects at import time — the client entry installs it once, keyed\n * by the same `data-plugin-css` attribute the settings-page stylesheet\n * (`./page-styles.ts`) uses, and removes it again when the plugin's fiber\n * unwinds.\n *\n * These rules are GLOBAL CSS: every selector in here can match markup this\n * plugin did not render. So each one is either qualified by a `ccp-` class of\n * our own, or anchored to the sidebar region it has to lay out — and the one\n * foreign anchor carries its justification in place (see the footer card\n * block; issue #48). `tests/styles.test.ts` audits that containment for both\n * stylesheets and simulates it against the real foreign class stems.\n *\n * Every colour comes from a harness theme alias with a neutral fallback, so\n * the panel follows the active theme (light/dark and any brand pack) without\n * hardcoded values. Classes are `ccp-` prefixed to stay clear of the settings\n * page's `cc-` set.\n *\n * @module dsh-commandcode-provider/client/panel-styles\n */\n\n/**\n * Stylesheet id (the `data-plugin-css` value that makes injection idempotent).\n *\n * The package prefix must match the one the settings-page stylesheet uses\n * (`PAGE_CSS_ID` in `./page-styles.ts`) and this package's real name: an id is\n * the injection's identity, so a stale fork prefix would let a second copy of\n * the plugin inject the same rules twice and would misreport the owner in the\n * DOM. The two ids must also stay distinct from each other — they key two\n * separate style tags, and a shared id would make the second injection a no-op\n * that silently drops one stylesheet.\n */\nexport const PANEL_CSS_ID = '@mars-sea/dsh-commandcode-provider/CommandCodePanel.module.css'\n\n/** The panel stylesheet. */\nexport const PANEL_CSS = `\n/* ------------------------------------------------- sidebar footer card */\n/* The shell's foot area renders this list ABOVE the Settings seat, so the card\n is the sidebar's bottom-most content. The shell supplies no chrome: the entry\n is the button. It is deliberately quiet — a surface that sits beside Settings\n should read as part of the column, not as a call to action — with one hover\n step and a hairline border.\n\n The shell's container is a flex ROW whose occupants (this card and ui-cordis's\n footer chip) each declare a full-width line and shrink-proof flex, so as a row\n it would overflow the column: this card's flex:0 0 auto cannot shrink, and the\n chip's width:100% basis would absorb the whole overflow and collapse to\n nothing. Both were written for a full-width line, which is exactly what a\n column gives them. Matched by the CSS-module class STEM — never a hashed name\n — so a dsh that renames it degrades to the shell's own row rather than\n breaking.\n\n THE ANCHOR IS LOAD-BEARING, and it is the whole reason this selector is not\n just [class*=\"_footerActions\"] (issue #48). \"footerActions\" is NOT a stem this\n shell owns alone: @deepseek-ai/dsh-client-ui-user-questions renders the\n ask-user-question dialog's button row as Mbwy4a_footerActions, so the\n unanchored rule forced THAT row into a column too and stacked the dialog's\n side-by-side buttons on every page. \"footArea\" is declared by\n dsh-client-ui-sidebar alone — verified against every client bundle of the\n 0.1.6-alpha.1 engine, and against our own cc-/ccp- class names, which collide\n with no engine class — so anchoring under it keeps the sidebar layout fix and\n cannot reach another component's markup. The descendant combinator (rather\n than a child one) deliberately survives a wrapper element appearing between\n the two: a renamed or restructured shell should degrade to its own row, not\n lose the fix. tests/styles.test.ts pins both halves of this — the dialog row\n is no longer matched, the sidebar row still is. */\n[class*=\"_footArea\"] [class*=\"_footerActions\"]{flex-direction:column}\n.ccp-foot{box-sizing:border-box;flex:0 0 auto;width:100%;min-width:0;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:1px solid transparent;border-radius:10px;flex-direction:column;gap:6px;margin:0 0 4px;padding:8px;display:flex}\n.ccp-foot:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}\n.ccp-foot:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n.ccp-footTop{align-items:center;gap:8px;min-width:0;display:flex}\n.ccp-footName{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);min-width:0;overflow:hidden;font-size:13px;font-weight:500;line-height:20px}\n/* One block per quota window: a head line carrying the window's own spend and\n limit, then the FULL-WIDTH bar under it. Stacking the two lets the card show\n the dollar figures — the reason this surface exists — without squeezing the\n bar into what is left beside them. Mirrors the dashboard's own window block. */\n.ccp-footRow{flex-direction:column;gap:4px;min-width:0;display:flex}\n.ccp-footHead{align-items:baseline;gap:8px;min-width:0;display:flex}\n.ccp-footLabel{flex:1;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}\n.ccp-footAmount{flex:none;color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px;font-variant-numeric:tabular-nums;white-space:nowrap}\n/* The card's markup must stay PHRASING content — it renders inside the shell's\n own button — so these bars are spans, not divs. That makes display:block\n load-bearing on BOTH: an inline box ignores width and height outright, so\n without it the 5px track still painted (a flex item is blockified by its\n container) while the fill collapsed to 0x0 and the bar showed no usage. */\n.ccp-footBar{display:block;background:var(--dsw-alias-bg-layer-2);border-radius:999px;height:5px;overflow:hidden}\n.ccp-footFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.ccp-footFillWarn{background:var(--dsw-alias-state-error-primary)}\n.ccp-footPct{flex:none;width:34px;color:var(--dsw-alias-label-secondary);text-align:right;font-size:11px;line-height:16px;font-variant-numeric:tabular-nums}\n\n/* The 56px rail: one icon button on the shell's own rail geometry (36px cell),\n so the collapsed column keeps a single 18px glyph like its siblings. */\n.ccp-railButton{box-sizing:border-box;width:36px;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:1px solid transparent;border-radius:8px;flex:none;justify-content:center;align-items:center;margin:0 0 4px;padding:0;display:inline-flex}\n.ccp-railButton:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}\n.ccp-railButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n\n/* The ring glyph. Sized entirely by its own width/height attribute, so the\n footer row, the rail button and the dashboard can each ask for their own. */\n.ccp-glyph{flex:none;justify-content:center;align-items:center;display:inline-flex;color:var(--dsw-alias-brand-primary)}\n\n/* ------------------------------------------------------------ dashboard */\n/* The center column in the layout frame: fill it, scroll the content column,\n and cap the reading width like the harness's own panels. */\n.ccp-main{background:var(--dsw-alias-bg-layer-1);width:100%;height:100%;overflow:auto;display:block}\n.ccp-mainInner{max-width:760px;margin:0 auto;padding:24px 20px 40px;flex-direction:column;gap:14px;display:flex;color:var(--dsw-alias-label-primary)}\n.ccp-header{align-items:center;gap:10px;display:flex;flex-wrap:wrap}\n.ccp-headerText{flex-direction:column;gap:2px;display:flex;min-width:0}\n.ccp-title{margin:0;font-size:18px;font-weight:600;line-height:1.4}\n.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}\n.ccp-spacer{flex:1}\n.ccp-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;font-variant-numeric:tabular-nums}\n/* The dashboard's exit: an icon-sized glyph button. The primitive's own\n geometry is kept (size=\"sm\"); only the glyph is enlarged and optically\n centred, so it reads as a dismiss control rather than a text button. */\n.ccp-close{min-width:28px;justify-content:center;padding-left:0;padding-right:0}\n.ccp-close span{font-size:16px;line-height:1}\n.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n\n/* Notices: the no-key guidance, a blocked report, and a stale-data error. */\n.ccp-notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:12px 14px;flex-direction:column;gap:4px;display:flex}\n.ccp-noticeError{border-color:var(--dsw-alias-state-error-primary)}\n.ccp-noticeTitle{margin:0;font-size:13px;font-weight:600;line-height:1.5}\n.ccp-noticeError .ccp-noticeTitle{color:var(--dsw-alias-state-error-primary)}\n.ccp-noticeHint{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55}\n.ccp-noticeDetail{margin:0;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;word-break:break-word}\n\n.ccp-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:14px;padding:16px 18px;flex-direction:column;gap:16px;display:flex}\n.ccp-cardHead{align-items:center;gap:10px;display:flex;flex-wrap:wrap}\n.ccp-avatar{flex:none;width:28px;height:28px;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-module-platform);border-radius:50%;justify-content:center;align-items:center;font-size:12px;font-weight:600;line-height:1;display:inline-flex}\n.ccp-cardIdentity{flex-direction:column;gap:1px;min-width:0;display:flex}\n.ccp-cardTitle{font-size:13px;font-weight:600;line-height:1.4}\n.ccp-cardOwner{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px}\n.ccp-block{flex-direction:column;gap:8px;display:flex}\n.ccp-blockTitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:600;line-height:1.5;text-transform:uppercase;letter-spacing:.04em}\n.ccp-planRow{align-items:center;gap:8px;display:flex;flex-wrap:wrap}\n.ccp-fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}\n.ccp-planName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:1.5}\n\n/* Stat tiles: the monthly credits and the usage totals share one grid. */\n.ccp-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px}\n.ccp-tile{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex;min-width:0}\n.ccp-tileLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}\n.ccp-tileValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4;font-variant-numeric:tabular-nums}\n.ccp-tileSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n\n/* Quota bars: the monthly bar and the two windows stack in one column, each a\n label row plus the track. */\n.ccp-windows{flex-direction:column;gap:14px;display:flex}\n.ccp-window{flex-direction:column;gap:6px;display:flex}\n.ccp-windowHead{align-items:baseline;gap:8px;display:flex}\n.ccp-windowLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:1.5}\n.ccp-windowValue{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5;font-variant-numeric:tabular-nums;white-space:nowrap}\n.ccp-windowPct{color:var(--dsw-alias-label-primary);min-width:38px;text-align:right;font-size:12px;font-weight:600;line-height:1.5;font-variant-numeric:tabular-nums}\n.ccp-warnTag{white-space:nowrap;background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary));border-radius:999px;padding:0 8px;font-size:11px;font-weight:600;line-height:17px}\n.ccp-bar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:8px}\n.ccp-barFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.ccp-barFillWarn{background:var(--dsw-alias-state-error-primary)}\n.ccp-windowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}\n\n/* Badges. */\n.ccp-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}\n.ccp-badgeError{background:transparent;color:var(--dsw-alias-state-error-primary)}\n.ccp-badgeWarn{background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary))}\n.ccp-badgeMuted{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;max-width:220px;overflow:hidden;text-overflow:ellipsis}\n\n/* Account switch: plain buttons, like the settings page's usage carousel. */\n.ccp-tabs{flex-wrap:wrap;gap:6px;display:flex}\n.ccp-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}\n.ccp-tab:hover:not(.ccp-tabActive){color:var(--dsw-alias-label-primary)}\n.ccp-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}\n\n@media (prefers-reduced-motion:reduce){.ccp-footFill,.ccp-barFill{transition:none}}\n`\n","/**\n * Locale copy for the \"Command Code\" settings page, and the declaration that\n * merges the page's namespace into the framework's `LocaleNamespaceMap` so\n * `ctx.locale.register` / `ctx.slots.register(..., { locale })` are typed.\n *\n * zh is the source of truth for the key set (repo convention); en must carry\n * the exact same keys — a mismatch is a compile error at the register site.\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Copy of the Command Code settings page. */\n 'settings.commandcode': SettingsCommandCodeKey\n }\n}\n\n/** Dictionary keys of the Command Code settings page. */\nexport type SettingsCommandCodeKey =\n | 'nav'\n | 'title'\n | 'intro'\n | 'apiKey'\n | 'apiKeyHint'\n | 'apiKeySet'\n | 'apiKeyUnset'\n | 'apiKeyLocked'\n | 'apiBase'\n | 'apiBaseHint'\n | 'workingDir'\n | 'workingDirHint'\n | 'requestTimeoutMs'\n | 'requestTimeoutMsHint'\n | 'streamIdleTimeoutMs'\n | 'streamIdleTimeoutMsHint'\n | 'transportMaxRetries'\n | 'transportMaxRetriesHint'\n | 'advancedSettings'\n | 'advancedSettingsHint'\n | 'advancedOverriddenOne'\n | 'advancedOverriddenMany'\n | 'advancedInvalid'\n | 'filterModelsByPlan'\n | 'filterModelsByPlanHint'\n | 'webSearch'\n | 'webSearchHint'\n | 'showSidebarQuota'\n | 'showSidebarQuotaHint'\n | 'commandGuard'\n | 'commandGuardHint'\n | 'commandGuardThreshold'\n | 'commandGuardThresholdHint'\n | 'commandGuardTimeoutMs'\n | 'commandGuardTimeoutMsHint'\n | 'zdr'\n | 'zdrHint'\n | 'accountsTitle'\n | 'accountsHint'\n | 'accountAdd'\n | 'accountRemove'\n | 'accountLabel'\n | 'accountKey'\n | 'accountKeyHint'\n | 'accountLoginAfterSave'\n | 'accountDefault'\n | 'activeAccount'\n | 'activeAccountAuto'\n | 'activeAccountHint'\n | 'rulesTitle'\n | 'rulesHint'\n | 'rulesEmpty'\n | 'rulesCatalogFailed'\n | 'ruleAdd'\n | 'ruleRemove'\n | 'ruleModel'\n | 'ruleModelPick'\n | 'ruleModelCount'\n | 'ruleAccount'\n | 'ruleHint'\n | 'modelSearchPlaceholder'\n | 'modelSearchEmpty'\n | 'modelStale'\n | 'visibleModelsTitle'\n | 'visibleModelsHint'\n | 'visibleModelsPick'\n | 'visibleModelsCount'\n | 'visibleModelsShowAll'\n | 'visibleModelsStaleHint'\n | 'visibleModelsCleanStale'\n | 'overridden'\n | 'reset'\n | 'invalidNumber'\n | 'numberTooSmall'\n | 'numberTooLarge'\n | 'readOnly'\n | 'unsaved'\n | 'save'\n | 'saving'\n | 'saved'\n | 'saveFailed'\n | 'discard'\n | 'cancel'\n | 'show'\n | 'hide'\n | 'usageTitle'\n | 'usageRefresh'\n | 'usageRefreshing'\n | 'usageLoading'\n | 'usageNoKey'\n | 'usageError'\n | 'usageRequests'\n | 'usageFailed'\n | 'usageSuccessRate'\n | 'usageCost'\n | 'usageTokens'\n | 'usageTokensIn'\n | 'usageTokensOut'\n | 'usageMonthly'\n | 'usagePurchased'\n | 'usageFree'\n | 'usageFiveHour'\n | 'usageWeekly'\n | 'usageExceeded'\n | 'usageReset'\n | 'usagePartial'\n | 'usageKeyClear'\n | 'usageKeyClearStaged'\n | 'usageUndoKeyClear'\n | 'usageKeyInvalid'\n | 'usageKeyInvalidHint'\n | 'usageServiceUnavailable'\n | 'usageServiceUnavailableHint'\n | 'usageNetworkError'\n | 'usageNetworkHint'\n | 'usageInvalidResponse'\n | 'usageInvalidResponseHint'\n | 'usageUpdated'\n | 'usagePeriodEnd'\n | 'usageActive'\n | 'usageCooldown'\n | 'usageInvalidKey'\n | 'usageUnconfigured'\n | 'updateAvailable'\n | 'updateHint'\n | 'loginTitle'\n | 'loginHintIdle'\n | 'loginSaveBefore'\n | 'loginButton'\n | 'loginStarting'\n | 'loginWaiting'\n | 'loginOpenLink'\n | 'loginCancel'\n | 'loginSuccess'\n | 'loginUnavailable'\n | 'loginDenied'\n | 'loginTimeout'\n | 'loginInvalidKey'\n | 'loginNetwork'\n | 'loginStoreFailed'\n | 'loginCancelled'\n | 'loginFailedGeneric'\n | 'cardTitle'\n | 'cardRouteActive'\n | 'cardLoadingHint'\n | 'cardRegistrationHint'\n\nexport const zh: Record<SettingsCommandCodeKey, string> = {\n nav: 'Command Code',\n title: 'Command Code',\n intro:\n '配置 Command Code Provider 连接。API 密钥仅保存在本机凭据服务中,不会回显;'\n + '其他字段写入用户设置,下次请求即生效。',\n apiKey: 'API 密钥',\n apiKeyHint: '在 commandcode.ai 控制台创建。留空保存不会覆盖已存储的密钥。',\n apiKeySet: '已配置',\n apiKeyUnset: '未配置',\n apiKeyLocked: '密钥由只读来源提供',\n apiBase: 'API 地址',\n apiBaseHint: '默认 https://api.commandcode.ai,一般无需修改。',\n workingDir: '工作目录',\n workingDirHint: '可选。留空时使用占位符显示的进程工作目录;仅在需要固定路径时填写。',\n requestTimeoutMs: '请求超时(毫秒)',\n requestTimeoutMsHint: '等待响应首个字节的超时;默认 60000。',\n streamIdleTimeoutMs: '流空闲超时(毫秒)',\n streamIdleTimeoutMsHint: '生成流停滞多久视为断连;默认 300000(长思考模型可静默数分钟,默认值刻意放宽)。',\n transportMaxRetries: '网络失败重试次数',\n transportMaxRetriesHint: '连接失败时自动重试几次,默认 5(各次等待 0.5+1+2+4+8 秒,合计约 15 秒)。'\n + '超过后直接报错,不再按指数退避长时间等待;填 0 表示不重试。限流、5xx 等由服务端要求重试的失败不受此项影响。',\n advancedSettings: '高级设置',\n advancedSettingsHint: 'API 地址、工作目录、超时、模型过滤、联网搜索与侧边栏额度卡片等不常修改的选项。',\n advancedOverriddenOne: '已自定义 1 项',\n advancedOverriddenMany: '已自定义 {count} 项',\n advancedInvalid: '高级设置中有未填好的数字,请展开修正后再保存。',\n filterModelsByPlan: '隐藏套餐外模型',\n filterModelsByPlanHint: '开启后,模型选择器只列出当前套餐可用的模型;账户持有按需余额时会显示全部。',\n webSearch: '用 Command Code 承载联网搜索',\n webSearchHint: '开启后,dsh 的 web_search 工具由 Command Code 承担(复用同一个 API key 与地址),并优先于其他搜索后端;关闭则把选择权交还给之前的后端(如 modsearch),而不是强制回退到 DeepSeek 搜索。',\n showSidebarQuota: '在侧边栏显示额度卡片',\n showSidebarQuotaHint: '开启后,侧边栏底部(Settings 上方)显示 Command Code 套餐与配额卡片,点击可在中间栏打开完整仪表盘。默认关闭:左侧不显示任何额度信息,也不会为其后台刷新用量。保存后立即生效。',\n commandGuard: 'AI 命令安全预判',\n commandGuardHint: '命令确认弹窗前,先由 typesafe/jev 判断它是否安全:安全就自动放行,其余照常弹窗。默认关闭。',\n commandGuardThreshold: '自动放行阈值(0.5–1)',\n commandGuardThresholdHint: 'typesafe/jev 判定\"安全\"的概率达到该值即放行,默认 0.9。',\n commandGuardTimeoutMs: '判定超时(毫秒,200–10000)',\n commandGuardTimeoutMsHint: 'typesafe/jev 超过该时间未返回就照常弹窗,默认 1500。',\n zdr: '零数据保留(ZDR)',\n zdrHint:\n '开启后,请求只经由不留存提示词与回复、也不用于训练的上游(等价于 CLI 的 CMD_ZDR=1)。'\n + '没有可用 ZDR 上游的模型会返回错误,请换用其他模型或关闭此开关。'\n + 'ZDR 容量按上游实价透传,通常更贵;费用读数仍按常规目录价估算。默认关闭。',\n accountsTitle: '多账户轮换',\n accountsHint: '当前账户达到用量限额(429)或密钥失效(401)时,请求自动切换到下一个账户;全部耗尽时会提示最早的重置时间。',\n accountAdd: '添加账户',\n accountRemove: '移除',\n accountLabel: '账户备注名',\n accountKey: 'API 密钥',\n accountKeyHint: '该账户的 API 密钥。留空保存不会覆盖已存储的密钥。',\n accountLoginAfterSave: '先点击页面底部的「保存」,再点击该账户的「登录 Command Code」通过网页获取密钥。',\n accountDefault: '默认账户',\n activeAccount: '当前使用账户',\n activeAccountAuto: '自动(第一个可用账户)',\n activeAccountHint: '手动指定优先使用的账户,保存后下次请求即生效;所选账户耗尽时仍会自动切换到其他可用账户。',\n rulesTitle: '按模型切换账户',\n rulesHint: '选择模型并路由到某个账户(可多选)。命中规则的模型且该账户可用时优先使用;账户耗尽或密钥失效时仍自动回落到其他账户。规则按列表顺序匹配,第一条命中生效。',\n rulesEmpty: '尚未配置规则。',\n rulesCatalogFailed: '模型目录获取失败,暂时无法选择模型;已保存的规则仍会生效。',\n ruleAdd: '添加规则',\n ruleRemove: '移除',\n ruleModel: '模型',\n ruleModelPick: '选择模型…',\n ruleModelCount: '已选 {count} 个模型',\n ruleAccount: '目标账户',\n ruleHint: '从下拉列表勾选要路由的模型(可多选),再选择目标账户。',\n modelSearchPlaceholder: '搜索模型…',\n modelSearchEmpty: '没有匹配的模型。',\n modelStale: '已下架',\n visibleModelsTitle: '模型白名单',\n visibleModelsHint:\n '勾选要保留的模型,模型选择器就只列出这些;一个都不勾选时则显示全部模型。'\n + '保存后,下次打开模型选择器生效。',\n visibleModelsPick: '选择要保留的模型…',\n visibleModelsCount: '已选 {count} 个模型',\n visibleModelsShowAll: '显示全部',\n visibleModelsStaleHint: '有 {count} 个已选模型在目录中找不到了(可能已下架),不影响其他模型;可清理或保留。',\n visibleModelsCleanStale: '清理失效({count})',\n overridden: '已覆盖',\n reset: '重置',\n invalidNumber: '无效数字',\n numberTooSmall: '不能小于 1(毫秒)',\n numberTooLarge: '超出允许上限(2147483647 毫秒)',\n readOnly: '当前配置为只读。',\n unsaved: '未保存',\n save: '保存',\n saving: '保存中',\n saved: '已保存 ✓',\n saveFailed: '保存失败,请重试。',\n discard: '放弃',\n cancel: '取消',\n show: '显示',\n hide: '隐藏',\n usageTitle: '账户用量',\n usageRefresh: '刷新',\n usageRefreshing: '刷新中…',\n usageLoading: '正在获取账户用量…',\n usageNoKey: '配置 API 密钥后,这里会显示账户的用量与额度状态。',\n usageError: '用量获取失败',\n usageRequests: '请求',\n usageFailed: '失败',\n usageSuccessRate: '成功率',\n usageCost: '花费',\n usageTokens: 'Token',\n usageTokensIn: '入',\n usageTokensOut: '出',\n usageMonthly: '月额度',\n usagePurchased: '已购',\n usageFree: '赠送',\n usageFiveHour: '5 小时窗口',\n usageWeekly: '每周窗口',\n usageExceeded: '已超限',\n usageReset: '重置于',\n usagePartial: '部分端点数据不可用',\n usageKeyClear: '清除已存密钥',\n usageKeyClearStaged: '将清除(保存后生效)',\n usageUndoKeyClear: '撤销清除',\n usageKeyInvalid: 'API 密钥无效或已过期',\n usageKeyInvalidHint: '服务端拒绝了全部请求(401)。请检查该账户配置的密钥,或到 commandcode.ai 控制台重新生成。',\n usageServiceUnavailable: 'Command Code 服务暂时不可用',\n usageServiceUnavailableHint: '服务端返回了错误(5xx),稍后点击刷新重试。',\n usageNetworkError: '无法连接 Command Code 服务',\n usageNetworkHint: '所有请求都没有到达服务端。请检查网络连接或 API 地址设置。',\n usageInvalidResponse: 'Command Code 响应无法读取',\n usageInvalidResponseHint: '请求已收到响应,但内容无法解析。请检查宿主的 HTTP 代理或响应解压配置。',\n usageUpdated: '更新于',\n usagePeriodEnd: '账期截止',\n usageActive: '当前使用',\n usageCooldown: '限额冷却中',\n usageInvalidKey: '密钥无效',\n usageUnconfigured: '该账户尚未配置 API 密钥。',\n updateAvailable: '可更新',\n updateHint: '已发布新版本,点击查看发布说明;更新插件后刷新本页,提示会自动消失。',\n loginTitle: '通过官方登录获取密钥',\n loginHintIdle: '不想手动创建密钥?点击登录后浏览器会打开 commandcode.ai 授权页,完成后密钥自动写入本机凭据服务,下次请求即生效。',\n loginSaveBefore: '请先保存本页更改,再通过网页登录此账户。',\n loginButton: '登录 Command Code',\n loginStarting: '正在启动本地回调服务…',\n loginWaiting: '等待在浏览器中完成授权…',\n loginOpenLink: '打开授权页面 ↗',\n loginCancel: '取消登录',\n loginSuccess: '已登录为',\n loginUnavailable: '此环境暂不支持登录流程,请手动粘贴密钥。',\n loginDenied: '授权被拒绝。可重试,或手动粘贴密钥。',\n loginTimeout: '等待超时:未在窗口期内收到授权回调,请重试。',\n loginInvalidKey: '获取到的密钥未通过校验(401),请重试或手动粘贴。',\n loginNetwork: '无法连接 Command Code 服务校验密钥,请检查网络后重试。',\n loginStoreFailed: '密钥无法写入本机凭据服务,请手动粘贴。',\n loginCancelled: '登录已取消。',\n loginFailedGeneric: '登录失败,请重试或手动粘贴密钥。',\n cardTitle: 'Command Code',\n cardRouteActive: '已启用',\n cardLoadingHint: '正在读取 Command Code 配置…',\n cardRegistrationHint: '此卡片随 Command Code 插件注册,需要较新版本的 DeepSeek Harness 才会显示完整内容。',\n}\n\nexport const en: Record<SettingsCommandCodeKey, string> = {\n nav: 'Command Code',\n title: 'Command Code',\n intro:\n 'Configure the Command Code Provider connection. The API key is stored only'\n + ' in the local credential service and never echoed; other fields are written'\n + ' to user settings and take effect on the next request.',\n apiKey: 'API key',\n apiKeyHint: 'Create one in the commandcode.ai console. Saving with this field'\n + ' blank keeps the stored key.',\n apiKeySet: 'Configured',\n apiKeyUnset: 'Not configured',\n apiKeyLocked: 'Key provided by a read-only source',\n apiBase: 'API base URL',\n apiBaseHint: 'Defaults to https://api.commandcode.ai; usually leave as-is.',\n workingDir: 'Working directory',\n workingDirHint: 'Optional. Leave blank to use the process cwd shown as the'\n + ' placeholder; fill in only to pin a specific path.',\n requestTimeoutMs: 'Request timeout (ms)',\n requestTimeoutMsHint: 'Time to wait for the first response byte; default 60000.',\n streamIdleTimeoutMs: 'Stream idle timeout (ms)',\n streamIdleTimeoutMsHint: 'How long a stalled stream is treated as dead; default 300000'\n + ' (deliberately generous — long-thinking models can stay silent for minutes).',\n transportMaxRetries: 'Transport retries',\n transportMaxRetriesHint: 'How many times a failed connection is retried automatically; default 5'\n + ' (waits of 0.5+1+2+4+8s, ~15s in total). After that the failure is reported instead of waiting'\n + ' on the exponential backoff. 0 disables the retries. Rate limits and 5xx answers keep their'\n + ' own, longer retry window.',\n advancedSettings: 'Advanced',\n advancedSettingsHint: 'Rarely touched options: API base URL, working directory, timeouts, model filtering, web search, and the sidebar quota card.',\n advancedOverriddenOne: '1 customized',\n advancedOverriddenMany: '{count} customized',\n advancedInvalid: 'A number in Advanced settings is not ready to save; expand to fix it.',\n filterModelsByPlan: 'Hide out-of-plan models',\n filterModelsByPlanHint: 'When on, the model picker lists only models your subscription'\n + ' includes; any on-demand credit balance shows the full catalog.',\n webSearch: 'Serve dsh web search with Command Code',\n webSearchHint: 'When on, the model-facing web_search tool is backed by Command Code'\n + ' (same API key and base URL as chat), winning over other search backends.'\n + ' Off hands the selection back to the previous backend (e.g. modsearch)'\n + ' instead of forcing the shipped DeepSeek search.',\n showSidebarQuota: 'Show the quota card in the sidebar',\n showSidebarQuotaHint: 'When on, a Command Code plan & quota card sits at the bottom of the'\n + ' sidebar (above Settings) and opens the full dashboard in the centre column.'\n + ' Off by default: nothing is shown on the left, and no background usage poll'\n + ' runs for it. Applies on save.',\n commandGuard: 'AI command guard',\n commandGuardHint: 'Before a shell command asks for approval, typesafe/jev judges whether'\n + ' it is safe: safe commands run without a prompt, everything else asks as usual.'\n + ' Off by default.',\n commandGuardThreshold: 'Auto-approve threshold (0.5–1)',\n commandGuardThresholdHint: 'Approve when typesafe/jev rates the command \"safe\" at least'\n + ' this likely; default 0.9.',\n commandGuardTimeoutMs: 'Judgement timeout (ms, 200–10000)',\n commandGuardTimeoutMsHint: 'If typesafe/jev does not answer in time, the normal prompt'\n + ' appears; default 1500.',\n zdr: 'Zero data retention (ZDR)',\n zdrHint:\n 'Serve requests only through upstreams that keep no prompts or completions'\n + ' and never train on them (the same opt-in as the CLI\\'s CMD_ZDR=1). A few'\n + ' models have no ZDR upstream; requests for those models fail rather than'\n + ' losing ZDR protection. ZDR capacity is billed'\n + ' at the upstream\\'s pass-through rates and usually costs more; the cost'\n + ' readout keeps quoting the ordinary catalog rates. Off by default.',\n accountsTitle: 'Account rotation',\n accountsHint: 'When the active account hits its usage limit (429) or its key'\n + ' fails (401), requests switch to the next account; when every account is'\n + ' exhausted the error names the earliest window reset.',\n accountAdd: 'Add account',\n accountRemove: 'Remove',\n accountLabel: 'Account label',\n accountKey: 'API key',\n accountKeyHint: 'This account’s API key. Saving with the field blank keeps the stored key.',\n accountLoginAfterSave: 'Use Save at the bottom of the page, then sign in to this account in your browser to obtain a key.',\n accountDefault: 'Default account',\n activeAccount: 'Active account',\n activeAccountAuto: 'Auto (first usable account)',\n activeAccountHint: 'Pin the preferred account; applies to the next request after saving.'\n + ' If the selected account is exhausted, requests still rotate to another usable account.',\n rulesTitle: 'Route models to accounts',\n rulesHint: 'Pick models (multi-select) and route them to an account. When the'\n + ' request’s model is in a rule and that account is usable, it serves;'\n + ' an exhausted or invalid routed account falls back to the normal rotation.'\n + ' Rules match in list order — the first hit wins.',\n rulesEmpty: 'No rules yet.',\n rulesCatalogFailed: 'Could not load the model catalog — selecting models is unavailable; saved rules still apply.',\n ruleAdd: 'Add rule',\n ruleRemove: 'Remove',\n ruleModel: 'Models',\n ruleModelPick: 'Select models…',\n ruleModelCount: '{count} model(s) selected',\n ruleAccount: 'Target account',\n ruleHint: 'Check the models to route from the dropdown (multi-select), then pick the target account.',\n modelSearchPlaceholder: 'Search models…',\n modelSearchEmpty: 'No matching models.',\n modelStale: 'Retired',\n visibleModelsTitle: 'Model allowlist',\n visibleModelsHint:\n 'Check the models you want to keep, and model pickers will list only those. '\n + 'If nothing is checked, every model is shown. After saving, the change '\n + 'applies the next time you open a model picker.',\n visibleModelsPick: 'Select models to keep…',\n visibleModelsCount: '{count} model(s) selected',\n visibleModelsShowAll: 'Show all',\n visibleModelsStaleHint: '{count} selected model(s) are no longer in the catalog (possibly retired);'\n + ' other models are unaffected. Clean them up or keep them.',\n visibleModelsCleanStale: 'Clean stale ({count})',\n overridden: 'Overridden',\n reset: 'Reset',\n invalidNumber: 'Invalid number',\n numberTooSmall: 'Must be at least 1 (ms)',\n numberTooLarge: 'Above the allowed maximum (2147483647 ms)',\n readOnly: 'Settings are read-only.',\n unsaved: 'Unsaved',\n save: 'Save',\n saving: 'Saving',\n saved: 'Saved ✓',\n saveFailed: 'Save failed, please retry.',\n discard: 'Discard',\n cancel: 'Cancel',\n show: 'Show',\n hide: 'Hide',\n usageTitle: 'Account usage',\n usageRefresh: 'Refresh',\n usageRefreshing: 'Refreshing…',\n usageLoading: 'Fetching account usage…',\n usageNoKey: 'Configure an API key to see this account’s usage and credit state here.',\n usageError: 'Could not fetch usage',\n usageRequests: 'Requests',\n usageFailed: 'failed',\n usageSuccessRate: 'Success rate',\n usageCost: 'Spend',\n usageTokens: 'Tokens',\n usageTokensIn: 'in',\n usageTokensOut: 'out',\n usageMonthly: 'Monthly',\n usagePurchased: 'Purchased',\n usageFree: 'Free',\n usageFiveHour: '5-hour window',\n usageWeekly: 'Weekly window',\n usageExceeded: 'Exceeded',\n usageReset: 'Resets',\n usagePartial: 'Some endpoint data unavailable',\n usageKeyClear: 'Clear stored key',\n usageKeyClearStaged: 'Will be cleared on save',\n usageUndoKeyClear: 'Undo clear',\n usageKeyInvalid: 'API key invalid or expired',\n usageKeyInvalidHint: 'The server rejects every request (401). Check the key configured for this account, or generate a new one in the commandcode.ai console.',\n usageServiceUnavailable: 'The Command Code service is temporarily unavailable',\n usageServiceUnavailableHint: 'The server returned errors (5xx); try Refresh again later.',\n usageNetworkError: 'Could not reach the Command Code service',\n usageNetworkHint: 'No request reached the server. Check your network connection or the API base setting.',\n usageInvalidResponse: 'Could not read the Command Code response',\n usageInvalidResponseHint: 'The requests received responses, but their bodies could not be parsed. Check the host HTTP proxy or response decoding.',\n usageUpdated: 'Updated',\n usagePeriodEnd: 'Period ends',\n usageActive: 'Active',\n usageCooldown: 'Cooling down',\n usageInvalidKey: 'Invalid key',\n usageUnconfigured: 'No API key configured for this account yet.',\n updateAvailable: 'update available',\n updateHint: 'A newer version has been published; click for release notes. The notice disappears once the plugin is updated.',\n loginTitle: 'Sign in to fetch a key',\n loginHintIdle: 'Rather not create a key by hand? Sign in and your browser opens the commandcode.ai authorization page; the approved key is stored in the local credential service and applies to the next request.',\n loginSaveBefore: 'Save page changes before signing in to this account.',\n loginButton: 'Sign in to Command Code',\n loginStarting: 'Starting the local callback server…',\n loginWaiting: 'Waiting for authorization in your browser…',\n loginOpenLink: 'Open the authorization page ↗',\n loginCancel: 'Cancel sign-in',\n loginSuccess: 'Signed in as',\n loginUnavailable: 'Sign-in is unavailable in this environment; paste the API key instead.',\n loginDenied: 'Authorization was denied. Try again or paste the key manually.',\n loginTimeout: 'Timed out waiting for the authorization callback; try again.',\n loginInvalidKey: 'The delivered key failed validation (401). Try again or paste it manually.',\n loginNetwork: 'Could not reach the Command Code service to validate the key; check your network and retry.',\n loginStoreFailed: 'The key could not be stored in the local credential service; paste it manually.',\n loginCancelled: 'Sign-in cancelled.',\n loginFailedGeneric: 'Sign-in failed; try again or paste the key manually.',\n cardTitle: 'Command Code',\n cardRouteActive: 'Active',\n cardLoadingHint: 'Loading the Command Code configuration…',\n cardRegistrationHint: 'This card is contributed by the Command Code plugin; a newer DeepSeek Harness is needed to show the full controls.',\n}\n","/**\n * Browser half of the dsh-commandcode-provider bundle.\n *\n * Two responsibilities:\n *\n * 1. A \"Command Code\" settings page (a `settings.section` entry at the same\n * nav level as General / Models / Plugins). The Models page renders an\n * unknown-adapter-family card for the `commandcode` provider and disables\n * its submit, so the API key cannot be configured there; this page is the\n * dedicated surface. It writes the API key through the credentials domain\n * (the `COMMANDCODE_API_KEY` reference the plugin resolves via\n * `ctx.remote.credentials`) and the connection facts through the\n * `llm-commandcode` settings namespace, so a saved key or endpoint reaches\n * the very next request.\n *\n * 2. The Models-page provider card (settings.models.provider-card) — see\n * `./card.tsx`.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { createSnapshotStore } from './snapshot-store.ts'\n// Type-only imports that pull in the client-service augmentations\n// (`slots`/`remote`/`locale` on Context) and the `settings.section` SlotMap\n// entry (declared through dsh-client-ui-settings).\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { createSettingsScope, type SettingsRemoteNamespace, type SettingsScopeContext } from './settings-scope.ts'\nimport { CommandCodeSettingsController, COMMANDCODE_NS, type SettingsPageState } from './settings.ts'\nimport type { HostDescriptionSource, SettingsPageApi } from './settings.ts'\nimport { adaptLegacyCredentials, type LegacyCredentialsApi } from './legacy-credentials.ts'\nimport { CommandCodeUsageController, type UsagePageState, type UsageRemote } from './usage.ts'\nimport { CommandCodePricesController, type SessionCostPricesState } from './prices.ts'\nimport { CommandCodeLoginController, type LoginPageState, type LoginRemote } from './login.ts'\nimport { USAGE_REMOTE_CONTRIBUTION, MODELS_REMOTE_CONTRIBUTION, PRICES_REMOTE_CONTRIBUTION } from '../usage-wire.ts'\nimport { LOGIN_REMOTE_CONTRIBUTION } from '../login-wire.ts'\nimport type { TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'\nimport { CommandCodeSettingsPage } from './section.tsx'\nimport { CommandCodeProviderCard } from './card.tsx'\nimport { CommandCodePanel, CommandCodeFooterEntry } from './panel-view.tsx'\nimport type { PanelInjected } from './panel-view.tsx'\nimport { CommandCodeSessionCost } from './session-cost-view.tsx'\nimport type { SessionCostInjected } from './session-cost-view.tsx'\nimport { startPanelAutoRefresh } from './panel.ts'\nimport { PAGE_CSS, PAGE_CSS_ID } from './page-styles.ts'\nimport { PANEL_CSS, PANEL_CSS_ID } from './panel-styles.ts'\n// Type-only: pulls in the SlotMap merge for the composer dock\n// (`./session-cost-slots.ts`). The sidebar-foot / center-column merge rides the\n// `./panel-view.tsx` value import above, which imports `./panel-slots.ts`.\nimport type {} from './session-cost-slots.ts'\nimport { zh, en } from './locales.ts'\nimport { PANEL_COPY_EN, PANEL_COPY_ZH, PANEL_LOCALE_NS } from './panel-copy.ts'\n\n\n\n/** Inject the page stylesheet once (idempotent per tag). */\nfunction injectPageCss(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector(`style[data-plugin-css=\"${PAGE_CSS_ID}\"]`) !== null) return\n const tag = document.createElement('style')\n tag.dataset.plugin = '@mars-sea/dsh-commandcode-provider'\n tag.dataset.pluginCss = PAGE_CSS_ID\n tag.textContent = PAGE_CSS\n document.head.appendChild(tag)\n}\n\n/**\n * Install the plans & quota panel's stylesheet and return its disposer, for\n * `ctx.effect` to own. Keyed by its own `data-plugin-css` id, so the injection\n * is idempotent even if a second surface asks for it later.\n */\nfunction injectPanelCss(): () => void {\n if (typeof document === 'undefined') return () => {}\n if (document.querySelector(`style[data-plugin-css=\"${PANEL_CSS_ID}\"]`) !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.plugin = '@mars-sea/dsh-commandcode-provider'\n tag.dataset.pluginCss = PANEL_CSS_ID\n tag.textContent = PANEL_CSS\n document.head.appendChild(tag)\n return () => {\n tag.remove()\n }\n}\n\n/**\n * Plans & quota panel id. It is the layout's `MainPanelId`: one string shared\n * by the `sidebar.footer.action` card and the `main` slot cell, so the card\n * selects this panel and nothing else. `dsh-client-ui-layout` is not a\n * dependency of this bundle (its type is only a brand over `string`), so the\n * brand is applied at the call site instead of importing the package.\n */\nconst PANEL_ID = 'commandcode-panel'\n\n/**\n * ui-conversation's reserved `main` key, used only as the exit fallback for a\n * layout whose `selectPanel` predates the `null` \"show the Conversation\"\n * selection (see `close` in {@link applyClientSurfaces}). Declared locally for\n * the same reason as {@link PANEL_ID}: ui-conversation is not a dependency of\n * this bundle, and the key is a published contract of the layout (its README\n * names `conversation` as reserved for the Conversation).\n */\nconst CONVERSATION_PANEL_ID = 'conversation'\n\n/**\n * The composer figure's entry id in `conversation.composer.dock`. Its own id,\n * not the shipped `stats` cell's: reusing `stats` would REPLACE the tokens /\n * cache-hit / throughput readout rather than inject into it, and that readout\n * is the harness's to format (see `./session-cost-display.ts`).\n */\nconst SESSION_COST_ID = 'commandcode-session-cost'\n\n/**\n * The one shot of the `layout` service this plugin needs, declared\n * structurally for the same reason as {@link PANEL_ID}: importing the package\n * would make the browser resolve a client module this bundle never calls.\n * Reached through the reflective `ctx.get('layout')`, never a bare `ctx.layout`\n * property — cordis throws `cannot get property … without inject` for an\n * undeclared service, and declaring `layout` statically would park the whole\n * client fiber (settings page included) on a service some profiles never mount.\n */\ninterface LayoutSelectionSeam {\n /** `null` shows the Conversation again; a string selects that registered `main` key. */\n selectPanel(id: string | null): void\n}\n\n/**\n * Connection fields retained by pre-0.1.2 clients and absent from the current\n * transport handle. Only the credential face and the host description are read.\n */\ninterface LegacyConnectionLike {\n api?: { credentials?: LegacyCredentialsApi }\n hostDescription?: HostDescriptionSource\n}\n\n/**\n * Client plugin body. Gates on the services shared by both client generations\n * (`slots`, `locale`, `connection`, `remote`) — never on `settingsScope`,\n * which 0.1.7 removed and which the settings scope here replaces for every\n * generation. Current clients mount the page after `remote.credentials`\n * appears; legacy clients mount it from the connection ApiProxy credential\n * face.\n */\nexport function apply(ctx: Context): void {\n injectPageCss()\n\n // The \"Command Code\" settings page: register the section once the\n // `settings.section` declaration is on the ledger (ui-settings-general\n // owns the shell; registration order relative to it is not constrained —\n // `slots.inject` waits for the declaration).\n ctx.effect(() => ctx.locale.register('settings.commandcode', { zh, en }), 'dsh-commandcode-provider: page copy')\n\n // The plans & quota panel's copy is a namespace of its own: the panel is not\n // part of the settings page, but it follows the SAME active language (both\n // panel registrations declare it below, which is what binds their `t` seat).\n // Registered here rather than next to those registrations so the namespace\n // exists even on the legacy credential path, which returns early below.\n ctx.effect(\n () => ctx.locale.register(PANEL_LOCALE_NS, { zh: PANEL_COPY_ZH, en: PANEL_COPY_EN }),\n 'dsh-commandcode-provider: panel copy',\n )\n\n const connection = ctx.get('connection') as LegacyConnectionLike | undefined\n const legacyApi = adaptLegacyCredentials(connection?.api?.credentials)\n if (legacyApi !== undefined) {\n applyClientSurfaces(ctx, legacyApi, connection?.hostDescription)\n return\n }\n\n // DSH 0.1.2 exposes credentials through a Typert Remote namespace. Keep it\n // optional at the root so a legacy client without `remote.credentials` can\n // still activate through the ApiProxy branch above.\n ctx.inject(['remote.credentials'], (remoteCtx) => {\n const credentials = (remoteCtx.remote as unknown as {\n credentials: SettingsPageApi['credentials']\n }).credentials\n applyClientSurfaces(remoteCtx, { credentials })\n })\n}\n\n/** Mount the one shared UI implementation over either credential transport. */\nfunction applyClientSurfaces(\n ctx: Context,\n api: SettingsPageApi,\n hostDescription?: HostDescriptionSource,\n): void {\n // The settings scope: this plugin's own binding of the `llm-commandcode`\n // namespace over `remote.settings` (see `./settings-scope.ts`). The harness\n // used to provide a `settingsScope` service to bind here, but that wrapper\n // existed only through 0.1.6 and was removed with the 0.1.7 settings\n // rewrite — while the describe/mutate wire underneath spans every\n // supported release, so one implementation now serves all of them.\n //\n // The namespace object is captured from an INJECT-SCOPED context, never read\n // off `ctx.remote`: `remote.settings` is a Cordis service nested under\n // `remote`, and cordis answers a read through a context that does not declare\n // it with `Error: cannot get property \"remote.settings\" without inject`. That\n // throw lands inside the scope's own `try`/`catch` (so nothing is logged),\n // leaving the mirror unanswered, the scope on its initial `writable: false`\n // snapshot, and the page read-only with every control disabled — the 0.1.7\n // settings-page report. The resolver below hands the scope the very object\n // the inject resolved; `refresh()` re-reads once it lands, and a profile whose\n // Host serves no settings namespace simply never resolves it, where the page\n // keeps rendering its degraded state instead of crashing.\n let settingsNamespace: SettingsRemoteNamespace | undefined\n const scope = createSettingsScope<Record<string, unknown>>(\n ctx as unknown as SettingsScopeContext,\n COMMANDCODE_NS,\n () => settingsNamespace,\n )\n ctx.effect(() => () => { void scope.dispose() }, 'dsh-commandcode-provider: settings scope')\n ctx.inject(['remote.settings'], (settingsCtx) => {\n settingsNamespace = (settingsCtx.remote as unknown as {\n settings: SettingsRemoteNamespace\n }).settings\n // The first read raced this inject and answered \"not mounted\"; re-read now\n // that the namespace is here (and again whenever it re-mounts).\n scope.refresh()\n settingsCtx.effect(() => () => {\n settingsNamespace = undefined\n }, 'dsh-commandcode-provider: settings namespace')\n })\n // The model catalog for the settings page's model editors (the\n // routing-rule editor and the visible-models filter) is served by the\n // `commandcode/models` Remote below; the controller reads it through this\n // mutable seam so the Remote mount (which happens after the controller is\n // constructed) still reaches the catalog fetch. Unset until the mount\n // lands — the controller degrades to the empty-catalog state meanwhile.\n let modelsRemote: NonNullable<SettingsPageApi['models']> | undefined\n const controller = new CommandCodeSettingsController(\n scope,\n { ...api, models: () => modelsRemote?.() ?? Promise.resolve({ ok: false, error: { message: 'commandcode/models remote is not mounted' } }) },\n hostDescription,\n )\n ctx.effect(() => () => controller.dispose(), 'dsh-commandcode-provider: settings controller')\n const store = createSnapshotStore<SettingsPageState>(controller.state())\n controller.subscribe(() => store.set(controller.state()))\n ctx.effect(\n () => (ctx.remote as unknown as {\n $on(event: 'credentials/reference-updated', listener: (ref: string) => void): () => void\n }).$on('credentials/reference-updated', () => { controller.refreshCredentials() }),\n 'dsh-commandcode-provider: credential invalidations',\n )\n\n // The account-usage card + login panel: mount the shared Remote contribution\n // (one mount carries every endpoint this plugin serves — report, catalog,\n // price table, and login — so the Client's bookkeeping stays 1:1 with the\n // Host's single registry registration), then resolve the\n // `remote.commandcode` namespace through a scoped inject. Cordis only serves\n // services a fiber declares in `inject`, and the namespace service exists\n // only after the mount — a static inject would deadlock the plugin (the\n // mounter would wait for its own mount), so the inject is registered\n // dynamically once the mount lands. A Host half that predates the Remote\n // fails the calls instead, and the surfaces render their error branches.\n let usageNamespace: (typeof ctx.remote)['commandcode'] | undefined\n let usageMountError: string | undefined\n // Declared here, constructed below once the Remote seam exists: the mount\n // effect underneath calls `ensure()` from its inject callback, which cordis\n // runs synchronously while the mount promise settles — before the\n // controller's own `const` below would have been initialized.\n let pricesController: CommandCodePricesController | undefined\n // The same hazard for the usage controller, whose `const` is just as far\n // below: the inject callback needs a way to ask for a report without\n // touching that binding before it is initialized (a `const` read in its\n // temporal dead zone THROWS, so `?.` would not save it).\n let refreshUsage: (() => void) | undefined\n const contribution: TypertRemoteContribution = {\n package: USAGE_REMOTE_CONTRIBUTION.package,\n descriptors: [\n ...USAGE_REMOTE_CONTRIBUTION.descriptors,\n ...MODELS_REMOTE_CONTRIBUTION.descriptors,\n ...PRICES_REMOTE_CONTRIBUTION.descriptors,\n ...LOGIN_REMOTE_CONTRIBUTION.descriptors,\n ],\n }\n ctx.effect(() => {\n let cancelled = false\n let unmount: (() => Promise<void>) | undefined\n void ctx.remote.$mount(contribution).then((dispose: () => Promise<void>) => {\n if (cancelled) {\n void dispose()\n return\n }\n unmount = dispose\n ctx.inject(['remote.commandcode'], (namespaceCtx) => {\n usageNamespace = namespaceCtx.remote.commandcode\n // The catalog Remote is live now; (re)fetch it for the model editors.\n controller.refreshCatalog()\n // ...and the price table, which the composer's cost readout needs. This\n // is its only trigger: `ensure()` is idempotent, so a readout already on\n // screen simply starts pricing when the table lands, and asking earlier\n // could only fail (the namespace did not exist yet).\n pricesController?.reload()\n // ...and the usage report. A surface can (and on a boot with the quota\n // card on, always does) ask for it BEFORE this mount lands: the answer\n // then is the synthetic \"remote is not mounted\" failure, which the\n // controller stores as `status: 'error'` — and its `shouldRefresh` only\n // fires from `idle`, so nothing would ever retry it (`usage.ts`). The\n // namespace is live here, so re-read now and replace that stale answer.\n refreshUsage?.()\n namespaceCtx.effect(() => () => {\n usageNamespace = undefined\n }, 'dsh-commandcode-provider: usage namespace')\n })\n }, (error: unknown) => {\n // A mount failure (e.g. a harness without the Remote mount) leaves the\n // namespace unset; keep the reason so the card can surface it.\n usageMountError = error instanceof Error ? error.message : String(error)\n })\n return () => {\n cancelled = true\n usageNamespace = undefined\n if (unmount !== undefined) void unmount()\n }\n }, 'dsh-commandcode-provider: usage remote')\n const usageRemote: UsageRemote = {\n report: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/report remote is not mounted' } }\n }\n return namespace.report()\n },\n models: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/models remote is not mounted' } }\n }\n return namespace.models()\n },\n prices: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/prices remote is not mounted' } }\n }\n const call = namespace.prices\n // A Host half older than the price table mounts no such descriptor, so\n // the namespace member is genuinely missing. Report it as a failure the\n // readout treats as permanent rather than throwing.\n if (typeof call !== 'function') {\n return { ok: false, error: { message: 'the Host serves no commandcode/prices endpoint', permanent: true } }\n }\n return call.call(namespace)\n },\n }\n // Wire the catalog Remote into the settings controller's models seam so the\n // model editors can fetch the catalog once the mount lands.\n modelsRemote = () => usageRemote.models()\n const usageController = new CommandCodeUsageController(usageRemote)\n refreshUsage = () => void usageController.refresh()\n ctx.effect(() => () => usageController.dispose(), 'dsh-commandcode-provider: usage controller')\n const usageStore = createSnapshotStore<UsagePageState>(usageController.state())\n usageController.subscribe(() => usageStore.set(usageController.state()))\n\n // The composer's session-cost readout prices a session from a static table,\n // so its controller is a one-shot cache rather than a poll: it fetches once\n // the namespace is live and never again.\n pricesController = new CommandCodePricesController(usageRemote)\n ctx.effect(() => () => pricesController?.dispose(), 'dsh-commandcode-provider: price table')\n const pricesStore = createSnapshotStore<SessionCostPricesState>(pricesController.state())\n pricesController.subscribe(() => pricesStore.set(pricesController.state()))\n\n // The login panel: same namespace, three endpoints; the key never crosses\n // to the browser — the Host validates and stores it through the credentials\n // seam, and a landed login re-reads the credential badges + usage card.\n const loginRemote: LoginRemote = {\n loginBegin: async (targetRef?: string) => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginBegin(targetRef)\n },\n loginStatus: async () => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginStatus()\n },\n loginCancel: async () => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginCancel()\n },\n }\n const loginController = new CommandCodeLoginController(() => loginRemote)\n ctx.effect(() => () => loginController.dispose(), 'dsh-commandcode-provider: login controller')\n const loginStore = createSnapshotStore<LoginPageState>(loginController.state())\n let lastLoginPhase = loginController.state().phase\n loginController.subscribe(() => {\n const phase = loginController.state().phase\n // A landed login stored the key Host-side behind the page's back; the\n // badges must follow and the account card can finally fetch.\n if (phase === 'success' && lastLoginPhase !== 'success') {\n controller.refreshCredentials()\n void usageController.refresh()\n }\n lastLoginPhase = phase\n loginStore.set(loginController.state())\n })\n\n const injected = () => ({\n hooks: { commandCodeSettings: store, commandCodeUsage: usageStore, commandCodeLogin: loginStore },\n edit: (field: string, text: string) => controller.edit(field, text),\n resetField: (field: string) => controller.resetField(field),\n // A landed save can change the key or endpoint the usage endpoints read,\n // so the account card refetches; a failed save keeps the old data.\n save: () => void controller.save().then(() => {\n const settled = controller.state()\n if (!settled.failed && settled.anyAccountConfigured) void usageController.refresh()\n }),\n discard: () => controller.discard(),\n refreshUsage: () => void usageController.refresh(),\n beginLogin: (targetRef?: string) => void loginController.begin(targetRef),\n cancelLogin: () => void loginController.cancel(),\n addAccount: () => controller.addAccount(),\n removeAccount: (id: string) => controller.removeAccount(id),\n editAccountLabel: (id: string, text: string) => controller.editAccountLabel(id, text),\n editAccountKey: (id: string, text: string) => controller.editAccountKey(id, text),\n toggleKeyClear: (id: string) => controller.toggleKeyClear(id),\n addRule: () => controller.addRule(),\n removeRule: (id: string) => controller.removeRule(id),\n editRuleModels: (id: string, ids: string[]) => controller.editRuleModels(id, ids),\n editRuleAccount: (id: string, text: string) => controller.editRuleAccount(id, text),\n editVisibleModels: (ids: string[]) => controller.editVisibleModels(ids),\n clearVisibleModels: () => controller.clearVisibleModels(),\n })\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'commandcode',\n order: 12,\n label: () => ctx.locale.bind('settings.commandcode')('nav'),\n locale: 'settings.commandcode',\n inject: injected,\n }, CommandCodeSettingsPage))\n\n // The Models-page provider panel (dsh 0.1.2, rc.1): a keyed slot the\n // Models section dispatches with `entryKey = settingsNs` on every provider\n // card of an adapter family. Registering under `llm-commandcode` mounts the\n // panel beside the official editor on every Command Code row — including\n // the first-run setup posture, exactly where a user without a key lands.\n // While the official 编辑 toggle is open, the panel hides the official\n // editor shell (for this namespace it holds only the settings.yaml hint\n // over a disabled apply) and shows the real controls; see card.tsx.\n // The registration carries its own inject face (store hooks + actions)\n // because the declaring entry is ui-settings-models', not ours; the `t`\n // seat comes from the registration's own `locale` namespace.\n //\n // On dsh builds without this slot the declaration never exists and\n // `slots.inject` never fires its callback — the registration silently\n // does not happen, and nothing else about the plugin changes.\n ctx.slots.inject('settings.models.provider-card', () => ctx.slots.register({\n name: 'settings.models.provider-card',\n key: 'llm-commandcode',\n locale: 'settings.commandcode',\n inject: () => ({\n hooks: { commandCodeSettings: store, commandCodeLogin: loginStore },\n edit: (field: string, text: string) => controller.edit(field, text),\n save: () => void controller.save().then(() => {\n const settled = controller.state()\n if (!settled.failed && settled.anyAccountConfigured) void usageController.refresh()\n }),\n discard: () => controller.discard(),\n beginLogin: () => void loginController.begin(),\n cancelLogin: () => void loginController.cancel(),\n }),\n }, CommandCodeProviderCard))\n\n // The plans & quota panel: a footer card pinned at the bottom of the\n // sidebar, on top of the Settings seat, that opens a dashboard in the\n // center column.\n //\n // Two registrations, one navigation entry. `sidebar.footer.action` is the\n // list the sidebar shell renders in its foot area directly above the\n // Settings seat (`footArea` = `footerActions` then `settingsArea`), which is\n // what puts this card at the bottom of the column rather than at the top\n // with the global panel icons of `sidebar.panellist`. The layout's keyed\n // `main` slot holds the panel the card opens — `ctx.layout.selectPanel(id)`\n // resolves the id against that registry and throws when no cell occupies it,\n // so BOTH are required, and BOTH need the `inject` face below (an entry\n // without one receives none of the panel's data; see the `hooks` → `useX`\n // rule in panel-view.tsx).\n //\n // Unlike a `sidebar.panellist` row, the shell renders NO chrome around a\n // footer action: our component is the button, it owns the label (so a title\n // carrying live quota needs no re-registration — that dance exists only\n // because the shell caches a panellist entry's label), and it selects the\n // panel itself through the `open` action below.\n //\n // Both registrations declare the panel's own `locale` namespace\n // (`panel.commandcode`, registered in `apply` above), which is what binds the\n // `t` seat the components feed into `buildPanelView` — so the panel follows\n // the harness's active language and a switch re-renders it (the renderer\n // mints a fresh `t` per revision, and its identity is the invalidation).\n //\n // Version reality, measured across 0.1.1-rc.2 … 0.1.5-rc.2 (see AGENTS.md):\n // `sidebar.footer.action` and `conversation.composer.dock` exist and RENDER in\n // every one of those releases, while the layout's keyed `main` slot and its\n // `selectPanel` arrive in 0.1.5 (alpha.2 and rc.1 respectively). So the three\n // slots do NOT share a version floor, and the honest boundary is the layout\n // seam: without `selectPanel` the card would register, render, and do nothing\n // when clicked — a dead button. The footer registration is therefore gated on\n // the `layout` service, which arrives with the same package that owns `main`.\n //\n // The dashboard cell itself needs no such gate: registering a cell for a\n // declaration that never arrives is a no-op by construction (the callback only\n // runs while the declaration is live), so on an older engine it simply never\n // registers. Only the always-declared footer seat needed an explicit guard.\n //\n // Shape notes:\n // * The stylesheet gets its own `ctx.effect` rather than riding an `inject`\n // callback's return value, so the tag's lifetime is the plugin fiber's and\n // is unaffected by a slot declaration collapsing and re-declaring.\n // * Each registration is guarded so a failure in one surface cannot abort\n // `applyClientSurfaces` and take the OTHER surfaces down with it —\n // `slots.inject` rethrows a callback failure synchronously once the\n // declaration exists. The renderer contains a *render* crash by abdicating\n // the entry with no visible error, so a failure that leaves nothing on\n // screen must at least be loud in the console.\n const panelFace = (): PanelInjected => ({\n hooks: { commandCodeUsage: usageStore, commandCodeSettings: store },\n refresh: () => { pricesController?.ensure(); void usageController.refresh() },\n // The Host resolves every credential source, including CLI auth and literals.\n // A browser credential-reference lookup cannot determine availability.\n startAutoRefresh: () => startPanelAutoRefresh(usageController, () => true),\n // `layout` is read reflectively AT CLICK TIME, never captured at setup:\n // ui-layout is not a dependency of this bundle (its types are not imported\n // and its client module is never resolved), so a static `inject` would park\n // the whole client fiber — settings page included — on a service another\n // profile may never mount. The footer registration is gated on that same\n // seam, so by the time this runs the method exists; the guard stays as the\n // last line of defence against a layout that renames it.\n open: () => {\n const layout = ctx.get('layout') as LayoutSelectionSeam | undefined\n if (typeof layout?.selectPanel === 'function') layout.selectPanel(PANEL_ID)\n },\n // The dashboard's way out (issue #41). It occupies the center column in\n // place of the Conversation, and `open()` above is the ONLY other panel\n // selection this plugin makes — so without an exit the panel is a one-way\n // door: clicking the sidebar card just re-selects it. `selectPanel(null)`\n // is layout's \"show the Conversation\" selection and leaves the current\n // Session untouched. A layout whose `selectPanel` predates that `null`\n // form accepts only a registered key, so fall back to ui-conversation's\n // reserved `main` seat; a failure here must not take the surface down.\n close: () => {\n const layout = ctx.get('layout') as LayoutSelectionSeam | undefined\n if (typeof layout?.selectPanel !== 'function') return\n try {\n layout.selectPanel(null)\n } catch {\n try {\n layout.selectPanel(CONVERSATION_PANEL_ID)\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not close the plans & quota panel:', error)\n }\n }\n },\n })\n\n ctx.effect(() => injectPanelCss(), 'dsh-commandcode-provider: panel styles')\n\n try {\n ctx.slots.inject('main', () => ctx.slots.register(\n { name: 'main', key: PANEL_ID, locale: PANEL_LOCALE_NS, inject: panelFace },\n CommandCodePanel,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the plans & quota panel:', error)\n }\n\n // The footer card is registered only where the layout can actually open the\n // panel behind it. `ctx.inject(['layout'], …)` runs its body when that service\n // is live and re-runs it if the service is replaced, mirroring how the Remote\n // namespace is mounted — so a profile without ui-layout (the TUI, a headless\n // client) never registers the card, and a pre-0.1.5 engine that mounts a\n // layout lacking `selectPanel` is filtered out by the explicit capability\n // check below. Without this gate the card would render and silently do\n // nothing on click, which is worse than not being there.\n ctx.inject(['layout'], (layoutCtx) => {\n const layout = layoutCtx.get('layout') as LayoutSelectionSeam | undefined\n if (typeof layout?.selectPanel !== 'function') return\n try {\n layoutCtx.slots.inject('sidebar.footer.action', () => layoutCtx.slots.register(\n // `order` is the only control over position inside a list slot, and the\n // renderer sorts ascending. ui-cordis's footer chip registers at the\n // default 0, so 1 sorts after it — but any sibling passing an order ≥ 1\n // lands between this card and Settings, so \"directly above Settings\" is\n // a preference, not a guarantee.\n { name: 'sidebar.footer.action', id: PANEL_ID, order: 1, locale: PANEL_LOCALE_NS, inject: panelFace },\n CommandCodeFooterEntry,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the sidebar footer card:', error)\n }\n })\n\n // The composer's session-cost figure: an entry in the dock below the input\n // that renders NO surface of its own. The cost is injected into the harness's\n // own token-usage UI — the amount as the last item of the shipped pill's text\n // run, the breakdown as rows inside the usage dialog that pill opens (see\n // `./session-cost-display.ts`).\n //\n // The entry exists for its SEATS, not for a surface: `useProjection` is a\n // standard prop the composer hands every dock occupant, so this registration\n // is the only way to read the session's token accounting. Its id must stay\n // distinct from the shipped `stats` cell's, because registering under an\n // existing id REPLACES that cell rather than extending it.\n //\n // It carries only the price-table hook: the token buckets and the model\n // selection arrive from the composer itself as standard dock props\n // (`useProjection`), which the owner supplies to every occupant.\n //\n // No `locale` namespace and no `t` seat: the figure is English by\n // construction, from `./session-cost.ts`. dsh builds before 0.1.5 have no\n // `conversation.composer.dock`, so this registration silently does not happen\n // there — as does the injection itself, whose DOM anchors are 0.1.5 markup.\n const sessionCostFace = (): SessionCostInjected => ({\n hooks: { commandCodePrices: pricesStore },\n })\n\n try {\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n // No `order`: the entry renders nothing, so its position among the dock's\n // rows cannot matter — the sort only ever decides what a reader sees.\n { name: 'conversation.composer.dock', id: SESSION_COST_ID, inject: sessionCostFace },\n CommandCodeSessionCost,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the composer session-cost readout:', error)\n }\n}\n\nexport const inject: readonly string[] = [\n 'slots',\n 'locale',\n 'connection',\n 'remote',\n]\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["numberField","booleanField","IDLE","record","stringField","reject","pkg.version","(pkg as { repository?: unknown }).repository","useState","useMemo","Menu","Button","useCallback","useRef","HIDDEN_STYLE","useState","useRef","useState","Button","useRef"],"sources":["../src/client/snapshot-store.ts","../src/client/settings-scope.ts","../src/client/settings.ts","../src/client/usage.ts","../src/client/prices.ts","../src/client/login.ts","../src/wire-shared.ts","../src/usage-wire.ts","../src/login-wire.ts","../src/client/model-select.ts","../package.json","../src/client/version.ts","../src/client/update.ts","../src/client/section.tsx","../src/client/login-row.tsx","../src/client/card.tsx","../src/client/panel-copy.ts","../src/client/panel.ts","../src/client/panel-view.tsx","../src/cost-facts.ts","../src/client/session-cost.ts","../src/client/session-cost-display.ts","../src/client/session-cost-view.tsx","../src/client/page-styles.ts","../src/client/panel-styles.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * A tiny observable snapshot store — the `getSnapshot` / `subscribe` / `set`\n * triple React's `useSyncExternalStore` consumes through the harness slot kit\n * (the host builds each slot's `useFoo(selector)` hook from one of these).\n *\n * Vendored on purpose, and small enough to stay that way: the harness's\n * `@deepseek-ai/dsh-client-store` is a seeded platform module, but pulling it in\n * would add a fourth `require()` target (and a client-only peer) to the bundle\n * for the ~30 lines used here, and its `set()` carries engine semantics\n * (dev-mode deep freeze, forced replacement) these callers do not want.\n */\n\n/** Mutable observable snapshot consumed by slot hooks. */\nexport interface SnapshotStore<T> {\n getSnapshot(): T\n subscribe(listener: () => void): () => void\n set(value: T): void\n}\n\n/** Notify every subscriber without letting one faulty UI consumer suppress the rest. */\nfunction notifyListeners(listeners: ReadonlySet<() => void>): void {\n for (const listener of listeners) {\n try {\n listener()\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] snapshot subscriber failed:', error)\n }\n }\n}\n\n/** Create one observable snapshot store. */\nexport function createSnapshotStore<T>(initial: T): SnapshotStore<T> {\n let snapshot = initial\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => snapshot,\n subscribe(listener: () => void) {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n set(value: T) {\n if (Object.is(value, snapshot)) return\n snapshot = value\n notifyListeners(listeners)\n },\n }\n}\n","/**\n * Browser settings scope over the `remote.settings` Typert namespace.\n *\n * Until dsh 0.1.6 the web client bound `ctx.settingsScope` — a wrapper\n * `ui-settings` provided, itself derived from a shared mirror of\n * `remote.settings.describe()`. The 0.1.7 settings rewrite REMOVED that\n * wrapper service (settings became schema-derived profile Config forms), but\n * the wire underneath — `describe()`, `mutate(namespace, ops, revision)`, the\n * forwarded `settings/document-updated` invalidation, and the view shape\n * `{ writable, namespaces: [{ ns, value, base, user, revision, schema }] }` —\n * is byte-identical from 0.1.2-rc.1 through 0.1.7-alpha.1 (verified against\n * both engines' `ui-settings` bundles, which drove the SAME mirror/controller\n * pair from the first release this plugin supports to the newest).\n *\n * So this module speaks that wire directly and implements the\n * `SettingsScope<T>` face the settings-page controller already consumes —\n * one path for every supported engine, no dependency on a wrapper that only\n * half of them ship:\n *\n * - A mirror serializes `describe()` reads behind one snapshot store (a\n * read during a read marks exactly one rerun; a FAILED read keeps the\n * held view, so a transient Host error never blanks the page).\n * - The scope derives this namespace's row from the mirror — `ready` with\n * the row's value when present, `unavailable` when the namespace is not\n * in the directory — and writes through a single-flight `mutate` queue\n * fenced by the row's revision, folding each accepted answer back into\n * the mirror and re-reading after a rejected one.\n * - Persistence follows the rule both generations of `ui-settings` use: a\n * loopback page edits the Host, a remote page stays process-local\n * (`mode: 'memory'`, status `unavailable`, writes become no-ops).\n *\n * The namespace object is NOT read off the context: `remote.settings` is a\n * Cordis service nested under `remote`, and Cordis throws\n * `cannot get property \"remote.settings\" without inject` for an undeclared\n * read. It arrives through the `resolveRemote` seam instead — an object\n * captured inside `ctx.inject(['remote.settings'], …)` by the client entry\n * (see {@link SettingsRemoteResolver} for the failure this prevents).\n *\n * React-free on purpose, so `tests/settings-scope.test.ts` can drive the\n * whole lifecycle over a fake remote.\n *\n * @module dsh-commandcode-provider/client/settings-scope\n */\n\nimport type { SettingsScope, SettingsScopeSnapshot } from './settings.ts'\nimport { createSnapshotStore, type SnapshotStore } from './snapshot-store.ts'\n\n/** Result envelope of one current Typert Remote call. */\ntype Envelope<T> = { ok: true; value: T } | { ok: false; error?: { message?: string } | undefined }\n\n/** One path-addressed form edit — the `SettingsPathOp` wire shape. */\nexport interface SettingsPathOp {\n op: 'set' | 'unset'\n path: readonly string[]\n value?: unknown\n}\n\n/** One entry's row inside a `settings.describe()` view — `SettingsNamespaceView`. */\ninterface SettingsNamespaceRow {\n ns?: unknown\n value?: unknown\n base?: unknown\n user?: unknown\n revision?: unknown\n}\n\n/** The `settings.describe()` view: the directory plus the Host's write posture. */\ninterface SettingsView {\n namespaces?: SettingsNamespaceRow[] | undefined\n writable?: boolean | undefined\n}\n\n/** The `remote.settings` namespace this scope calls. Structural: never imported. */\nexport interface SettingsRemoteNamespace {\n describe(): Promise<Envelope<SettingsView>>\n /** A write answers with the fresh ROW for its namespace, not the directory. */\n mutate(\n namespace: string,\n ops: readonly SettingsPathOp[],\n revision?: number,\n ): Promise<Envelope<SettingsNamespaceRow>>\n}\n\n/**\n * Reads the `remote.settings` namespace object, or `undefined` while it is not\n * mounted.\n *\n * This is a SEAM rather than a property on {@link SettingsScopeContext} because\n * `remote.settings` is a Cordis service nested under `remote`, and Cordis\n * throws for an undeclared nested read:\n *\n * Error: cannot get property \"remote.settings\" without inject\n *\n * The service object therefore has to be captured inside a context that\n * declares it (`ctx.inject(['remote.settings'], (settingsCtx) => …)`) and handed\n * in here. Reading it off our own `ctx.remote` instead throws on EVERY\n * supported engine — including ≤0.1.6, whose `remote.settings` namespace is the\n * same shape — and the throw lands inside this module's own `try`/`catch`, so\n * the failure is silent: no describe is ever sent, the scope keeps its initial\n * `writable: false` snapshot, and the settings page renders read-only with every\n * control disabled. That was the 0.1.7 settings-page report.\n */\nexport type SettingsRemoteResolver = () => SettingsRemoteNamespace | undefined\n\n/**\n * The client `Context` slice this module consumes, typed structurally so the\n * browser bundle never imports a version-specific module value and node tests\n * can hand in a plain object. Only `remote` itself (a declared service) is read\n * here — never `remote.<namespace>`, which requires its own inject.\n */\nexport interface SettingsScopeContext {\n remote: {\n $host?: { isLoopback?: boolean } | undefined\n $on?: ((event: string, listener: () => void) => (() => void) | undefined) | undefined\n }\n /** Connection lifecycle; older clients and tests may omit it. */\n on?: ((event: string, listener: () => void) => unknown) | undefined\n}\n\n/** Mirror snapshot: one in-flight-or-idle describe read and its held view. */\ninterface MirrorState {\n status: 'idle' | 'loading' | 'ready' | 'unavailable'\n view: SettingsView | null\n error: string | null\n}\n\nconst MEMORY_STATUS: MirrorState['status'] = 'unavailable'\n\n/**\n * Backoff before re-reading a directory whose FIRST read failed, in millis.\n *\n * A first read can lose to a Host that is still coming up (the gateway's WS\n * handshake, a settings service mid-start): the failure is transient, but the\n * scope has nothing held, so it keeps its initial `{ status: 'loading',\n * writable: false }` snapshot — and every control on the settings page renders\n * disabled behind a \"read-only\" banner. Nothing else would ever re-read it:\n * the forwarded `settings/document-updated` and `connection/reset` signals need\n * a live Host to fire, and the namespace only re-mounts on a page reload. So a\n * failure with NOTHING held retries on this bounded ladder; a failure with a\n * held view keeps it (no retry — the page is already showing the last good\n * document, and `tests/settings-scope.test.ts` pins that).\n */\nexport const SETTINGS_DESCRIBE_RETRY_MS: readonly number[] = [1000, 2000, 4000]\n\n/** Timer seam for the bounded describe retry; tests drive it without waiting. */\nexport interface SettingsRetryTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\n\n/** The production timer: a browser/node timeout, no polling. */\nconst REAL_SETTINGS_TIMER: SettingsRetryTimer = {\n set(callback, ms) {\n const handle = setTimeout(callback, ms)\n ;(handle as { unref?: () => void }).unref?.()\n return handle\n },\n clear(handle) { clearTimeout(handle as ReturnType<typeof setTimeout>) },\n}\n\n/** Shallow equality over the snapshot fields, so an unchanged derive never churns subscribers. */\nfunction sameSnapshot(a: SettingsScopeSnapshot<never>, b: SettingsScopeSnapshot<never>): boolean {\n return a.status === b.status\n && Object.is(a.value, b.value)\n && Object.is(a.base, b.base)\n && Object.is(a.user, b.user)\n && Object.is(a.revision, b.revision)\n && a.writable === b.writable\n && a.mode === b.mode\n}\n\n/** Accept a decoded row value only when it is the object a settings section is. */\nfunction decodeRow(value: unknown): Record<string, unknown> | undefined {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n return value as Record<string, unknown>\n}\n\n/**\n * One shared mirror of the Host `settings.describe()` view.\n *\n * The run loop is the harness's own: serialize behind `inFlight`, fold a\n * concurrent invalidation into exactly one rerun, and hold the previous view\n * across a failed read (status stays `ready` with an `error`, or returns to\n * `idle` when nothing was ever held).\n */\nclass SettingsDescribeMirror {\n private readonly store: SnapshotStore<MirrorState>\n private readonly persistence: 'host' | 'memory'\n private inFlight: Promise<void> | undefined\n private rerun = false\n private generation = 0\n /** Pending retry handle and how many of {@link SETTINGS_DESCRIBE_RETRY_MS} are spent. */\n private retryHandle: unknown\n private retries = 0\n private disposed = false\n\n /**\n * @param resolveRemote - Reads the inject-captured `remote.settings` namespace.\n * @param persistence - Client-selected Host persistence; non-loopback pages may stay process-local.\n * @param timer - Retry timer seam (see {@link SETTINGS_DESCRIBE_RETRY_MS}).\n */\n constructor(\n private readonly resolveRemote: SettingsRemoteResolver,\n persistence: 'host' | 'memory',\n private readonly timer: SettingsRetryTimer = REAL_SETTINGS_TIMER,\n ) {\n this.persistence = persistence\n this.store = createSnapshotStore<MirrorState>({\n status: persistence === 'host' ? 'idle' : MEMORY_STATUS,\n view: null,\n error: null,\n })\n }\n\n getSnapshot(): MirrorState {\n return this.store.getSnapshot()\n }\n\n subscribe(listener: () => void): () => void {\n return this.store.subscribe(listener)\n }\n\n /** The cheap idempotent entry: kick a first read (a no-op on memory persistence). */\n ensure(): void {\n void this.load()\n }\n\n /**\n * Refresh from the Host. A call during an in-flight read marks one rerun\n * after it settles instead of racing a second wire read.\n * @returns settlement after this call's freshness is reflected.\n */\n load(): Promise<void> {\n // Memory persistence: the mirror never loads (the initial snapshot IS the\n // terminal state), matching both generations of ui-settings.\n if (this.disposed || this.persistence === 'memory') return Promise.resolve()\n // A live read supersedes a scheduled retry: the retry exists only to\n // revive a mirror that nothing else would ever re-read.\n this.clearRetry()\n if (this.inFlight !== undefined) {\n this.rerun = true\n return this.inFlight\n }\n const run = Promise.resolve().then(() => this.run())\n this.inFlight = run\n return run\n }\n\n /**\n * Fold one write answer's namespace ROW into the held view without a wire\n * read, and invalidate any read still in flight: a read begun before the\n * write committed must not publish the pre-write document over it. With no\n * held document the answer is not published as a partial document — the\n * next read (or the failed-write recovery) picks it up.\n * @param row - The namespace view a settings write answered with.\n */\n acceptView(row: SettingsNamespaceRow): void {\n const before = this.store.getSnapshot()\n this.generation += 1\n if (this.inFlight !== undefined) this.rerun = true\n if (before.view === null) return\n const held = before.view\n const namespaces = held.namespaces?.some((candidate) => candidate.ns === row.ns)\n ? held.namespaces.map((candidate) => (candidate.ns === row.ns ? row : candidate))\n : [...(held.namespaces ?? []), row]\n this.store.set({ ...before, view: { ...held, namespaces } })\n }\n\n private async run(): Promise<void> {\n try {\n for (;;) {\n const before = this.store.getSnapshot()\n if (before.status === 'idle') this.store.set({ ...before, status: 'loading' })\n this.rerun = false\n const generation = ++this.generation\n let outcome: { view: SettingsView } | { failure: string }\n try {\n const namespace = this.resolveRemote()\n if (namespace === undefined) throw new Error('the settings remote namespace is not mounted')\n const response = await namespace.describe()\n if (response.ok) {\n const value: unknown = response.value\n // The mirror holds a VIEW or nothing: an empty/malformed answer\n // must not be published as `ready` with an undefined view, or the\n // derive below would read through it. (Upstream guards the same way\n // by testing the held view for `undefined`.)\n outcome = typeof value === 'object' && value !== null\n ? { view: value as SettingsView }\n : { failure: 'settings describe answered no view' }\n } else {\n outcome = { failure: response.error?.message ?? 'settings describe failed' }\n }\n } catch (error: unknown) {\n outcome = { failure: error instanceof Error ? error.message : String(error) }\n }\n if (generation !== this.generation) continue\n if ('view' in outcome) {\n this.retries = 0\n this.store.set({ status: 'ready', view: outcome.view, error: null })\n } else {\n const held = this.store.getSnapshot()\n this.store.set({\n status: held.view === null ? 'idle' : 'ready',\n view: held.view,\n error: outcome.failure,\n })\n // Nothing was EVER held: the scope is stuck on its initial\n // `loading`/`writable: false` snapshot, which the settings page\n // renders as a fully disabled form. Retry on the bounded ladder so a\n // Host that was still starting up heals without a page reload; a\n // held view needs none (the page already shows the last good\n // document).\n if (held.view === null) this.scheduleRetry()\n }\n if (!this.rerun) break\n }\n } finally {\n this.inFlight = undefined\n }\n }\n\n /**\n * Schedule the next retry of a failed FIRST read ({@link SETTINGS_DESCRIBE_RETRY_MS}).\n * Bounded: once the ladder is spent the scope keeps its degraded snapshot,\n * exactly as before, until an invalidation or a namespace re-mount arrives.\n */\n private scheduleRetry(): void {\n if (this.disposed || this.retries >= SETTINGS_DESCRIBE_RETRY_MS.length) return\n const delay = SETTINGS_DESCRIBE_RETRY_MS[this.retries]!\n this.retries += 1\n this.retryHandle = this.timer.set(() => {\n this.retryHandle = undefined\n void this.load()\n }, delay)\n }\n\n /** Cancel a pending retry (a live read is starting, or the scope is going away). */\n private clearRetry(): void {\n if (this.retryHandle !== undefined) this.timer.clear(this.retryHandle)\n this.retryHandle = undefined\n }\n\n /** Stop the mirror: no further reads, and no retry may fire after disposal. */\n dispose(): void {\n this.disposed = true\n this.clearRetry()\n }\n}\n\n/**\n * One namespace's derived scope over the shared mirror, plus its serialized\n * Host writes. This is the face `CommandCodeSettingsController` consumes\n * (`getSnapshot` / `subscribe` / `set` / `unset`), so the controller itself\n * needs no changes for either generation.\n */\nclass RemoteSettingsScope<T> implements SettingsScope<T> {\n private readonly resolveRemote: SettingsRemoteResolver\n private readonly store: SnapshotStore<SettingsScopeSnapshot<T>>\n private readonly mirror: SettingsDescribeMirror\n private readonly namespace: string\n private readonly persistence: 'host' | 'memory'\n private tail: Promise<void> = Promise.resolve()\n private writeGeneration = 0\n private disposed = false\n private unsubscribe: (() => void) | undefined\n /** Revision answered by a superseded write still ahead of the mirror. */\n private pendingRevision: number | undefined\n\n constructor(\n resolveRemote: SettingsRemoteResolver,\n mirror: SettingsDescribeMirror,\n namespace: string,\n persistence: 'host' | 'memory',\n ) {\n this.resolveRemote = resolveRemote\n this.mirror = mirror\n this.namespace = namespace\n this.persistence = persistence\n this.store = createSnapshotStore<SettingsScopeSnapshot<T>>({\n status: persistence === 'host' ? 'loading' : 'unavailable',\n value: undefined,\n base: undefined,\n user: undefined,\n revision: undefined,\n writable: false,\n mode: persistence,\n })\n if (persistence === 'host') {\n this.unsubscribe = mirror.subscribe(() => { this.derive() })\n this.derive()\n }\n }\n\n getSnapshot(): SettingsScopeSnapshot<T> {\n return this.store.getSnapshot()\n }\n\n subscribe(listener: () => void): () => void {\n return this.store.subscribe(listener)\n }\n\n /** Queue one field write (the single-path `set` op form). */\n set(field: string, value: unknown): Promise<void> {\n return this.mutate([{ op: 'set', path: [field], value }])\n }\n\n /** Queue one field clear (the single-path `unset` op form). */\n unset(field: string): Promise<void> {\n return this.mutate([{ op: 'unset', path: [field] }])\n }\n\n /**\n * Queue one atomic namespace mutation behind the single-flight fence.\n * A rejected write (e.g. `SETTINGS_CONFLICT`) re-reads the Host so the\n * snapshot reports what actually landed; an accepted one folds its answer\n * in directly — unless a newer write already superseded it, in which case\n * that answer's revision becomes the next write's fence.\n */\n private mutate(ops: readonly SettingsPathOp[], expectedRevision?: number): Promise<void> {\n const ownedOps = structuredClone(ops)\n const generation = ++this.writeGeneration\n return this.enqueue(async () => {\n const revision = expectedRevision ?? this.pendingRevision ?? this.getSnapshot().revision\n const response = await this.mutateRemote(ownedOps, revision)\n if (!response.ok) {\n await this.recover(generation)\n return\n }\n if (this.disposed) return\n const row = response.value\n if (generation === this.writeGeneration) {\n this.pendingRevision = undefined\n this.mirror.acceptView(row)\n } else {\n this.pendingRevision = typeof row.revision === 'number' ? row.revision : undefined\n }\n })\n }\n\n private async mutateRemote(\n ops: readonly SettingsPathOp[],\n revision: number | undefined,\n ): Promise<Envelope<SettingsNamespaceRow>> {\n try {\n const namespace = this.resolveRemote()\n if (namespace === undefined) {\n return { ok: false, error: { message: 'the settings remote namespace is not mounted' } }\n }\n return await namespace.mutate(this.namespace, ops, revision)\n } catch (error: unknown) {\n return { ok: false, error: { message: error instanceof Error ? error.message : String(error) } }\n }\n }\n\n /** Reload Host state for the latest failed write; superseded failures leave recovery to it. */\n private async recover(generation: number): Promise<void> {\n if (this.disposed || generation !== this.writeGeneration) return\n this.pendingRevision = undefined\n await this.mirror.load()\n }\n\n /** Derive this namespace's snapshot from the mirror's held view. */\n private derive(): void {\n if (this.disposed) return\n const mirrored = this.mirror.getSnapshot()\n // `undefined` as well as `null`: the held view is only ever the wire's\n // answer, and a malformed one never reaches the store (see `run`).\n if (mirrored.view === null || mirrored.view === undefined) return\n const writable = mirrored.view.writable === true\n const row = mirrored.view.namespaces?.find((candidate) => candidate.ns === this.namespace)\n if (row === undefined) {\n this.publish({ status: 'unavailable', writable })\n return\n }\n const decoded = decodeRow(row.value)\n if (decoded === undefined) return\n this.publish({\n status: 'ready',\n writable,\n value: decoded as T,\n base: row.base,\n user: row.user,\n revision: typeof row.revision === 'number' ? row.revision : undefined,\n })\n }\n\n /** Publish `next` over the current snapshot, skipping the write when nothing changed. */\n private publish(next: {\n status: SettingsScopeSnapshot<T>['status']\n writable: boolean\n value?: T\n base?: unknown\n user?: unknown\n revision?: number | undefined\n }): void {\n const current = this.store.getSnapshot()\n const candidate: SettingsScopeSnapshot<T> = {\n status: next.status,\n value: 'value' in next ? next.value : current.value,\n base: 'base' in next ? next.base : current.base,\n user: 'user' in next ? next.user : current.user,\n revision: 'revision' in next ? next.revision : current.revision,\n writable: next.writable,\n mode: current.mode,\n }\n if (sameSnapshot(candidate as SettingsScopeSnapshot<never>, current as SettingsScopeSnapshot<never>)) return\n this.store.set(candidate)\n }\n\n /** Queue operations one at a time; memory persistence and disposal are no-ops. */\n private enqueue(operation: () => Promise<void>): Promise<void> {\n if (this.persistence === 'memory' || this.disposed) return Promise.resolve()\n const task = this.tail.then(async () => {\n if (this.disposed) return\n await operation()\n })\n this.tail = task.catch(() => {})\n return task\n }\n\n /** Stop queued operations, stop deriving, and wait for the current wire call to settle. */\n async dispose(): Promise<void> {\n this.disposed = true\n this.writeGeneration += 1\n this.unsubscribe?.()\n await this.tail\n }\n}\n\n/** The scope plus the handles the plugin entry wires into its fiber lifecycle. */\nexport interface ManagedSettingsScope<T> extends SettingsScope<T> {\n /** Re-read the Host — used when the `remote.settings` namespace mounts after boot. */\n refresh(): void\n /** Stop deriving, drop the forwarded-event subscriptions, and settle in-flight work. */\n dispose(): Promise<void>\n}\n\n/**\n * Build the plugin's settings scope for one namespace.\n *\n * Subscribes the two signals that can move the Host view — the forwarded\n * `settings/document-updated` invalidation and (when the client exposes it)\n * `connection/reset` — kicks the first describe read, and derives the\n * namespace row on every mirror change.\n *\n * `resolveRemote` is the INJECT-CAPTURED namespace (see\n * {@link SettingsRemoteResolver}): `remote.settings` is a Cordis service nested\n * under `remote`, so a read through our own context throws and has to be\n * replaced by an object captured inside `ctx.inject(['remote.settings'], …)`.\n * The caller that owns that inject calls {@link ManagedSettingsScope.refresh}\n * once the namespace lands, which is what turns the first, namespace-less read\n * into a served one; a profile that never mounts the namespace leaves the page\n * in its degraded (`unavailable`, read-only) state instead of throwing.\n *\n * @param context - The client context slice (only the declared `remote` service is read).\n * @param namespace - Settings namespace (profile entry id) this scope binds.\n * @param resolveRemote - Reads the inject-captured `remote.settings` namespace.\n * @returns The scope plus the refresh/dispose handles the entry wires into its fiber.\n */\nexport function createSettingsScope<T>(\n context: SettingsScopeContext,\n namespace: string,\n resolveRemote: SettingsRemoteResolver,\n timer: SettingsRetryTimer = REAL_SETTINGS_TIMER,\n): ManagedSettingsScope<T> {\n // Persistence follows ui-settings on both generations: a loopback page\n // edits the Host; a remote page stays process-local.\n const loopback = context.remote.$host?.isLoopback === true\n const persistence: 'host' | 'memory' = loopback ? 'host' : 'memory'\n const mirror = new SettingsDescribeMirror(resolveRemote, persistence, timer)\n const scope = new RemoteSettingsScope<T>(resolveRemote, mirror, namespace, persistence)\n const disposers: Array<() => void> = []\n if (loopback) {\n if (typeof context.remote.$on === 'function') {\n const off = context.remote.$on('settings/document-updated', () => { mirror.ensure() })\n if (typeof off === 'function') disposers.push(off)\n }\n if (typeof context.on === 'function') {\n const off = context.on('connection/reset', () => { void mirror.load() })\n if (typeof off === 'function') disposers.push(off as () => void)\n }\n mirror.ensure()\n }\n return {\n getSnapshot: () => scope.getSnapshot(),\n subscribe: (listener) => scope.subscribe(listener),\n set: (field, value) => scope.set(field, value),\n unset: (field) => scope.unset(field),\n refresh: () => { void mirror.load() },\n dispose: async () => {\n for (const dispose of disposers.splice(0)) dispose()\n // Before the scope: a pending describe retry would otherwise re-read a\n // directory nobody is rendering any more.\n mirror.dispose()\n await scope.dispose()\n },\n }\n}\n","/**\n * Browser controller for the \"Command Code\" settings page.\n *\n * The page lives at the same settings-nav level as General / Models / Plugins\n * (a `settings.section` entry, id `commandcode`). It exists because the\n * Models page renders an unknown-adapter-family card for the `commandcode`\n * provider and deliberately disables its submit — the API key cannot be\n * configured there. This page owns the connection facts the plugin resolves\n * per request:\n *\n * - API key -> written through the credentials domain under the reference\n * the plugin resolves (`apiKeyEnv`, default\n * `COMMANDCODE_API_KEY`). The literal never rides a response,\n * so the control only reports whether one is configured.\n * - API base -> the `llm-commandcode` settings namespace (`apiBase`), same\n * namespace the Models page card addresses.\n * - Timeouts, behavior switches, model visibility -> the same namespace,\n * staged and written on save.\n * - Accounts -> `accounts`, `activeAccount`, `modelAccountRules` and the\n * per-account credentials, committed immediately.\n *\n * The controller mirrors the plugin-card pattern from the harness's own\n * settings UI: it binds the `llm-commandcode` namespace through a\n * `SettingsScope` — this plugin's own binding of `remote.settings` (see\n * `./settings-scope.ts`; the harness's `settingsScope` wrapper existed only\n * through 0.1.6 and was removed with the 0.1.7 settings rewrite, while the\n * wire underneath spans every supported release) — keeps a staged draft of\n * edits, and writes them on save through `scope.set` / the credentials\n * domain. The Host stays the single fact source; the snapshot is republished\n * after each accepted write.\n *\n * This module is deliberately free of JSX — it only produces the state face\n * the React component renders.\n */\n\n/** The settings namespace the plugin registers (host half, src/index.ts). */\nexport const COMMANDCODE_NS = 'llm-commandcode'\n/** Default credential reference the plugin resolves when none is named. */\nexport const DEFAULT_API_KEY_REF = 'COMMANDCODE_API_KEY'\n\n/** The settings-scope snapshot fields consumed by this controller. */\nexport interface SettingsScopeSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n base: unknown\n user: unknown\n revision: number | undefined\n writable: boolean\n mode: 'host' | 'memory'\n}\n\n/** Current settings-scope service face used without importing a browser plugin value. */\nexport interface SettingsScope<T> {\n getSnapshot(): SettingsScopeSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n unset(field: string): Promise<void>\n}\n\n/** Result envelope returned by one current Typert Remote call. */\ninterface RemoteResult<T> {\n ok: boolean\n value?: T\n error?: { message: string }\n}\n\n/** Credential facts returned without exposing the credential value. */\ninterface CredentialInfo {\n configured: boolean\n writable: boolean\n}\n\n/** The narrow slice of the wire face this controller needs. */\nexport interface SettingsPageApi {\n /** Credential methods exposed by the current Typert Remote namespace. */\n credentials: {\n describe(refs: string[]): Promise<RemoteResult<Record<string, CredentialInfo>>>\n set(ref: string, value: string): Promise<RemoteResult<void>>\n unset(ref: string): Promise<RemoteResult<void>>\n }\n /**\n * The model catalog for the settings page's model editors (the\n * routing-rule editor and the visible-models filter; Host-side). Absent\n * on legacy transports without the Remote mount — the editors degrade to\n * the empty-catalog state.\n */\n models?(): Promise<RemoteResult<{ models: CatalogModelOption[] }>>\n}\n\n/** One editable text field's staged state (blank = keep stored value). */\nexport interface StagedField {\n /** Live draft text the input shows. */\n text: string\n /** Whether the user explicitly cleared the field (reset to inherited). */\n clear: boolean\n /** Whether the user layer carries this field (marks it overridden). */\n overridden: boolean\n /** Whether the staged draft fails to parse (blocks save). */\n invalid: boolean\n /**\n * Why the draft is invalid — a non-number (`format`) or an out-of-range\n * number (`tooSmall`/`tooLarge`); undefined when valid.\n */\n invalidReason: InvalidReason | undefined\n}\n\n/** Why a staged draft fails validation (drives the per-field error copy). */\nexport type InvalidReason = 'format' | 'tooSmall' | 'tooLarge'\n\n/**\n * One extra account row. Account management commits immediately (no page\n * save), so a row carries only Host facts — never a staged draft.\n */\nexport interface AccountItemState {\n /** Stable id — the account's credential reference (also its slot id). */\n id: string\n /** Credential reference this account's key lives under. */\n ref: string\n /** Stored label (falls back to the reference). */\n label: string\n /** Whether a key is stored for this account (Host-reported). */\n configured: boolean\n /** Whether the credentials domain can store the key. */\n writable: boolean\n}\n\n/** The immediate account operations, named for the failure copy. */\nexport type AccountOperation = 'create' | 'rename' | 'remove' | 'key' | 'active' | 'models'\n\n/** One selectable catalog model in the settings page's model editors. */\nexport interface CatalogModelOption {\n id: string\n name: string\n /**\n * Minimum plan-tier key (a Host `KNOWN_PLANS` value), or undefined for\n * models outside the snapshot / older Hosts. Drives the tier headings in\n * the editor dropdowns; absent tiers render unheaded.\n */\n tier?: string\n}\n\n/** The page's full state face, projected from the scope + drafts + credential. */\nexport interface SettingsPageState {\n /** Whether the namespace snapshot is ready. */\n available: boolean\n /** Whether the Host document accepts writes. */\n writable: boolean\n /** Whether the API key is currently configured (Host-reported). */\n apiKeyConfigured: boolean\n /** Whether ANY account (default or extra) has a stored key — gates the usage card. */\n anyAccountConfigured: boolean\n /** Whether the credentials domain can store the key. */\n apiKeyWritable: boolean\n /**\n * The default API key draft (write-only; starts blank, never echoes the\n * stored key). Only the Models-page card stages it for its own save; the\n * settings page writes keys immediately through `setAccountKey()`.\n */\n apiKey: StagedField\n /** apiBase draft. */\n apiBase: StagedField\n /** requestTimeoutMs draft. */\n requestTimeoutMs: StagedField\n /** streamIdleTimeoutMs draft. */\n streamIdleTimeoutMs: StagedField\n /**\n * transportMaxRetries draft: how many transport failures one request absorbs\n * before the failure surfaces (issue #39's second report — the retry policy's\n * 1000-attempt, 15-minute cadence turned a 10-second TCP connect timeout into\n * an ~8-minute stall). Unset means the Host default, so it stages like the\n * timeout fields above rather than as a toggle with an implicit default.\n */\n transportMaxRetries: StagedField\n /**\n * filterModelsByPlan draft, staged as `'true'`/`'false'`/`''` (unset). The\n * component renders it as a toggle; `''` means \"inherit the default\" (on).\n */\n filterModelsByPlan: StagedField\n /**\n * webSearch draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (on — Command Code\n * serves the dsh web_search tool).\n */\n webSearch: StagedField\n /**\n * showSidebarQuota draft, staged as `'true'`/`'false'`/`''` (unset). The\n * component renders it as a toggle; `''` means \"inherit the default\" (off —\n * the sidebar quota card is opt-in, so an unset document shows nothing on\n * the left).\n */\n showSidebarQuota: StagedField\n /**\n * commandGuard draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (off — the guard\n * turns a decision model's opinion into an approval grant, so it is opt-in).\n */\n commandGuard: StagedField\n /**\n * commandGuardLevel draft: `'high'` / `'medium'` / `'low'`, or `''` (unset,\n * which the Host reads as `'medium'`). The page renders it as a three-way\n * segmented control.\n */\n commandGuardLevel: StagedField\n /**\n * zdr draft, staged as `'true'`/`'false'`/`''` (unset). The component\n * renders it as a toggle; `''` means \"inherit the default\" (off — ZDR\n * changes which upstream serves a request and usually what it costs, so it\n * is opt-in like the guard above).\n */\n zdr: StagedField\n /**\n * Whether the STORED document turns the sidebar quota card on\n * (`showSidebarQuota === true`). This is the fact the sidebar card itself\n * follows — deliberately NOT the staged draft above: the page has an explicit\n * Save, and a card that appeared from an unsaved draft would outlive a\n * discarded edit (the staging lives as long as the client does) until the\n * next page load. The stored fact flips the moment a save lands, so the card\n * still appears/disappears without a reload.\n */\n sidebarQuota: boolean\n /**\n * The stored pinned account: a slot id (`default` or an extra account's\n * credential reference); `''` means \"auto — first usable account\".\n */\n activeAccount: string\n /** Extra accounts (multi-account rotation), in rotation order. */\n accounts: AccountItemState[]\n /**\n * Each account's dedicated models, keyed by slot id, derived from the stored\n * `modelAccountRules` with the runtime's first-match-wins semantics, so a\n * model sits under exactly the one account that would serve it.\n */\n accountModels: Record<string, string[]>\n /** Whether an immediate account operation is in flight. */\n accountBusy: boolean\n /** The last immediate account operation that failed (cleared by the next one). */\n accountFailed: AccountOperation | undefined\n /** Effective visible-model allowlist: staged draft or stored value. Empty = show all. */\n visibleModels: string[]\n /** The catalog the model editors offer (Host-side, empty until loaded). */\n catalogModels: CatalogModelOption[]\n /** Whether the catalog fetch failed (editors fall back to typing). */\n catalogFailed: boolean\n /** Whether any staged edit differs from the stored section. */\n dirty: boolean\n /** Whether a staged numeric field fails to parse (save blocked). */\n invalid: boolean\n /** Whether a save is in flight. */\n saving: boolean\n /** Whether the last save failed (drafts retained for correction). */\n failed: boolean\n /**\n * Monotonic counter bumped once per accepted save. The component watches it\n * to flash the save bar's \"saved\" confirmation (timing lives in the component; the\n * controller stays a plain state machine with no timers).\n */\n savedCount: number\n}\n\n/** Parsed outcome of one field's draft. */\ntype Parsed =\n | { kind: 'set'; value: string | number | boolean }\n | { kind: 'clear' }\n | { kind: 'invalid'; reason: InvalidReason }\n\n/** One field's staged draft (internal; the public face adds derived flags). */\ninterface Staged {\n text: string\n clear: boolean\n}\n\n/** A field conversion spec. */\ninterface FieldSpec {\n field: string\n format(value: unknown): string\n parse(text: string): Parsed\n}\n\n/** A free-text field; an empty draft clears it. */\nfunction textField(field: string): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'string' ? value : ''),\n parse: (text) => {\n const trimmed = text.trim()\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed }\n },\n }\n}\n\n/**\n * A numeric field; an empty draft clears it, anything non-numeric blocks\n * save, and an optional inclusive `bounds` range rejects out-of-range values\n * with a specific reason (the Host schema would reject them at save time with\n * only a generic failure — catching it here names the problem while typing).\n * Decimals pass: the Host schema is `z.number()` too, and a fractional\n * millisecond value is harmless even if pointless.\n */\nfunction numberField(field: string, bounds?: { min?: number; max?: number }): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'number' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n const parsed = Number(trimmed)\n if (!Number.isFinite(parsed)) return { kind: 'invalid', reason: 'format' }\n if (bounds?.min !== undefined && parsed < bounds.min) return { kind: 'invalid', reason: 'tooSmall' }\n if (bounds?.max !== undefined && parsed > bounds.max) return { kind: 'invalid', reason: 'tooLarge' }\n return { kind: 'set', value: parsed }\n },\n }\n}\n\n/** A field limited to fixed string choices; an empty draft clears it. */\nfunction choiceField(field: string, choices: readonly string[]): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'string' && choices.includes(value) ? value : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n return choices.includes(trimmed) ? { kind: 'set', value: trimmed } : { kind: 'invalid', reason: 'format' }\n },\n }\n}\n\n/**\n * A boolean field, staged as the strings `'true'`/`'false'` (an empty draft\n * clears it). The component renders a toggle and only ever stages these two\n * strings; anything else blocks save.\n */\nfunction booleanField(field: string): FieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'boolean' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim()\n if (trimmed === '') return { kind: 'clear' }\n if (trimmed === 'true') return { kind: 'set', value: true }\n if (trimmed === 'false') return { kind: 'set', value: false }\n return { kind: 'invalid', reason: 'format' }\n },\n }\n}\n\n/**\n * Inclusive bounds for the millisecond timeout fields, mirroring the Host\n * Config schema (`z.number().min(1).max(MAX_TIMER_DELAY_MS)` in src/index.ts;\n * `MAX_TIMER_DELAY_MS` is dsh-timeout's 2^31-1 timer ceiling). The client\n * bundle cannot import the node-side package, so the bound is pinned here —\n * the host remains the final gate.\n */\nexport const MIN_TIMEOUT_MS = 1\nexport const MAX_TIMEOUT_MS = 2147483647\n\n/** The command guard's auto-approve levels, strictest first. */\nexport const COMMAND_GUARD_LEVEL_CHOICES = ['high', 'medium', 'low'] as const\n\n/** The level an unset `commandGuardLevel` reads as on the Host. */\nexport const COMMAND_GUARD_DEFAULT_LEVEL_CHOICE = 'medium'\n\n/** The fields this page edits inside the `llm-commandcode` namespace. */\nconst SECTION_FIELDS: FieldSpec[] = [\n textField('apiBase'),\n numberField('requestTimeoutMs', { min: MIN_TIMEOUT_MS, max: MAX_TIMEOUT_MS }),\n numberField('streamIdleTimeoutMs', { min: MIN_TIMEOUT_MS, max: MAX_TIMEOUT_MS }),\n // A COUNT of retries, not a millisecond wait: it shares the Host schema's\n // 0..50 bounds (`MAX_TRANSPORT_MAX_RETRIES` in src/transport-retry.ts, applied\n // to `transportMaxRetries` in src/index.ts) rather than the timer ceiling\n // above, so a draft can never be saved in a shape the Host rejects. The Host\n // stays the final gate, and the client bundle cannot import that node-side\n // module — `tests/transport-retry.test.ts` pins the schema's bound against\n // the constant so this mirrored literal cannot drift unnoticed.\n numberField('transportMaxRetries', { min: 0, max: 50 }),\n booleanField('filterModelsByPlan'),\n booleanField('webSearch'),\n booleanField('showSidebarQuota'),\n booleanField('commandGuard'),\n // Mirrors COMMAND_GUARD_LEVELS in the Host's `src/command-guard.ts`; this\n // bundle cannot import that node-side module, and the Host schema stays the\n // final gate.\n choiceField('commandGuardLevel', COMMAND_GUARD_LEVEL_CHOICES),\n booleanField('zdr'),\n]\n\n/** Whether two model-id lists are equal as sets (order-insensitive). */\nfunction sameModels(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false\n const set = new Set(a)\n return b.every((id) => set.has(id))\n}\n\n/** One stored routing rule, normalized. */\ninterface StoredRule {\n models: string[]\n account: string\n}\n\n/**\n * Fold routing rules into one model list per account with the runtime's\n * first-match-wins order (`matchModelRule()` in src/accounts.ts): a model\n * claimed by an earlier rule is ignored by every later one. Account order is\n * first appearance, which keeps a rewrite's rule order stable.\n */\nexport function accountModelMap(rules: readonly StoredRule[]): Map<string, string[]> {\n const claimed = new Set<string>()\n const map = new Map<string, string[]>()\n for (const rule of rules) {\n const list = map.get(rule.account) ?? []\n for (const model of rule.models) {\n if (claimed.has(model)) continue\n claimed.add(model)\n list.push(model)\n }\n map.set(rule.account, list)\n }\n return map\n}\n\n/** Serialize a per-account model map back into `modelAccountRules`. */\nfunction rulesFromMap(map: ReadonlyMap<string, readonly string[]>): StoredRule[] {\n const out: StoredRule[] = []\n for (const [account, models] of map) {\n if (models.length > 0) out.push({ models: [...models], account })\n }\n return out\n}\n\n/**\n * Controller bridging the `llm-commandcode` scope and the credentials domain\n * onto the page.\n *\n * Two write paths with different contracts:\n * - The staged form (connection, behavior and model-visibility fields, plus\n * the Models-page card's default key draft) lands on `save()`.\n * - Account management (create, rename, remove, key replacement, pinning and\n * per-account models) commits IMMEDIATELY and serially. A new account had to\n * be saved before browser sign-in could target it (the Host refuses a login\n * for a reference the stored `accounts` list does not name), which turned\n * \"add an account\" into edit → save → sign in; committing each operation\n * removes that dance and keeps unrelated staged edits out of it.\n */\nexport class CommandCodeSettingsController {\n private readonly scope: SettingsScope<Record<string, unknown>>\n private readonly api: SettingsPageApi\n private readonly specs = new Map(SECTION_FIELDS.map((spec) => [spec.field, spec]))\n private readonly staged = new Map<string, Staged>()\n private readonly listeners = new Set<() => void>()\n private readonly disposers: Array<() => void> = []\n private disposed = false\n /** The credential reference the default account resolves. */\n private credentialRef = DEFAULT_API_KEY_REF\n /** Host-reported configured/writable state per credential reference. */\n private readonly credentialStates = new Map<string, { configured: boolean; writable: boolean }>()\n /** Staged visible-model allowlist (undefined = no draft). */\n private visibleModelsDraft: string[] | undefined = undefined\n /** The catalog the model editors offer (Host-side). */\n private catalogModels: CatalogModelOption[] = []\n private catalogFailed = false\n private saving = false\n private failed = false\n private savedCount = 0\n /** Tail of the serial account-operation queue. */\n private accountQueue: Promise<unknown> = Promise.resolve()\n private accountPending = 0\n private accountFailed: AccountOperation | undefined = undefined\n\n /**\n * @param scope - bound scope for the `llm-commandcode` namespace.\n * @param api - credentials wire face.\n */\n constructor(\n scope: SettingsScope<Record<string, unknown>>,\n api: SettingsPageApi,\n ) {\n this.scope = scope\n this.api = api\n this.disposers.push(scope.subscribe(() => {\n this.recomputeCredentialRef()\n void this.describeAll()\n this.publish()\n }))\n this.recomputeCredentialRef()\n void this.describeAll()\n this.refreshCatalog()\n }\n\n /** Release every subscription held on external sources. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n for (const dispose of this.disposers) dispose()\n this.disposers.length = 0\n this.listeners.clear()\n }\n\n /**\n * The credential reference the section names, or the provider default. A\n * user who renamed `apiKeyEnv` in the profile Config gets a page that\n * addresses the renamed ref instead of silently writing the default —\n * mirroring the Models page's `refFor()`.\n */\n private recomputeCredentialRef(): void {\n const snapshot = this.scope.getSnapshot()\n const named = typeof snapshot.value?.apiKeyEnv === 'string' && snapshot.value.apiKeyEnv.length > 0\n ? snapshot.value.apiKeyEnv\n : DEFAULT_API_KEY_REF\n if (named === this.credentialRef) return\n this.credentialStates.delete(this.credentialRef)\n this.credentialRef = named\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Build the current page state face. */\n state(): SettingsPageState {\n const snapshot = this.scope.getSnapshot()\n const plan = this.plan()\n const credential = this.credentialStates.get(this.credentialRef)\n const accounts = this.effectiveAccounts()\n const active = this.sectionValue('activeAccount')\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n apiKeyConfigured: credential?.configured ?? false,\n anyAccountConfigured: (credential?.configured ?? false) || accounts.some((account) => account.configured),\n apiKeyWritable: credential?.writable ?? true,\n apiKey: {\n text: this.staged.get('apiKey')?.text ?? '',\n clear: false,\n overridden: false,\n invalid: false,\n invalidReason: undefined,\n },\n apiBase: this.field('apiBase'),\n requestTimeoutMs: this.field('requestTimeoutMs'),\n streamIdleTimeoutMs: this.field('streamIdleTimeoutMs'),\n transportMaxRetries: this.field('transportMaxRetries'),\n filterModelsByPlan: this.field('filterModelsByPlan'),\n webSearch: this.field('webSearch'),\n showSidebarQuota: this.field('showSidebarQuota'),\n commandGuard: this.field('commandGuard'),\n commandGuardLevel: this.field('commandGuardLevel'),\n zdr: this.field('zdr'),\n sidebarQuota: this.sectionValue('showSidebarQuota') === true,\n activeAccount: typeof active === 'string' ? active : '',\n accounts,\n accountModels: Object.fromEntries(accountModelMap(this.storedRules())),\n accountBusy: this.accountPending > 0,\n accountFailed: this.accountFailed,\n visibleModels: this.effectiveVisibleModels(),\n catalogModels: this.catalogModels,\n catalogFailed: this.catalogFailed,\n dirty: plan.length > 0 || this.visibleModelsDirty(),\n invalid: plan.some((item) => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n savedCount: this.savedCount,\n }\n }\n\n // -----------------------------------------------------------------------\n // Staged form\n // -----------------------------------------------------------------------\n\n /** Stage one field's draft text. */\n edit(field: string, text: string): void {\n if (field !== 'apiKey') this.spec(field)\n this.staged.set(field, { text, clear: false })\n this.failed = false\n this.publish()\n }\n\n /** Reset one section field to its inherited (composition) value. */\n resetField(field: string): void {\n if (field === 'apiKey') {\n this.staged.delete('apiKey')\n this.failed = false\n this.publish()\n return\n }\n const spec = this.spec(field)\n this.staged.set(field, { text: spec.format(this.baseValue(field)), clear: true })\n this.failed = false\n this.publish()\n }\n\n /** Discard every staged edit. */\n discard(): void {\n if (this.staged.size === 0 && this.visibleModelsDraft === undefined && !this.failed) return\n this.staged.clear()\n this.visibleModelsDraft = undefined\n this.failed = false\n this.publish()\n }\n\n /**\n * Re-read the Host's credential facts without any staged edit. The browser\n * login stores a key Host-side behind the page's back; the plugin entry\n * calls this when a login lands so the configured/writable badges follow.\n */\n refreshCredentials(): void {\n void this.describeAll()\n }\n\n /** Write every staged edit, then re-read the Host's accepted state. */\n async save(): Promise<void> {\n const plan = this.plan()\n const visibleRuns = this.visibleModelsPlan()\n if ((plan.length === 0 && visibleRuns.length === 0) || this.saving) return\n const runs: Array<() => Promise<boolean>> = []\n for (const item of plan) {\n if (item.run === undefined) return\n runs.push(item.run)\n }\n this.saving = true\n this.failed = false\n this.publish()\n let landed = true\n // Stop at the first failure: later writes would persist a partial state\n // the staged drafts no longer describe. A throwing write counts as a\n // failure too (the scope seam may reject).\n for (const run of [...runs, ...visibleRuns]) {\n let ok = false\n try {\n ok = await run()\n } catch {\n ok = false\n }\n if (!ok) {\n landed = false\n break\n }\n }\n this.saving = false\n this.failed = !landed\n if (landed) {\n this.savedCount += 1\n this.staged.clear()\n this.visibleModelsDraft = undefined\n } else {\n this.reconcileStaging()\n }\n this.publish()\n }\n\n /** Stage the visible-model allowlist (multi-select). */\n editVisibleModels(models: string[]): void {\n this.visibleModelsDraft = [...models]\n this.failed = false\n this.publish()\n }\n\n /** Stage \"show all models\" (clears the allowlist). */\n clearVisibleModels(): void {\n this.visibleModelsDraft = []\n this.failed = false\n this.publish()\n }\n\n // -----------------------------------------------------------------------\n // Immediate account management\n // -----------------------------------------------------------------------\n\n /**\n * Create one extra account now and return its credential reference, or\n * undefined when the account could not be stored. With `key` the key lands\n * first, so a stored row never names a reference whose key write failed;\n * without it the row is stored keyless so browser sign-in can target it.\n */\n async createAccount(input: { label: string; key?: string }): Promise<string | undefined> {\n let created: string | undefined\n await this.runAccountOp('create', async () => {\n const ref = this.nextAccountRef()\n const key = input.key?.trim() ?? ''\n if (key !== '' && !(await this.writeKeyTo(ref, key))) return false\n const label = input.label.trim() === '' ? ref : input.label.trim()\n let ok = false\n try {\n ok = await this.writeAccountList([...this.rawStoredAccounts(), { label, apiKeyEnv: ref }])\n } catch {\n ok = false\n }\n if (!ok) {\n if (key !== '') await this.unsetKey(ref)\n return false\n }\n created = ref\n return true\n })\n return created\n }\n\n /** Rename one stored extra account now. */\n renameAccount(ref: string, label: string): Promise<boolean> {\n const next = label.trim()\n return this.runAccountOp('rename', async () => {\n if (next === '') return false\n const list = this.rawStoredAccounts().map((entry) => entry.apiKeyEnv === ref ? { ...entry, label: next } : { ...entry })\n return this.writeAccountList(list)\n })\n }\n\n /**\n * Remove one stored extra account now: its stored key, its dedicated\n * models and a pin naming it go with it, so nothing orphaned remains.\n */\n removeAccount(ref: string): Promise<boolean> {\n return this.runAccountOp('remove', async () => {\n if (this.credentialStates.get(ref)?.configured === true && !(await this.unsetKey(ref))) return false\n const list = this.rawStoredAccounts().filter((entry) => entry.apiKeyEnv !== ref).map((entry) => ({ ...entry }))\n if (!(await this.writeAccountList(list))) return false\n const map = accountModelMap(this.storedRules())\n if (map.has(ref)) {\n map.delete(ref)\n if (!(await this.writeRules(rulesFromMap(map)))) return false\n }\n if (this.sectionValue('activeAccount') === ref) return this.clear('activeAccount')\n return true\n })\n }\n\n /** Store a replacement key now; `target` is `'default'` or an extra account's reference. */\n setAccountKey(target: string, key: string): Promise<boolean> {\n const value = key.trim()\n return this.runAccountOp('key', async () => {\n if (value === '') return false\n return this.writeKeyTo(this.refFor(target), value)\n })\n }\n\n /** Remove a stored key now; `target` is `'default'` or an extra account's reference. */\n clearAccountKey(target: string): Promise<boolean> {\n return this.runAccountOp('key', () => this.unsetKey(this.refFor(target)))\n }\n\n /** Pin the serving account now (`''` returns to automatic rotation). */\n setActiveAccount(id: string): Promise<boolean> {\n return this.runAccountOp('active', () => id === ''\n ? this.clear('activeAccount')\n : this.store('activeAccount', id))\n }\n\n /**\n * Replace one account's dedicated models now. A model belongs to one\n * account at a time, so each selected model is moved out of any other\n * account's list — the stored rules then carry no shadowed entries.\n */\n setAccountModels(target: string, models: readonly string[]): Promise<boolean> {\n return this.runAccountOp('models', async () => {\n const chosen = [...new Set(models.filter((id) => id !== ''))]\n const taken = new Set(chosen)\n const map = accountModelMap(this.storedRules())\n for (const [account, list] of map) {\n if (account !== target) map.set(account, list.filter((id) => !taken.has(id)))\n }\n map.set(target, chosen)\n return this.writeRules(rulesFromMap(map))\n })\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n /** Run one account operation after every earlier one, tracking busy/failure. */\n private runAccountOp(op: AccountOperation, run: () => Promise<boolean>): Promise<boolean> {\n this.accountPending += 1\n this.accountFailed = undefined\n this.publish()\n const result = this.accountQueue.then(async () => {\n if (!this.scope.getSnapshot().writable) return false\n try {\n return await run()\n } catch {\n return false\n }\n })\n this.accountQueue = result\n return result.then((ok) => {\n this.accountPending -= 1\n if (!ok) this.accountFailed = op\n this.publish()\n return ok\n })\n }\n\n private refFor(target: string): string {\n return target === 'default' ? this.credentialRef : target\n }\n\n /**\n * The first free `<credentialRef>_<n>` reference. Derived from the default\n * reference's name, so a renamed `apiKeyEnv` yields `MY_KEY_2`-style refs\n * consistent with the default slot.\n */\n private nextAccountRef(): string {\n const used = new Set([this.credentialRef, ...this.storedExtras().map((extra) => extra.ref)])\n let n = 2\n while (used.has(`${this.credentialRef}_${n}`)) n += 1\n return `${this.credentialRef}_${n}`\n }\n\n private spec(field: string): FieldSpec {\n const spec = this.specs.get(field)\n if (spec === undefined) throw new Error(`commandcode settings page has no field ${field}`)\n return spec\n }\n\n /** One field's rendered state: draft text, whether it is user-overridden, invalid. */\n private field(field: string): StagedField {\n const spec = this.spec(field)\n const staged = this.staged.get(field)\n if (staged === undefined) {\n return {\n text: spec.format(this.sectionValue(field)),\n clear: false,\n overridden: this.stored(field),\n invalid: false,\n invalidReason: undefined,\n }\n }\n const parsed = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text)\n return {\n text: staged.text,\n clear: staged.clear,\n overridden: parsed.kind === 'set',\n invalid: parsed.kind === 'invalid',\n invalidReason: parsed.kind === 'invalid' ? parsed.reason : undefined,\n }\n }\n\n private sectionValue(field: string): unknown {\n return this.scope.getSnapshot().value?.[field]\n }\n\n private baseValue(field: string): unknown {\n const base = this.scope.getSnapshot().base\n return typeof base === 'object' && base !== null && !Array.isArray(base)\n ? (base as Record<string, unknown>)[field]\n : undefined\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n const user = this.scope.getSnapshot().user\n return typeof user === 'object' && user !== null && !Array.isArray(user)\n ? (user as Record<string, unknown>)\n : undefined\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer()\n return user !== undefined && Object.prototype.hasOwnProperty.call(user, field)\n }\n\n /**\n * The writes a save would perform, in staged order. A field whose draft is\n * not a value its spec accepts carries no write (the save refuses).\n */\n private plan(): Array<{ field: string; run: (() => Promise<boolean>) | undefined }> {\n const plan: Array<{ field: string; run: (() => Promise<boolean>) | undefined }> = []\n for (const [field, staged] of this.staged) {\n if (field === 'apiKey') {\n const value = staged.text.trim()\n if (value !== '') plan.push({ field, run: () => this.writeKeyTo(this.credentialRef, value) })\n continue\n }\n const spec = this.spec(field)\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) })\n continue\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue\n const parsed = spec.parse(staged.text)\n if (parsed.kind === 'invalid') plan.push({ field, run: undefined })\n else if (parsed.kind === 'clear') plan.push({ field, run: () => this.clear(field) })\n else plan.push({ field, run: () => this.store(field, parsed.value) })\n }\n return plan\n }\n\n /** Drop staged drafts a partially landed save already stored. */\n private reconcileStaging(): void {\n for (const [field, staged] of [...this.staged]) {\n if (field === 'apiKey' || staged.clear) continue\n if (staged.text === this.spec(field).format(this.sectionValue(field))) this.staged.delete(field)\n }\n if (this.visibleModelsDraft !== undefined && sameModels(this.visibleModelsDraft, this.storedVisibleModels())) {\n this.visibleModelsDraft = undefined\n }\n }\n\n private async clear(field: string): Promise<boolean> {\n if (!this.stored(field)) return true\n await this.scope.unset(field)\n return !this.stored(field)\n }\n\n private async store(field: string, value: string | number | boolean): Promise<boolean> {\n await this.scope.set(field, value)\n return this.userLayer()?.[field] === value\n }\n\n /** Write one account's key, then re-read the Host's credential states. */\n private async writeKeyTo(ref: string, value: string): Promise<boolean> {\n try {\n const response = await this.api.credentials.set(ref, value)\n if (!response.ok) return false\n } catch {\n return false\n }\n await this.describeAll([ref])\n return this.credentialStates.get(ref)?.configured ?? false\n }\n\n /** Unset one stored credential, then re-read the Host's credential states. */\n private async unsetKey(ref: string): Promise<boolean> {\n try {\n const response = await this.api.credentials.unset(ref)\n if (!response.ok) return false\n } catch {\n return false\n }\n await this.describeAll([ref])\n return this.credentialStates.get(ref)?.configured !== true\n }\n\n /**\n * Ask the credentials domain about every reference this page writes, plus\n * `extra` — a key written for an account whose row is not stored yet.\n */\n private async describeAll(extra: readonly string[] = []): Promise<void> {\n const refs = [...new Set([this.credentialRef, ...this.storedExtras().map((account) => account.ref), ...extra])]\n let response: Awaited<ReturnType<SettingsPageApi['credentials']['describe']>>\n try {\n response = await this.api.credentials.describe(refs)\n } catch {\n return\n }\n if (!response.ok) return\n let changed = false\n for (const ref of refs) {\n const view = response.value?.[ref]\n const next = {\n configured: view?.configured ?? false,\n writable: view?.writable ?? true,\n }\n const prev = this.credentialStates.get(ref)\n if (prev === undefined || prev.configured !== next.configured || prev.writable !== next.writable) {\n this.credentialStates.set(ref, next)\n changed = true\n }\n }\n if (changed) this.publish()\n }\n\n /**\n * Fetch the model catalog for the settings page's model editors through\n * the Host Remote. Runs once at construction; call again (e.g. from the\n * client entry once the Remote mount lands) to (re)try — a later success\n * clears a prior failure flag so the editors recover without a page reload.\n */\n refreshCatalog(): void {\n const models = this.api.models\n if (models === undefined) {\n this.catalogFailed = true\n this.publish()\n return\n }\n void models().then((response) => {\n if (response.ok && Array.isArray(response.value?.models)) {\n // Defensive per-entry shaping: the Remote result is untrusted at the\n // boundary, and an older Host predates the tier field.\n const shaped: CatalogModelOption[] = []\n for (const model of response.value.models) {\n if (typeof model !== 'object' || model === null) continue\n const entry = model as unknown as Record<string, unknown>\n if (typeof entry.id !== 'string' || typeof entry.name !== 'string') continue\n shaped.push({\n id: entry.id,\n name: entry.name,\n ...(typeof entry.tier === 'string' ? { tier: entry.tier } : {}),\n })\n }\n this.catalogModels = shaped\n this.catalogFailed = false\n } else {\n this.catalogFailed = true\n }\n }, () => {\n this.catalogFailed = true\n }).then(() => this.publish())\n }\n\n // -----------------------------------------------------------------------\n // Stored accounts and rules\n // -----------------------------------------------------------------------\n\n /** The raw `accounts` array of the stored section, verbatim. */\n private rawStoredAccounts(): Array<Record<string, unknown>> {\n const raw = this.scope.getSnapshot().value?.accounts\n if (!Array.isArray(raw)) return []\n return raw.filter(\n (entry): entry is Record<string, unknown> =>\n typeof entry === 'object' && entry !== null && !Array.isArray(entry),\n )\n }\n\n /**\n * The stored extra accounts this page can address: the rows carrying a\n * credential reference. Entries it cannot name (a composition entry with a\n * literal `apiKey`, or an unknown shape) are never dropped — every list\n * write starts from {@link rawStoredAccounts} and copies them verbatim,\n * because the settings layer replaces the whole array.\n */\n private storedExtras(): Array<{ label: string; ref: string }> {\n const out: Array<{ label: string; ref: string }> = []\n const seen = new Set<string>()\n for (const record of this.rawStoredAccounts()) {\n const ref = record.apiKeyEnv\n if (typeof ref !== 'string' || ref === '' || seen.has(ref)) continue\n seen.add(ref)\n const label = record.label\n out.push({ label: typeof label === 'string' && label !== '' ? label : ref, ref })\n }\n return out\n }\n\n private effectiveAccounts(): AccountItemState[] {\n return this.storedExtras().map((extra) => ({\n id: extra.ref,\n ref: extra.ref,\n label: extra.label,\n configured: this.credentialStates.get(extra.ref)?.configured ?? false,\n writable: this.credentialStates.get(extra.ref)?.writable ?? true,\n }))\n }\n\n /** Persist a full accounts list and verify the Host stored it. */\n private async writeAccountList(list: Array<Record<string, unknown>>): Promise<boolean> {\n await this.scope.set('accounts', list)\n const after = this.rawStoredAccounts()\n return after.length === list.length\n && list.every((item, index) => after[index]?.apiKeyEnv === item.apiKeyEnv && after[index]?.label === item.label)\n }\n\n /** The stored routing rules from the settings section (`modelAccountRules`). */\n private storedRules(): StoredRule[] {\n const raw = this.scope.getSnapshot().value?.modelAccountRules\n if (!Array.isArray(raw)) return []\n const out: StoredRule[] = []\n for (const entry of raw) {\n if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) continue\n const record = entry as Record<string, unknown>\n const models = Array.isArray(record.models)\n ? record.models.filter((m): m is string => typeof m === 'string' && m !== '')\n : []\n if (models.length === 0) continue\n out.push({\n models,\n account: typeof record.account === 'string' && record.account !== '' ? record.account : 'default',\n })\n }\n return out\n }\n\n /** Persist routing rules and verify the Host stored them. */\n private async writeRules(list: StoredRule[]): Promise<boolean> {\n await this.scope.set('modelAccountRules', list)\n const after = this.storedRules()\n return after.length === list.length\n && list.every((item, index) =>\n after[index] !== undefined\n && sameModels(after[index].models, item.models)\n && after[index].account === item.account)\n }\n\n /** The stored visible-model allowlist (`visibleModels`); empty = show all. */\n private storedVisibleModels(): string[] {\n const raw = this.scope.getSnapshot().value?.visibleModels\n if (!Array.isArray(raw)) return []\n return raw.filter((m): m is string => typeof m === 'string' && m !== '')\n }\n\n private effectiveVisibleModels(): string[] {\n return this.visibleModelsDraft ?? this.storedVisibleModels()\n }\n\n private visibleModelsDirty(): boolean {\n return this.visibleModelsDraft !== undefined\n && !sameModels(this.visibleModelsDraft, this.storedVisibleModels())\n }\n\n private visibleModelsPlan(): Array<() => Promise<boolean>> {\n if (!this.visibleModelsDirty()) return []\n return [async () => {\n const list = this.visibleModelsDraft ?? []\n await this.scope.set('visibleModels', list)\n return sameModels(this.storedVisibleModels(), list)\n }]\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * Browser controller for the settings page's account-usage card.\n *\n * The card renders the same account/usage/credit facts the `/commandcode`\n * command prints, fetched Host-side through the `commandcode/report` Remote\n * (the browser never holds the API key). This controller owns the fetch\n * lifecycle — idle/loading/ready/error, one in-flight request at a time,\n * stale-response dropping — and the display formatting, so the React\n * component stays a thin renderer and node tests can drive everything.\n *\n * Deliberately JSX-free, mirroring `./settings.ts`.\n *\n * @module dsh-commandcode-provider/client/usage\n */\n\nimport type { CommandCodeAccountsReport, CommandCodeCatalog, CommandCodePriceTable } from '../usage-wire.ts'\nimport type { CommandCodeLoginStatus } from '../login-wire.ts'\nimport type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'\n\n/**\n * Merge the plugin's Remote endpoints into the harness's typed client Remote\n * surface (the same declaration pattern the harness's generated\n * typert.remote-client files use), so `ctx.remote.commandcode.*()` is typed\n * once each contribution is mounted. The `commandcode` namespace member is\n * declared exactly once (interface merging forbids duplicate members), so\n * this one declaration carries the usage report, the model catalog, the price\n * table, AND the login endpoints — the endpoint-level declarations live beside\n * their controllers.\n */\ndeclare module '@deepseek-ai/dsh-typert-protocol' {\n interface TypertRemoteMap {\n 'commandcode/report': () => Promise<RemoteResult<CommandCodeAccountsReport>>\n 'commandcode/models': () => Promise<RemoteResult<CommandCodeCatalog>>\n 'commandcode/prices': () => Promise<RemoteResult<CommandCodePriceTable>>\n }\n interface TypertRemoteNamespaceMap {\n commandcode: {\n report: () => Promise<RemoteResult<CommandCodeAccountsReport>>\n models: () => Promise<RemoteResult<CommandCodeCatalog>>\n /**\n * Optional because the Host half and this browser bundle can be a\n * cross-version pair: a Host older than the price table mounts no\n * `commandcode/prices` descriptor, so the member is genuinely absent at\n * runtime. The price controller reads a missing method as \"no table\"\n * (see `./prices.ts`) instead of throwing.\n */\n prices?: () => Promise<RemoteResult<CommandCodePriceTable>>\n loginBegin: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n loginStatus: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n loginCancel: () => Promise<RemoteResult<CommandCodeLoginStatus>>\n }\n }\n}\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface UsageRemote {\n report(): Promise<\n | { ok: true; value: CommandCodeAccountsReport }\n | { ok: false; error: { message: string } }\n >\n models(): Promise<\n | { ok: true; value: CommandCodeCatalog }\n | { ok: false; error: { message: string } }\n >\n /**\n * Optional for the same cross-version reason as the namespace member above:\n * an older Host serves no price table. `CommandCodePricesController` reads\n * the absence as a permanent \"no prices\" state.\n */\n prices?(): Promise<\n | { ok: true; value: CommandCodePriceTable }\n | { ok: false; error: { message: string } }\n >\n}\n\n/** The card's fetch lifecycle. */\nexport type UsageStatus =\n /** Never fetched (no API key configured yet, or not requested). */\n | 'idle'\n /** A fetch is in flight; `report` retains the last good data if any. */\n | 'loading'\n /** The last fetch succeeded. */\n | 'ready'\n /** The last fetch failed (no key, unreachable host, old plugin). */\n | 'error'\n\n/** The card's full state face. */\nexport interface UsagePageState {\n status: UsageStatus\n /** The last successfully fetched report (retained across refetches). */\n report: CommandCodeAccountsReport | undefined\n /** The last failure's message (error status). */\n error: string | undefined\n /** Millis timestamp of the last successful fetch. */\n fetchedAt: number | undefined\n}\n\nconst IDLE: UsagePageState = { status: 'idle', report: undefined, error: undefined, fetchedAt: undefined }\n\n/**\n * Controller bridging the `commandcode/report` Remote onto the card. Public\n * API mirrors {@link CommandCodeSettingsController}: `state()` projections,\n * `subscribe`, and one `refresh()` action.\n */\nexport class CommandCodeUsageController {\n private readonly remote: UsageRemote\n private readonly listeners = new Set<() => void>()\n private current: UsagePageState = IDLE\n private generation = 0\n private inFlight = false\n private disposed = false\n\n constructor(remote: UsageRemote) {\n this.remote = remote\n }\n\n /** Release every subscription. Idempotent; in-flight results are dropped. */\n dispose(): void {\n this.disposed = true\n this.generation += 1\n this.listeners.clear()\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current card state face. */\n state(): UsagePageState {\n return this.current\n }\n\n /**\n * Fetch (or refetch) the report. Concurrent refreshes collapse onto one\n * request; a superseded fetch's late result is dropped, never published.\n */\n async refresh(): Promise<void> {\n if (this.disposed || this.inFlight) return\n const generation = ++this.generation\n this.inFlight = true\n this.current = { ...this.current, status: 'loading', error: undefined }\n this.publish()\n try {\n const response = await this.remote.report()\n if (this.disposed || generation !== this.generation) return\n if (response.ok) {\n this.current = { status: 'ready', report: response.value, error: undefined, fetchedAt: Date.now() }\n } else {\n this.current = { ...this.current, status: 'error', error: response.error.message }\n }\n } catch (error: unknown) {\n if (this.disposed || generation !== this.generation) return\n this.current = {\n ...this.current,\n status: 'error',\n error: error instanceof Error ? error.message : String(error),\n }\n } finally {\n if (generation === this.generation) this.inFlight = false\n }\n this.publish()\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of this.listeners) listener()\n }\n}\n\n// ---------------------------------------------------------------------------\n// Display formatting (shared by the component, covered by node tests)\n// ---------------------------------------------------------------------------\n\n/** Format a dollar amount compactly (2 decimals). */\nexport function formatMoney(value: number): string {\n return `$${value.toFixed(2)}`\n}\n\n/** Format a dollar amount precisely (4 decimals) for small totals. */\nexport function formatMoneyExact(value: number): string {\n return `$${value.toFixed(4)}`\n}\n\n/** Format a large token count compactly (1.9M style). */\nexport function formatTokensCompact(value: number): string {\n if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`\n if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`\n if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`\n return String(value)\n}\n\n/**\n * Format a success-rate percentage (already in percent units, e.g. 99.96):\n * at most two decimals, trailing zeros trimmed — `100` stays `100`, not\n * `100.00`, and the raw upstream float `99.965552876334` becomes `99.97`.\n * The `%` suffix is appended by the caller (the card and the dashboard line\n * both compose it).\n */\nexport function formatSuccessRate(value: number): string {\n return String(Number(value.toFixed(2)))\n}\n\n/** One window's fill ratio in [0, 1]; 0 when uncapped. */\nexport function windowRatio(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.max(0, Math.min(1, used / cap))\n}\n\n/** Format a millis timestamp as a local short date-time; empty when unset. */\nexport function formatResetAt(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleString()\n}\n\n/** Host facts drive the usage card, including keys invisible to browser credentials. */\nexport function usageCardState(usage: UsagePageState) {\n const accounts = usage.report?.accounts ?? []\n return {\n loading: usage.status === 'loading',\n shouldRefresh: usage.status === 'idle',\n noKey: accounts.length > 0 && !accounts.some(account => account.configured),\n }\n}\n","/**\n * Browser controller for the model price table the composer's session-cost\n * figure depends on.\n *\n * The rates are vendored Host-side (`src/model-prices.ts`) and cross the\n * `commandcode/prices` Remote, so the browser never carries its own copy that\n * could drift from the snapshot, and a price update reaches an open page\n * without rebuilding the client bundle.\n *\n * Successful reads are cached until the Host namespace rebinds. Transient\n * failures retry three times with bounded backoff; manual refresh can retry\n * after that. Rebinding drops stale in-flight results and resets the budget.\n * Missing endpoints are permanent until the namespace changes.\n *\n * Deliberately JSX-free, mirroring `./usage.ts`.\n *\n * @module dsh-commandcode-provider/client/prices\n */\n\nimport type { CommandCodePriceTable } from '../usage-wire.ts'\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface PricesRemote {\n /**\n * Optional because the Host and the browser bundle can be a cross-version\n * pair: a Host half older than this feature serves no `commandcode/prices`\n * endpoint, and the controller must read that as \"no price table\" instead of\n * calling an undefined method.\n */\n prices?(): Promise<\n | { ok: true; value: CommandCodePriceTable }\n | { ok: false; error: { message: string; permanent?: boolean } }\n >\n}\n\n/** The price table's fetch lifecycle. */\nexport type PricesStatus =\n /** Never requested. */\n | 'idle'\n /** A fetch is in flight. */\n | 'loading'\n /** The table is loaded and cached for the page's lifetime. */\n | 'ready'\n /** The last fetch failed; `ensure()` may try again. */\n | 'error'\n\n/** The readout's price-table state face. */\nexport interface SessionCostPricesState {\n status: PricesStatus\n /** The cached table (only ever set once). */\n table: CommandCodePriceTable | undefined\n /** The last failure's message. */\n error: string | undefined\n}\n\nconst IDLE: SessionCostPricesState = { status: 'idle', table: undefined, error: undefined }\n\n/**\n * Timer seam for the bounded retry backoff, so a node test can drive the\n * schedule without waiting on it.\n */\nexport interface PriceRetryTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\nconst RETRY_TIMER: PriceRetryTimer = {\n set(callback, ms) { const handle = setTimeout(callback, ms); handle.unref?.(); return handle },\n clear(handle) { clearTimeout(handle as ReturnType<typeof setTimeout>) },\n}\n\n/**\n * Cache over the `commandcode/prices` Remote, with a bounded transient-retry\n * budget. Public API mirrors {@link CommandCodeUsageController}: `state()`,\n * `subscribe`, and `ensure()`; `reload()` additionally drops the cache and\n * restarts the budget when the Host namespace rebinds.\n *\n * Not a one-shot: the last fetch is cached until `reload()`, a transient\n * failure is retried three times at 1/2/4 s (the delays are bounded, not a\n * poll), and a MANUAL `ensure()` still fetches after that budget is spent. A\n * PERMANENT failure — the Host serving no such endpoint — is terminal for the\n * binding and is only cleared by `reload()`.\n */\nexport class CommandCodePricesController {\n private readonly remote: PricesRemote\n private readonly listeners = new Set<() => void>()\n private current: SessionCostPricesState = IDLE\n private generation = 0\n private inFlight = false\n private disposed = false\n\n private retryHandle: unknown\n private attempts = 0\n private permanent = false\n private readonly timer: PriceRetryTimer\n\n constructor(remote: PricesRemote, timer: PriceRetryTimer = RETRY_TIMER) {\n this.timer = timer\n this.remote = remote\n }\n\n /** Release every subscription. Idempotent; in-flight results are dropped. */\n dispose(): void {\n this.disposed = true\n this.clearRetry()\n this.listeners.clear()\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** The current state face. */\n state(): SessionCostPricesState {\n return this.current\n }\n\n /**\n * Fetch the table unless it is already loaded, permanent, or in flight — and\n * unless a bounded retry already owns the next attempt.\n *\n * The only callers are the client entry: `reload()` when the Remote namespace\n * lands or rebinds, and a manual refresh. Nothing in the composer calls it, so\n * a mounted readout does not trigger a fetch of its own — it renders whatever\n * the table's state currently is.\n */\n ensure(): void {\n if (this.disposed || this.permanent || this.inFlight || this.current.status === 'ready') return\n this.clearRetry()\n const call = this.remote.prices\n // An older Host half serves no price endpoint. That is a permanent\n // condition for this page, so it lands in the error state (the readout\n // stays hidden) rather than retrying on every mount.\n if (typeof call !== 'function') {\n this.permanent = true\n this.publish({ status: 'error', table: undefined, error: 'the Host serves no commandcode/prices endpoint' })\n return\n }\n const generation = this.generation\n this.inFlight = true\n this.attempts += 1\n this.publish({ status: 'loading', table: this.current.table, error: undefined })\n let request: ReturnType<NonNullable<PricesRemote['prices']>>\n try { request = call.call(this.remote) } catch (error) { request = Promise.reject(error) }\n void request.then((result) => {\n if (this.disposed || generation !== this.generation) return\n this.inFlight = false\n if (result.ok) {\n this.publish({ status: 'ready', table: result.value, error: undefined })\n return\n }\n this.permanent = result.error.permanent === true\n this.publish({ status: 'error', table: undefined, error: result.error.message })\n this.scheduleRetry()\n }, (error: unknown) => {\n if (this.disposed || generation !== this.generation) return\n this.inFlight = false\n this.publish({\n status: 'error',\n table: undefined,\n error: error instanceof Error ? error.message : String(error),\n })\n this.scheduleRetry()\n })\n }\n\n /** Rebinding a Host invalidates cached prices and restarts the bounded retry budget. */\n reload(): void {\n if (this.disposed) return\n this.generation += 1\n this.inFlight = false\n this.clearRetry()\n this.permanent = false\n this.attempts = 0\n this.current = IDLE\n this.ensure()\n }\n\n private clearRetry(): void {\n if (this.retryHandle !== undefined) this.timer.clear(this.retryHandle)\n this.retryHandle = undefined\n }\n\n private scheduleRetry(): void {\n if (this.disposed || this.permanent || this.attempts >= 4) return\n this.retryHandle = this.timer.set(() => { this.retryHandle = undefined; this.ensure() }, 1000 * 2 ** (this.attempts - 1))\n }\n\n private publish(next: SessionCostPricesState): void {\n this.current = next\n for (const listener of this.listeners) listener()\n }\n}\n","/**\n * Browser controller for the settings page's login panel.\n *\n * The panel drives the Host-half browser login (the official\n * `command-code login` loopback dance) through the Typert Gateway: `begin`\n * asks the Host to bind the callback server and returns the Studio URL, the\n * controller polls `loginStatus` once a second while the attempt is live, and\n * `cancel` tears it down. The key itself never crosses to the browser — the\n * Host validates and stores it through the credentials seam.\n *\n * Transport-level failures (no mounted Remote, an older Host without the\n * login endpoints) land in the dedicated `unavailable` phase so the page can\n * point back at manual paste. Deliberately JSX-free, mirroring\n * `./settings.ts` and `./usage.ts`.\n *\n * @module dsh-commandcode-provider/client/login\n */\n\nimport type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'\nimport type { CommandCodeLoginFailureReason, CommandCodeLoginStatus } from '../login-wire.ts'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\n\n/** The endpoint-level Remote surface this controller calls. */\ndeclare module '@deepseek-ai/dsh-typert-protocol' {\n interface TypertRemoteMap {\n 'commandcode/loginBegin': (targetRef?: string) => Promise<RemoteResult<CommandCodeLoginStatus>>\n 'commandcode/loginStatus': () => Promise<RemoteResult<CommandCodeLoginStatus>>\n 'commandcode/loginCancel': () => Promise<RemoteResult<CommandCodeLoginStatus>>\n }\n}\n\n/** The narrow slice of the mounted Remote this controller calls. */\nexport interface LoginRemote {\n loginBegin(targetRef?: string): Promise<LoginCallResult>\n loginStatus(): Promise<LoginCallResult>\n loginCancel(): Promise<LoginCallResult>\n}\n\n/** One Remote call's outcome as the controller sees it. */\nexport type LoginCallResult =\n | { ok: true; value: CommandCodeLoginStatus }\n | { ok: false; error: { message: string } }\n\n/** The panel's full state face. */\nexport interface LoginPageState {\n /**\n * `idle` — nothing started; `starting` — begin() in flight; `waiting` —\n * the Studio URL is live and polling; `success`/`failed` — terminal;\n * `unavailable` — the Remote itself could not be reached (old Host, mount\n * failure), manual paste is the way.\n */\n phase: 'idle' | 'starting' | 'waiting' | 'success' | 'failed' | 'unavailable'\n /** The saved extra account receiving this attempt, or undefined for default. */\n targetRef?: string\n /** The Studio authorization URL while `waiting`. */\n authUrl: string | undefined\n /** The account display name on `success`. */\n userName: string | undefined\n /** The key's Studio label on `success`. */\n keyName: string | undefined\n /** The stable failure reason when `failed`. */\n reason: CommandCodeLoginFailureReason | undefined\n /** Secondary failure detail when `failed`/`unavailable`. */\n message: string | undefined\n}\n\n/** Keep one account's login status out of every other account's row. */\nexport function loginStateForTarget(\n state: LoginPageState,\n targetRef: string | undefined,\n): { visible: LoginPageState; busyElsewhere: boolean } {\n if (state.targetRef === targetRef) return { visible: state, busyElsewhere: false }\n return {\n visible: { ...state, phase: 'idle', authUrl: undefined },\n busyElsewhere: state.phase === 'starting' || state.phase === 'waiting',\n }\n}\n\n/** How often a live attempt is polled. */\nconst POLL_INTERVAL_MS = 1_000\n\n/**\n * The login panel's fetch/poll lifecycle. One poll loop at a time; a fresh\n * `begin()` supersedes any previous loop via a generation token.\n */\nexport class CommandCodeLoginController {\n private readonly remote: () => LoginRemote | undefined\n private readonly listeners = new Set<() => void>()\n private readonly pollMs: number\n /** Monotonic token; only the latest loop may publish polling results. */\n private generation = 0\n private disposed = false\n\n private phase: LoginPageState['phase'] = 'idle'\n private targetRef: string | undefined\n private authUrl: string | undefined\n private userName: string | undefined\n private keyName: string | undefined\n private reason: CommandCodeLoginFailureReason | undefined\n private message: string | undefined\n\n constructor(remote: () => LoginRemote | undefined, pollMs = POLL_INTERVAL_MS) {\n this.remote = remote\n this.pollMs = pollMs\n }\n\n /** Subscribe to state projections. @returns the disposer. */\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n }\n\n /** Build the current panel state face. */\n state(): LoginPageState {\n return {\n phase: this.phase,\n ...(this.targetRef === undefined ? {} : { targetRef: this.targetRef }),\n authUrl: this.authUrl,\n userName: this.userName,\n keyName: this.keyName,\n reason: this.reason,\n message: this.message,\n }\n }\n\n /** Start (or rejoin) a login attempt and begin polling its status. */\n async begin(targetRef?: string): Promise<void> {\n if (this.disposed || this.phase === 'starting' || this.phase === 'waiting') return\n const generation = ++this.generation\n this.targetRef = targetRef\n this.set({ phase: 'starting', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: undefined })\n const remote = this.remote()\n if (remote === undefined) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: 'login remote is not mounted' })\n return\n }\n let result: LoginCallResult\n try {\n result = await remote.loginBegin(targetRef)\n } catch (error: unknown) {\n // A transport throw (gateway hiccup) reads the same as a rejected call.\n result = { ok: false, error: { message: error instanceof Error ? error.message : String(error) } }\n }\n if (this.superseded(generation)) return\n if (!result.ok) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: result.error.message })\n return\n }\n this.apply(result.value)\n if (this.currentPhase === 'waiting') void this.poll(generation)\n }\n\n /** Cancel a waiting attempt. */\n async cancel(): Promise<void> {\n if (this.disposed || (this.phase !== 'starting' && this.phase !== 'waiting')) return\n const generation = ++this.generation\n const remote = this.remote()\n if (remote === undefined) return\n let result: LoginCallResult\n try {\n result = await remote.loginCancel()\n } catch {\n // The Host may be gone; reflect the local cancel regardless.\n this.set({ phase: 'failed', authUrl: undefined, userName: undefined, keyName: undefined, reason: 'cancelled', message: undefined })\n return\n }\n if (this.superseded(generation)) return\n if (result.ok) this.apply(result.value)\n else this.set({ phase: 'failed', authUrl: undefined, userName: undefined, keyName: undefined, reason: 'cancelled', message: undefined })\n }\n\n /** Stop polling and release listeners. Idempotent. */\n dispose(): void {\n if (this.disposed) return\n this.disposed = true\n this.generation += 1\n this.listeners.clear()\n }\n\n // -----------------------------------------------------------------------\n // Internals\n // -----------------------------------------------------------------------\n\n /** Poll until the attempt leaves `waiting` or a newer loop supersedes us. */\n private async poll(generation: number): Promise<void> {\n // A getter read (not the field) so control-flow narrowing across `await`\n // cannot claim the phase is frozen.\n while (!this.disposed && !this.superseded(generation) && this.currentPhase === 'waiting') {\n await sleep(this.pollMs)\n if (this.disposed || this.superseded(generation) || this.currentPhase !== 'waiting') return\n const remote = this.remote()\n if (remote === undefined) {\n this.set({ phase: 'unavailable', authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: 'login remote is not mounted' })\n return\n }\n let result: LoginCallResult\n try {\n result = await remote.loginStatus()\n } catch {\n continue // one missed poll is not an outage; the next tick retries\n }\n if (this.superseded(generation) || this.currentPhase !== 'waiting') return\n if (result.ok) this.apply(result.value)\n }\n }\n\n private get currentPhase(): LoginPageState['phase'] {\n return this.phase\n }\n\n /** Project one Host status onto the panel face. */\n private apply(status: CommandCodeLoginStatus): void {\n const base = { authUrl: undefined, userName: undefined, keyName: undefined, reason: undefined, message: undefined }\n if (status.state === 'waiting') {\n this.set({ ...base, phase: 'waiting', authUrl: status.authUrl })\n return\n }\n if (status.state === 'success') {\n this.set({ ...base, phase: 'success', userName: status.userName, keyName: status.keyName })\n return\n }\n if (status.state === 'failed') {\n this.set({ ...base, phase: 'failed', reason: status.reason, message: status.message })\n return\n }\n // `idle` mid-poll means the Host restarted; the attempt is gone.\n this.set({ ...base, phase: 'failed', reason: 'cancelled', message: 'the login attempt is no longer active' })\n }\n\n /** Replace the whole state face and notify. Explicit over partial patches. */\n private set(state: LoginPageState): void {\n this.phase = state.phase\n this.authUrl = state.authUrl\n this.userName = state.userName\n this.keyName = state.keyName\n this.reason = state.reason\n this.message = state.message\n this.publish()\n }\n\n private superseded(generation: number): boolean {\n return this.disposed || generation !== this.generation\n }\n\n private publish(): void {\n if (this.disposed) return\n for (const listener of [...this.listeners]) listener()\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n// ---------------------------------------------------------------------------\n// Hint copy for the login panel / card row (JSX-free so node tests drive it)\n// ---------------------------------------------------------------------------\n\n/**\n * The per-reason copy for a failed login attempt. Shared by the settings\n * page's login panel and the Models-page card's login row — the same reasons\n * can surface from either surface.\n */\nexport function loginFailureCopy(\n reason: CommandCodeLoginFailureReason | undefined,\n t: Translate<SettingsCommandCodeKey>,\n): string {\n if (reason === 'denied') return t('loginDenied')\n if (reason === 'timeout') return t('loginTimeout')\n if (reason === 'invalid-key') return t('loginInvalidKey')\n if (reason === 'network') return t('loginNetwork')\n if (reason === 'unavailable') return t('loginStoreFailed')\n if (reason === 'cancelled') return t('loginCancelled')\n return t('loginFailedGeneric')\n}\n\n/** One login panel row's computed hint: text, class stem, and optional title. */\nexport interface LoginHint {\n text: string\n className: string\n /** Tooltip shown when the row carries secondary failure detail. */\n title: string | undefined\n}\n\n/**\n * The hint text + class for one login panel state, shared by the settings\n * page's `LoginPanel` and the Models-page card's login row so both surfaces\n * can never drift apart. Pure: no timers, no state — the components render it.\n */\nexport function loginHint(\n state: LoginPageState,\n t: Translate<SettingsCommandCodeKey>,\n): LoginHint {\n if (state.phase === 'starting' || state.phase === 'waiting') {\n return {\n text: t(state.phase === 'starting' ? 'loginStarting' : 'loginWaiting'),\n className: 'cc-hint',\n title: undefined,\n }\n }\n if (state.phase === 'success') {\n const keyName = state.keyName !== undefined && state.keyName !== '' ? ` · ${state.keyName}` : ''\n return {\n text: `${t('loginSuccess')} ${state.userName ?? ''}${keyName}`.trim(),\n className: 'cc-loginDone',\n title: undefined,\n }\n }\n if (state.phase === 'failed') {\n return {\n text: loginFailureCopy(state.reason, t),\n className: 'cc-loginError',\n title: state.message,\n }\n }\n if (state.phase === 'unavailable') {\n return {\n text: `${t('loginUnavailable')} ${state.message ?? ''}`.trim(),\n className: 'cc-loginError',\n title: undefined,\n }\n }\n return { text: t('loginHintIdle'), className: 'cc-hint', title: undefined }\n}\n","/**\n * Shared boundary-validation and Remote-descriptor plumbing for the plugin's\n * hand-rolled Typert wire contracts (`commandcode/report`, `commandcode/models`,\n * `commandcode/login*`).\n *\n * Every Remote this plugin serves crosses the Typert Gateway with a strict\n * result schema: the Host half registers a descriptor against a Cordis service\n * (`src/usage-remote.ts`) and the browser half mounts the matching contribution\n * on `ctx.remote` (`src/client/index.ts`). The wire contract is deliberately\n * dependency-free so the client bundle can inline it — a pure-TS helper module\n * imported by the wire files keeps it that way while removing the schema\n * helpers and descriptor boilerplate they used to duplicate.\n *\n * @module dsh-commandcode-provider/wire-shared\n */\nimport type { InvocationDescriptor, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\n\n/** The npm package identity every contribution and descriptor claims. */\nexport const REMOTE_PACKAGE = '@mars-sea/dsh-commandcode-provider'\n\n/** The Cordis service key the Gateway resolves every Command Code Remote from. */\nexport const REMOTE_SERVICE = 'commandcodeUsage'\n\n/** The wire namespace all Command Code endpoints share. */\nexport const REMOTE_NAMESPACE = 'commandcode'\n\n/** The read/validate helpers one boundary codec needs. */\nexport interface BoundaryValidator {\n /** Reject one boundary value with a field-naming error. */\n reject(field: string): never\n /** Narrow an unknown value to a plain record, or reject. */\n record(value: unknown, field: string): Record<string, unknown>\n /** Read one required string field (`field` is the dotted error label). */\n stringField(source: Record<string, unknown>, key: string, field: string): string\n /** Read one required finite number field (`field` is the dotted error label). */\n numberField(source: Record<string, unknown>, key: string, field: string): number\n /** Read one required boolean field (`field` is the dotted error label). */\n booleanField(source: Record<string, unknown>, key: string, field: string): boolean\n}\n\n/**\n * Build the validator helpers one endpoint uses. `prefix` names the\n * endpoint in the rejection message (e.g. `commandcode/report result:`), so\n * each wire file keeps its own diagnostic phrasing while sharing the helper\n * bodies.\n *\n * The helpers return the reject call directly in the failure branch: since\n * `reject` is typed `never`, the ternary's union collapses to the success type\n * without relying on TypeScript's control-flow analysis of a never-returning\n * call (which only recognizes function declarations, not the destructured\n * arrow `reject` callers receive from this factory).\n */\nexport function makeBoundaryValidator(prefix: string): BoundaryValidator {\n const reject = (field: string): never => {\n throw new TypeError(`${prefix} invalid ${field}`)\n }\n const record = (value: unknown, field: string): Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? value as Record<string, unknown>\n : reject(field)\n const stringField = (source: Record<string, unknown>, key: string, field: string): string =>\n typeof source[key] === 'string' ? source[key] as string : reject(field)\n const numberField = (source: Record<string, unknown>, key: string, field: string): number =>\n typeof source[key] === 'number' && Number.isFinite(source[key] as number)\n ? source[key] as number\n : reject(field)\n const booleanField = (source: Record<string, unknown>, key: string, field: string): boolean =>\n typeof source[key] === 'boolean' ? source[key] as boolean : reject(field)\n return { reject, record, stringField, numberField, booleanField }\n}\n\n/**\n * One strict result codec.\n *\n * `mode: 'strict'` carries a LAZY schema factory (`create()`), which the\n * registry requires and the Gateway validates with (`codec.create().parse`).\n * The schema is built by `makeStrictCodec` from the endpoint's hand-rolled\n * validator, so nothing here depends on a generated codec.\n */\ninterface StrictCodec<Output> {\n readonly mode: 'strict'\n readonly typeSymbol: string\n readonly create: () => TypertSchema<Output>\n}\n\n/** Use the same strict-codec shape for invocation parameters and results. */\nexport function makeStrictCodec<Output>(typeSymbol: string, schema: TypertSchema<Output>): StrictCodec<Output> {\n return { mode: 'strict', typeSymbol, create: () => schema }\n}\n\n/**\n * Build one strict invocation descriptor. Every Command Code Remote shares the\n * `commandcode` namespace, the `commandcodeUsage` service, and a strict\n * `mode: 'strict'` result — only the endpoint, method, result type symbol, and\n * schema differ — so the boilerplate lives here once and each endpoint supplies\n * only its own facts.\n */\nexport function makeRemoteDescriptor<Output>(\n endpoint: string,\n method: string,\n typeSymbol: string,\n schema: TypertSchema<Output>,\n): InvocationDescriptor {\n return {\n id: `${REMOTE_PACKAGE}#${endpoint}`,\n service: REMOTE_SERVICE,\n namespace: REMOTE_NAMESPACE,\n method,\n invocation: { kind: 'direct' },\n parameters: [],\n result: makeStrictCodec(typeSymbol, schema),\n }\n}\n","/**\n * Wire contract for the Command Code account-usage Remote\n * (`commandcode/report`).\n *\n * The settings page renders the same account/usage/credit facts the\n * `/commandcode` command prints, but the browser never holds the API key —\n * the report must be produced Host-side and cross the Connection RPC carrier.\n * The harness exposes plugin-defined Host methods through the Typert Gateway:\n * the Host half registers a strict invocation descriptor against a Cordis\n * service (`src/usage-remote.ts`), and the browser half mounts the matching\n * Remote contribution on `ctx.remote` (`src/client/index.ts`).\n *\n * This module is the single source both halves share: the result validator\n * (a hand-rolled {@link TypertSchema}, so neither half needs a schema library)\n * and the exact descriptor object, so the endpoint can never drift apart.\n * It is deliberately dependency-free — the client bundle inlines it, and only\n * `import type` edges leave it (erased at build). The boundary-validator\n * helpers and the descriptor boilerplate live in `./wire-shared.ts`, shared\n * with the login wire contract.\n *\n * @module dsh-commandcode-provider/usage-wire\n */\n\nimport type { CommandCodeCredits, CommandCodeUsageReport, UsageBlockReason } from './adapter.ts'\n\nexport type { CommandCodeUsageReport, UsageBlockReason }\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** One account's usage entry in the multi-account report. */\nexport interface CommandCodeAccountUsage {\n /** Stable slot id (`default`, `account-2`, …). */\n id: string\n /** Display label (user-provided or generated). */\n label: string\n /** Whether an API key resolved for this account. */\n configured: boolean\n /** Whether this account currently serves requests (first usable slot). */\n active: boolean\n /** Rotation mark: `''` (usable), `'rate-limit'`, or `'invalid-credential'`. */\n mark: string\n /** Known cooldown end in millis; 0 when unknown or not cooling down. */\n cooldownUntil: number\n /** The per-account report; `failures`-only when the fetch itself failed. */\n report: CommandCodeUsageReport\n}\n\n/** The settings page's account card data: one entry per configured account. */\nexport interface CommandCodeAccountsReport {\n accounts: CommandCodeAccountUsage[]\n}\n\n/** The npm package identity both contribution registrations claim. */\nexport const USAGE_REMOTE_PACKAGE = REMOTE_PACKAGE\n\n/** Canonical `<namespace>/<method>` endpoint of the usage report Remote. */\nexport const USAGE_REPORT_ENDPOINT = 'commandcode/report'\n\n/**\n * The shared read/validate helpers for the usage report endpoint, prefixed\n * so rejection messages name the offending boundary.\n */\nconst { reject, record, stringField, numberField, booleanField } =\n makeBoundaryValidator('commandcode/report result:')\n\n/** Validate one window-limit block (`fiveHour` / `weekly`). */\n/**\n * Parse one quota window, or undefined when the frame carries no such window.\n *\n * The distinction is load-bearing at this boundary: an ABSENT window means the\n * billing endpoint reported none (an unlimited plan), while a present block with\n * `cap: 0` means uncapped spend that was really reported. Collapsing the two\n * would draw a zeroed quota row for an account that has no such limit.\n */\nfunction windowLimit(\n value: unknown,\n field: string,\n): { used: number; cap: number; exceeded: boolean; resetAt: number } | undefined {\n if (value === undefined) return undefined\n const source = record(value, field)\n return {\n used: numberField(source, 'used', `${field}.used`),\n cap: numberField(source, 'cap', `${field}.cap`),\n exceeded: booleanField(source, 'exceeded', `${field}.exceeded`),\n resetAt: numberField(source, 'resetAt', `${field}.resetAt`),\n }\n}\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeUsageReport}.\n * Optional sections stay optional; every present field is shape-checked so a\n * malformed frame fails the boundary instead of rendering garbage.\n */\nfunction parseUsageReport(value: unknown): CommandCodeUsageReport {\n const source = record(value, 'report')\n const failures = source.failures\n if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== 'string')) reject('failures')\n const report: CommandCodeUsageReport = { failures: failures as string[] }\n\n if (source.blocked !== undefined) {\n const blocked = source.blocked\n // Positive check: TS's never-return control-flow analysis only recognizes\n // function declarations, not the factory's destructured-arrow `reject`, so\n // narrow `blocked` in the positive branch instead.\n if (blocked === 'invalid-key' || blocked === 'service-unavailable' || blocked === 'invalid-response' || blocked === 'network') {\n report.blocked = blocked\n } else {\n reject('blocked')\n }\n }\n\n if (source.account !== undefined) {\n const account = record(source.account, 'account')\n report.account = {\n id: stringField(account, 'id', 'account.id'),\n name: stringField(account, 'name', 'account.name'),\n userName: stringField(account, 'userName', 'account.userName'),\n }\n }\n\n if (source.usage !== undefined) {\n const usage = record(source.usage, 'usage')\n report.usage = {\n totalCount: numberField(usage, 'totalCount', 'usage.totalCount'),\n totalCost: numberField(usage, 'totalCost', 'usage.totalCost'),\n successRate: numberField(usage, 'successRate', 'usage.successRate'),\n completedCount: numberField(usage, 'completedCount', 'usage.completedCount'),\n failedCount: numberField(usage, 'failedCount', 'usage.failedCount'),\n totalTokensIn: numberField(usage, 'totalTokensIn', 'usage.totalTokensIn'),\n totalTokensOut: numberField(usage, 'totalTokensOut', 'usage.totalTokensOut'),\n totalCredits: numberField(usage, 'totalCredits', 'usage.totalCredits'),\n periodBasis: stringField(usage, 'periodBasis', 'usage.periodBasis'),\n }\n }\n\n if (source.credits !== undefined) {\n const credits = record(source.credits, 'credits')\n const parsed: CommandCodeCredits = {\n monthlyCredits: numberField(credits, 'monthlyCredits', 'credits.monthlyCredits'),\n purchasedCredits: numberField(credits, 'purchasedCredits', 'credits.purchasedCredits'),\n freeCredits: numberField(credits, 'freeCredits', 'credits.freeCredits'),\n }\n // OPTIONAL on the wire: a Host half that predates this field serves the\n // scalar 0 for an omitted balance, which cannot be told from a real zero.\n // An explicit `false` therefore means \"not reported\" and the panel keeps the\n // figure off the dashboard; an absent flag (an older Host) stays unset and\n // is read as \"assume reported\", so a real balance is not lost cross-version.\n // A PRESENT value must still be a boolean, so a malformed frame is rejected\n // here rather than coerced.\n if (credits.monthlyReported !== undefined) {\n parsed.monthlyReported = booleanField(credits, 'monthlyReported', 'credits.monthlyReported')\n }\n for (const flag of ['purchasedReported', 'freeReported'] as const) {\n if (credits[flag] !== undefined) parsed[flag] = booleanField(credits, flag, `credits.${flag}`)\n }\n // Absent means the endpoint reported no such window. The window parsers\n // return undefined for an absent block, and an optional member is only set\n // when it was really there.\n const fiveHour = windowLimit(credits.fiveHour, 'credits.fiveHour')\n const weekly = windowLimit(credits.weekly, 'credits.weekly')\n if (fiveHour !== undefined) parsed.fiveHour = fiveHour\n if (weekly !== undefined) parsed.weekly = weekly\n report.credits = parsed\n }\n\n if (source.plan !== undefined) {\n const plan = record(source.plan, 'plan')\n const monthly = plan.monthlyCredits\n if (monthly !== null && (typeof monthly !== 'number' || !Number.isFinite(monthly))) reject('plan.monthlyCredits')\n report.plan = {\n planId: stringField(plan, 'planId', 'plan.planId'),\n name: stringField(plan, 'name', 'plan.name'),\n status: stringField(plan, 'status', 'plan.status'),\n monthlyCredits: monthly as number | null,\n currentPeriodEnd: numberField(plan, 'currentPeriodEnd', 'plan.currentPeriodEnd'),\n }\n }\n\n return report\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeAccountUsage}. */\nfunction parseAccountUsage(value: unknown): CommandCodeAccountUsage {\n const source = record(value, 'account')\n return {\n id: stringField(source, 'id', 'account.id'),\n label: stringField(source, 'label', 'account.label'),\n configured: booleanField(source, 'configured', 'account.configured'),\n active: booleanField(source, 'active', 'account.active'),\n mark: stringField(source, 'mark', 'account.mark'),\n cooldownUntil: numberField(source, 'cooldownUntil', 'account.cooldownUntil'),\n report: parseUsageReport(source.report),\n }\n}\n\n/** Parse the wire result into a {@link CommandCodeAccountsReport}. */\nfunction parseAccountsReport(value: unknown): CommandCodeAccountsReport {\n const source = record(value, 'result')\n const accounts = source.accounts\n if (Array.isArray(accounts)) {\n return { accounts: accounts.map(parseAccountUsage) }\n }\n return reject('accounts')\n}\n\n/**\n * The strict result codec both halves attach to the descriptor. Hand-rolled:\n * the client bundle may not require a schema library, and `TypertSchema` is\n * deliberately minimal so one `parse` function satisfies it.\n */\nexport const usageReportSchema: TypertSchema<CommandCodeAccountsReport> = {\n parse: parseAccountsReport,\n}\n\n/**\n * The one invocation descriptor, shared verbatim by the Host registration and\n * the Client mount. `service` names the Cordis key the Gateway resolves the\n * receiver from; `namespace`/`method` name the wire endpoint.\n */\nexport const USAGE_REPORT_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeAccountsReport>(\n USAGE_REPORT_ENDPOINT,\n 'report',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeAccountsReport`,\n usageReportSchema,\n )\n\n/** The Host-face contribution registered on `ctx.typert`. */\nexport const USAGE_HOST_CONTRIBUTION = {\n package: USAGE_REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n // Every Host contribution must carry its reflection model. This hand-written\n // Remote deliberately has no generated reflection exports, so use the\n // official empty-model form rather than a cast that would leave registry\n // inspection with `model: undefined`.\n model: { services: [], events: [], objects: [] },\n invocations: [USAGE_REPORT_DESCRIPTOR],\n}\n\n/** The Client-face contribution mounted on `ctx.remote`. */\nexport const USAGE_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [USAGE_REPORT_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog Remote (`commandcode/models`)\n// ---------------------------------------------------------------------------\n\n/** One catalog entry the settings page's model editors offer. */\nexport interface CommandCodeCatalogModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n /**\n * Minimum plan-tier key for this model (a `KNOWN_PLANS` value: `go`,\n * `goat`, `pro`, `provider`, `max`), or undefined for models outside the\n * snapshot. The settings page groups the model-editor dropdowns under\n * tier headings from this — the browser cannot import the Host's\n * capability snapshot, so the Host stamps it per entry.\n */\n tier?: string\n}\n\n/** The model-catalog Remote result: the full catalog, sorted for picking. */\nexport interface CommandCodeCatalog {\n models: CommandCodeCatalogModel[]\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the model-catalog Remote. */\nexport const MODELS_ENDPOINT = 'commandcode/models'\n\n/**\n * The shared read/validate helpers for the model-catalog endpoint — a\n * separate instance so catalog boundary errors name `commandcode/models`,\n * not the report endpoint.\n */\nconst {\n record: catalogRecord,\n stringField: catalogString,\n} = makeBoundaryValidator('commandcode/models result:')\n\n/** Parse one untrusted boundary value into a {@link CommandCodeCatalogModel}. */\nfunction parseCatalogModel(value: unknown): CommandCodeCatalogModel {\n const source = catalogRecord(value, 'model')\n const model: CommandCodeCatalogModel = {\n id: catalogString(source, 'id', 'model.id'),\n name: catalogString(source, 'name', 'model.name'),\n }\n // Tier is optional on the wire (older Hosts predate it); a present\n // non-string is a contract violation, not a silent drop.\n if (source.tier !== undefined) {\n model.tier = catalogString(source, 'tier', 'model.tier')\n }\n return model\n}\n\n/** Parse the wire result into a {@link CommandCodeCatalog}. */\nfunction parseCatalog(value: unknown): CommandCodeCatalog {\n const source = catalogRecord(value, 'result')\n const models = source.models\n if (Array.isArray(models)) {\n return { models: models.map(parseCatalogModel) }\n }\n throw new TypeError('commandcode/models result: invalid models')\n}\n\n/** The strict result codec for the model-catalog Remote. */\nexport const modelsSchema: TypertSchema<CommandCodeCatalog> = {\n parse: parseCatalog,\n}\n\n/**\n * The model-catalog invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the usage report.\n */\nexport const MODELS_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodeCatalog>(\n MODELS_ENDPOINT,\n 'models',\n `${USAGE_REMOTE_PACKAGE}#CommandCodeCatalog`,\n modelsSchema,\n )\n\n/** The Client-face contribution for the model-catalog endpoint. */\nexport const MODELS_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [MODELS_DESCRIPTOR],\n}\n\n// ---------------------------------------------------------------------------\n// Model price table Remote (`commandcode/prices`)\n// ---------------------------------------------------------------------------\n\n/**\n * One model's per-token rates, in USD per 1,000,000 tokens — the unit the\n * official pricing page publishes in.\n */\nexport interface CommandCodeModelRates {\n /** Uncached (billed) input tokens. */\n inputCost: number\n /** Completion tokens. */\n outputCost: number\n /** Input tokens served from the provider's cache. */\n cacheReadCost: number\n /**\n * Input tokens written into the provider's cache. Present for a minority of\n * models — the page publishes no cache-write rate for the rest, whose\n * cache-write tokens are therefore UNPRICED. Do not substitute a multiple of\n * the input rate for a missing value.\n */\n cacheWriteCost?: number\n}\n\n/** One whole-request context band; maxContext is inclusive, absent on the last band. */\nexport interface CommandCodeContextTier extends CommandCodeModelRates {\n maxContext?: number\n}\n\n/** One model's rates plus the peak-hour override for time-of-day models. */\nexport interface CommandCodeModelPrice extends CommandCodeModelRates {\n /**\n * Lookup key: the catalog model id when a catalog model maps to this row,\n * otherwise the pricing page's own slug. A session reports catalog ids, so\n * this is the primary key the browser looks up by.\n */\n id: string\n /** The pricing page's slug for this row — the secondary lookup key. */\n slug: string\n /**\n * Rates charged inside the peak windows. The row's own top-level rates are\n * the off-peak rates, so a row WITH this block is time-of-day priced and a\n * row without it is flat-priced.\n */\n peak?: CommandCodeModelRates\n contextTiers?: CommandCodeContextTier[]\n /**\n * Whether the model costs nothing on every plan right now (a free deal or a\n * `:free` catalog variant). Served explicitly at zero rates so a surface can\n * say \"free\" rather than showing nothing.\n */\n free?: boolean\n}\n\n/** The price-table Remote result: every known model's rates. */\nexport interface CommandCodePriceTable {\n /**\n * Every priced model, keyed by {@link CommandCodeModelPrice.id} (catalog id\n * first, pricing slug as the fallback) and carrying its slug as a second\n * lookup key. A model absent from this list has no known price and must\n * render no cost at all rather than a guess.\n */\n models: CommandCodeModelPrice[]\n /**\n * Peak-pricing windows as `[startHour, endHour)` in UTC, end-exclusive,\n * applying Monday–Friday only. Shipped with the table so the browser prices\n * against the Host snapshot's schedule instead of restating it.\n */\n peakHours: Array<[number, number]>\n}\n\n/** Canonical `<namespace>/<method>` endpoint of the price-table Remote. */\nexport const PRICES_ENDPOINT = 'commandcode/prices'\n\n/**\n * The shared read/validate helpers for the price-table endpoint — its own\n * instance so price boundary errors name `commandcode/prices`.\n */\nconst {\n reject: priceReject,\n record: priceRecord,\n stringField: priceString,\n numberField: priceNumber,\n booleanField: priceBoolean,\n} = makeBoundaryValidator('commandcode/prices result:')\n\n/** Parse one rate block (`rates`, or a model's `peak` override). */\nfunction parseRates(source: Record<string, unknown>, field: string): CommandCodeModelRates {\n const rates: CommandCodeModelRates = {\n inputCost: priceNumber(source, 'inputCost', `${field}.inputCost`),\n outputCost: priceNumber(source, 'outputCost', `${field}.outputCost`),\n cacheReadCost: priceNumber(source, 'cacheReadCost', `${field}.cacheReadCost`),\n }\n // Optional on the wire: only a minority of models publish a cache-write\n // rate, and a present non-number is a contract violation rather than a\n // silent zero.\n if (source.cacheWriteCost !== undefined) {\n rates.cacheWriteCost = priceNumber(source, 'cacheWriteCost', `${field}.cacheWriteCost`)\n }\n return rates\n}\n\n/** Parse one untrusted boundary value into a {@link CommandCodeModelPrice}. */\nfunction parseModelPrice(value: unknown): CommandCodeModelPrice {\n const source = priceRecord(value, 'model')\n const price: CommandCodeModelPrice = {\n id: priceString(source, 'id', 'model.id'),\n slug: priceString(source, 'slug', 'model.slug'),\n ...parseRates(source, 'model'),\n }\n if (source.peak !== undefined) price.peak = parseRates(priceRecord(source.peak, 'model.peak'), 'model.peak')\n if (source.contextTiers !== undefined) {\n if (!Array.isArray(source.contextTiers) || source.contextTiers.length === 0) priceReject('contextTiers')\n let previous = 0\n price.contextTiers = (source.contextTiers as unknown[]).map((value, index, tiers) => {\n const tier = priceRecord(value, 'contextTier')\n const out: CommandCodeContextTier = parseRates(tier, 'contextTier')\n if (tier.maxContext !== undefined) {\n const max = priceNumber(tier, 'maxContext', 'contextTier.maxContext')\n if (!Number.isSafeInteger(max) || max <= previous || index === tiers.length - 1) priceReject('contextTier.maxContext')\n previous = max\n out.maxContext = max\n } else if (index !== tiers.length - 1) priceReject('contextTier.maxContext')\n return out\n })\n }\n if (source.free !== undefined) price.free = priceBoolean(source, 'free', 'model.free')\n return price\n}\n\n/** Parse the wire result into a {@link CommandCodePriceTable}. */\nfunction parsePriceTable(value: unknown): CommandCodePriceTable {\n const source = priceRecord(value, 'result')\n const models = source.models\n if (!Array.isArray(models)) priceReject('models')\n const peakHours = source.peakHours\n if (!Array.isArray(peakHours)) priceReject('peakHours')\n return {\n models: (models as unknown[]).map(parseModelPrice),\n peakHours: (peakHours as unknown[]).map((window) => {\n if (!Array.isArray(window) || window.length !== 2) priceReject('peakHours[]')\n const [start, end] = window as [unknown, unknown]\n if (typeof start !== 'number' || typeof end !== 'number') priceReject('peakHours[]')\n return [start, end] as [number, number]\n }),\n }\n}\n\n/** The strict result codec for the price-table Remote. */\nexport const pricesSchema: TypertSchema<CommandCodePriceTable> = {\n parse: parsePriceTable,\n}\n\n/**\n * The price-table invocation descriptor, sharing the same `commandcodeUsage`\n * service and `commandcode` namespace as the report and catalog endpoints.\n */\nexport const PRICES_DESCRIPTOR: InvocationDescriptor =\n makeRemoteDescriptor<CommandCodePriceTable>(\n PRICES_ENDPOINT,\n 'prices',\n `${USAGE_REMOTE_PACKAGE}#CommandCodePriceTable`,\n pricesSchema,\n )\n\n/** The Client-face contribution for the price-table endpoint. */\nexport const PRICES_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: USAGE_REMOTE_PACKAGE,\n descriptors: [PRICES_DESCRIPTOR],\n}\n","/**\n * Wire contract for the Command Code login Remote endpoints\n * (`commandcode/loginBegin`, `commandcode/loginStatus`,\n * `commandcode/loginCancel`).\n *\n * The settings page can start a browser login against the official Command\n * Code Studio (the same loopback flow `command-code login` performs) instead\n * of pasting an API key. The loopback server must live in the Host half — it\n * binds a local port and receives the key — so the page drives it through the\n * Typert Gateway exactly like the usage report.\n *\n * This module is the single source both halves share, deliberately\n * dependency-free (`import type` edges only): the strict status validator the\n * client trusts, the three descriptors both halves register, and the two\n * contribution objects. The state shape mirrors the Host-only flow machine in\n * `src/login.ts` as plain JSON.\n *\n * @module dsh-commandcode-provider/login-wire\n */\n\nimport type { InvocationDescriptor, TypertRemoteContribution, TypertSchema } from '@deepseek-ai/dsh-typert-protocol'\nimport {\n makeBoundaryValidator,\n makeRemoteDescriptor,\n makeStrictCodec,\n REMOTE_PACKAGE,\n} from './wire-shared.ts'\n\n/** Why a login attempt ended in `failed` (stable across versions for copy). */\nexport type CommandCodeLoginFailureReason =\n /** The Studio page reported the authorization was denied by the user. */\n | 'denied'\n /** No callback arrived within the flow's timeout window. */\n | 'timeout'\n /** The delivered key failed `/alpha/whoami` validation (401). */\n | 'invalid-key'\n /** The validation request could not reach the API. */\n | 'network'\n /** The key could not be stored (credentials seam unavailable). */\n | 'unavailable'\n /** The attempt was cancelled by the user or torn down with the plugin. */\n | 'cancelled'\n /** Anything else. */\n | 'error'\n\n/** One login attempt's full state face, as carried over the wire. */\nexport interface CommandCodeLoginStatus {\n /**\n * `idle` — no attempt; `waiting` — the loopback server is up and the\n * Studio URL is live; `success` — the key validated and was stored;\n * `failed` — see `reason`/`message`.\n */\n state: 'idle' | 'waiting' | 'success' | 'failed'\n /** The Studio authorization URL while `waiting`. */\n authUrl?: string\n /** The account display name reported by the Studio, on `success`. */\n userName?: string\n /** The key's label from the Studio, on `success`. */\n keyName?: string\n /** Why the attempt failed, when `failed`. */\n reason?: CommandCodeLoginFailureReason\n /** Human-readable failure detail, when `failed` (secondary to `reason`). */\n message?: string\n}\n\n/** The canonical endpoint paths of the three login Remotes. */\nexport const LOGIN_BEGIN_ENDPOINT = 'commandcode/loginBegin'\nexport const LOGIN_STATUS_ENDPOINT = 'commandcode/loginStatus'\nexport const LOGIN_CANCEL_ENDPOINT = 'commandcode/loginCancel'\n\nconst REASONS: readonly CommandCodeLoginFailureReason[] = [\n 'denied', 'timeout', 'invalid-key', 'network', 'unavailable', 'cancelled', 'error',\n]\n\n/** The shared read/validate helpers, prefixed with the login endpoint so\n * rejection messages name the offending boundary. */\nconst { reject, record, stringField } =\n makeBoundaryValidator('commandcode/login result:')\n\n/**\n * Parse one untrusted boundary value into a {@link CommandCodeLoginStatus}.\n * Every field is shape-checked so a malformed frame fails the boundary\n * instead of leaking into the page.\n */\nexport function parseLoginStatus(value: unknown): CommandCodeLoginStatus {\n const source = record(value, 'status')\n const state = source.state\n // The factory's destructured-arrow `reject` is typed never-returning but\n // TS narrows it only in the positive branch — assign inside the guard.\n if (state === 'idle' || state === 'waiting' || state === 'success' || state === 'failed') {\n const status: CommandCodeLoginStatus = { state }\n if (source.authUrl !== undefined) {\n status.authUrl = stringField(source, 'authUrl', 'authUrl')\n }\n if (source.userName !== undefined) {\n status.userName = stringField(source, 'userName', 'userName')\n }\n if (source.keyName !== undefined) {\n status.keyName = stringField(source, 'keyName', 'keyName')\n }\n if (source.reason !== undefined) {\n const reason = source.reason\n if (typeof reason === 'string' && REASONS.includes(reason as CommandCodeLoginFailureReason)) {\n status.reason = reason as CommandCodeLoginFailureReason\n } else {\n reject('reason')\n }\n }\n if (source.message !== undefined) {\n status.message = stringField(source, 'message', 'message')\n }\n return status\n }\n return reject('state')\n}\n\n/** The strict result codec shared by all three login endpoints. */\nexport const loginStatusSchema: TypertSchema<CommandCodeLoginStatus> = {\n parse: parseLoginStatus,\n}\n\n/** Optional account target; the Host still checks it against saved slots. */\nconst loginTargetSchema: TypertSchema<string | undefined> = {\n parse(value: unknown): string | undefined {\n if (value === undefined || typeof value === 'string') return value\n return reject('targetRef')\n },\n}\n\n/** Build one login invocation descriptor. Only begin accepts an account ref. */\nfunction loginDescriptor(endpoint: string, method: string): InvocationDescriptor {\n const descriptor = makeRemoteDescriptor<CommandCodeLoginStatus>(\n endpoint,\n method,\n `${REMOTE_PACKAGE}#CommandCodeLoginStatus`,\n loginStatusSchema,\n )\n return method === 'loginBegin'\n ? {\n ...descriptor,\n parameters: [{\n name: 'targetRef', wire: 'targetRef', source: 'json',\n codec: makeStrictCodec(`${REMOTE_PACKAGE}#CommandCodeLoginTargetRef`, loginTargetSchema),\n acceptsUndefined: true,\n }],\n }\n : descriptor\n}\n\n/** The three login descriptors, shared verbatim by Host registration and Client mount. */\nexport const LOGIN_DESCRIPTORS: readonly InvocationDescriptor[] = [\n loginDescriptor(LOGIN_BEGIN_ENDPOINT, 'loginBegin'),\n loginDescriptor(LOGIN_STATUS_ENDPOINT, 'loginStatus'),\n loginDescriptor(LOGIN_CANCEL_ENDPOINT, 'loginCancel'),\n]\n\n/** The Host-face contribution fragment registered on `ctx.typert`. */\nexport const LOGIN_HOST_CONTRIBUTION = {\n package: REMOTE_PACKAGE,\n face: 'host' as const,\n schemas: [],\n invocations: LOGIN_DESCRIPTORS,\n}\n\n/** The Client-face contribution fragment mounted on `ctx.remote`. */\nexport const LOGIN_REMOTE_CONTRIBUTION: TypertRemoteContribution = {\n package: REMOTE_PACKAGE,\n descriptors: LOGIN_DESCRIPTORS,\n}\n","/**\n * Model-select helpers for the settings page's model editors (browser half).\n *\n * The routing-rule editor and the visible-models filter both pick catalog\n * models through the same checkbox multi-select dropdown (`ModelMultiSelect`\n * in section.tsx). The dropdown's data shaping — search filtering, stale-id\n * detection, tier grouping — lives here, React-free, so node tests can drive\n * it directly.\n *\n * Dependency-free by design: the client bundle may only import platform/seed\n * modules, so the plan snapshot below is a deliberately small vendored copy\n * (tier key → heading label) rather than an import of src/capabilities.ts.\n * When upstream adds a plan tier, extend BOTH tables.\n *\n * @module dsh-commandcode-provider/model-select\n */\n\n/**\n * Minimum plan tier → dropdown section heading. Mirrors the Host-side\n * `KNOWN_PLANS` values + `PLAN_LABELS` in src/capabilities.ts (kept as a\n * vendored copy because the client bundle cannot import host modules).\n * Covers every tier key `KNOWN_PLANS` uses today; an unknown tier key falls\n * back to the raw key rather than vanishing the row.\n */\nconst TIER_HEADINGS: Readonly<Record<string, string>> = {\n go: 'Go',\n goat: 'GOAT',\n pro: 'Pro',\n provider: 'Provider',\n max: 'Max',\n}\n\n/**\n * The dropdown section heading for a catalog model id, or undefined for\n * models outside the known plan tiers (unmapped models and stale ids render\n * unheaded). `knownPlans` is the Host-side `KNOWN_PLANS` table, threaded in\n * by the caller so this module stays dependency-free.\n */\nexport function tierHeadingFor(\n modelId: string,\n knownPlans: Readonly<Record<string, string>>,\n): string | undefined {\n const tier = knownPlans[modelId]\n if (tier === undefined) return undefined\n return TIER_HEADINGS[tier] ?? tier\n}\n\n/** One selectable catalog model (mirrors `CatalogModelOption` in settings.ts). */\nexport interface SelectableModel {\n /** Catalog model id (e.g. `deepseek/deepseek-v4-pro`). */\n id: string\n /** Display name from the catalog. */\n name: string\n}\n\n/** One dropdown row: a live catalog model or a stale selection. */\nexport interface ModelSelectOption {\n /** Catalog model id (stale ids keep their raw id as the value). */\n value: string\n /** Display name (stale ids fall back to the raw id). */\n label: string\n /** True when the id is selected but the catalog no longer carries it. */\n stale: boolean\n}\n\n/** One dropdown section: a plan-tier heading plus its rows. */\nexport interface ModelSelectGroup {\n /** Section heading, or undefined for models outside the known plan tiers. */\n heading: string | undefined\n /** Rows in this section, in picker order. */\n options: ModelSelectOption[]\n}\n\n/**\n * Whether `text` matches `query` as a case-insensitive substring over the\n * model id AND display name. An empty/blank query matches everything.\n */\nexport function matchesModelQuery(\n model: SelectableModel,\n query: string,\n): boolean {\n const needle = query.trim().toLowerCase()\n if (needle === '') return true\n return model.id.toLowerCase().includes(needle)\n || model.name.toLowerCase().includes(needle)\n}\n\n/**\n * Build the dropdown options: the catalog (already in picker order) plus\n * any selected ids the catalog no longer carries, flagged stale so the UI\n * can mark them — a saved selection never silently loses an entry, and the\n * user can see which ones went stale upstream.\n *\n * When `query` is non-blank, catalog rows are filtered by\n * {@link matchesModelQuery}; stale rows are kept only while they match too,\n * so a search for a live model does not surface unrelated stale ids.\n */\nexport function buildModelSelectOptions(\n catalog: readonly SelectableModel[],\n selected: readonly string[],\n query = '',\n): ModelSelectOption[] {\n const catalogIds = new Set(catalog.map((model) => model.id))\n const options = catalog\n .filter((model) => matchesModelQuery(model, query))\n .map((model) => ({ value: model.id, label: model.name, stale: false }))\n // Dedupe defensively (order-preserving): hand-edited settings can repeat\n // or blank an id, and duplicate Menu ids would confuse selection state.\n const seen = new Set(catalogIds)\n for (const id of selected) {\n if (id === '' || seen.has(id)) continue\n seen.add(id)\n if (catalogIds.has(id)) continue\n if (!matchesModelQuery({ id, name: id }, query)) continue\n options.push({ value: id, label: id, stale: true })\n }\n return options\n}\n\n/**\n * Group dropdown options under plan-tier headings (`tierOf` maps a model id\n * to its tier heading, or undefined for unmapped models — see\n * {@link tierHeadingFor}). Live rows keep their relative order; stale ids\n * and unmapped live rows share one trailing unheaded group. Groups merge\n * repeats, so a catalog interleaving two tiers still renders one section\n * per tier.\n */\nexport function groupModelSelectOptions(\n options: readonly ModelSelectOption[],\n tierOf: (modelId: string) => string | undefined,\n): ModelSelectGroup[] {\n const groups: ModelSelectGroup[] = []\n const byHeading = new Map<string | undefined, ModelSelectGroup>()\n for (const option of options) {\n // Stale ids always render unheaded (their tier is unknowable); unmapped\n // live rows join the same trailing group so `heading: undefined`\n // appears at most once.\n const heading = option.stale ? undefined : tierOf(option.value)\n let group = byHeading.get(heading)\n if (group === undefined) {\n group = { heading, options: [] }\n byHeading.set(heading, group)\n groups.push(group)\n }\n group.options.push(option)\n }\n return groups\n}\n\n/**\n * Toggle one model id in a selection: remove it when present, append it\n * when absent (append keeps catalog order irrelevant — the picker re-sorts\n * by plan tier on render).\n */\nexport function toggleModelSelection(\n selected: readonly string[],\n modelId: string,\n): string[] {\n return selected.includes(modelId)\n ? selected.filter((value) => value !== modelId)\n : [...selected, modelId]\n}\n\n/** The catalog facts the visible-models card reads (mirrors `SettingsPageState`). */\nexport interface CatalogReadiness {\n /** Catalog model ids the Host reported (`[]` before the first fetch lands). */\n catalogIds: readonly string[]\n /** Whether the catalog fetch failed (or the Remote is unavailable). */\n catalogFailed: boolean\n}\n\n/**\n * Whether the catalog is trustworthy enough to call an unlisted selection\n * \"retired\". FALSE while the first fetch is still in flight and after a\n * failure, because the catalog is empty then and every selected id would look\n * stale — which turns the one-click stale cleanup into a button that silently\n * empties the allowlist. A successfully loaded but empty catalog is treated as\n * untrustworthy too: an empty list is far more likely a Host problem than every\n * model being retired at once, and the explicit \"show all\" entry covers the\n * user who really wants to clear the list.\n */\nexport function catalogIsReady(readiness: CatalogReadiness): boolean {\n return readiness.catalogIds.length > 0 && !readiness.catalogFailed\n}\n\n/**\n * Selected ids the loaded catalog no longer carries, in selection order.\n * Callers gate user-visible \"stale\" affordances on {@link catalogIsReady} —\n * the list itself is informational.\n */\nexport function staleModelIds(\n selected: readonly string[],\n readiness: CatalogReadiness,\n): string[] {\n const catalogIds = new Set(readiness.catalogIds)\n return selected.filter((id) => !catalogIds.has(id))\n}\n","","/**\n * The plugin's own version, read from package.json at build time.\n *\n * The client bundle inlines the JSON import (rolldown resolves it during the\n * tsdown build; node tests read it through tsx), so the rendered value always\n * matches the published package version with no second constant to keep in\n * sync. Rendered as a muted footer line on the settings page so a user can\n * report the exact build they run.\n *\n * @module dsh-commandcode-provider/client/version\n */\n\nimport pkg from '../../package.json'\n\n/** The published package version (e.g. `'0.6.0'`). */\nexport const PLUGIN_VERSION: string = pkg.version\n\n/**\n * This package's GitHub releases page, derived from the repository field so\n * the update hint's link target can never drift from the published home.\n * Tolerates both repository shapes (`{ url }` and the plain string form).\n */\nexport const PLUGIN_RELEASES_URL: string = (() => {\n const repo: unknown = (pkg as { repository?: unknown }).repository\n const url = typeof repo === 'string' ? repo : (repo as { url?: unknown } | undefined)?.url\n return `${typeof url === 'string' ? url.replace(/^git\\+/, '').replace(/\\.git$/, '') : 'https://github.com/Mars-Sea/dsh-commandcode-provider'}/releases`\n})()\n","/**\n * Plugin update hint (browser half).\n *\n * A deliberately small feature: when the \"Command Code\" settings page opens,\n * ask the npm registry for the package's published `latest` version and —\n * only when it is newer than the running build — let the page's footer show a\n * muted \"newer version available\" link to the GitHub releases. Everything\n * here is React-free and side-effect-seamed so node tests can drive it.\n *\n * Behaviour contract:\n *\n * - The registry is queried at most once per {@link UPDATE_CHECK_INTERVAL_MS}\n * per browser profile; the learned version is cached in `localStorage`\n * alongside the attempt time, so re-opening the settings page is free.\n * - A failed check records the attempt time too (an offline browser must not\n * hammer the registry on every page open) but keeps any previously learned\n * version, so the hint survives transient outages until it expires.\n * - Every failure mode (blocked network, non-OK status, malformed payload,\n * unavailable storage) degrades to \"no hint\"; nothing ever throws out of\n * {@link checkForUpdate}.\n *\n * The registry serves `access-control-allow-origin: *`, so the plain browser\n * fetch works from the GUI origin without any Host-side proxying.\n *\n * @module dsh-commandcode-provider/client/update\n */\n\n/** How often the page may hit the registry: once a day. */\nexport const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000\n\n/** Abort a hung registry request rather than keep the footer waiting. */\nexport const FETCH_TIMEOUT_MS = 5000\n\n/**\n * The npm registry document for this package's `latest` dist-tag. The scoped\n * name is path-escaped (`%2F`) so no client normalizes the slash away.\n */\nexport const NPM_LATEST_URL =\n 'https://registry.npmjs.org/@mars-sea%2Fdsh-commandcode-provider/latest'\n\n/**\n * Compare two version strings (`major.minor.patch[-pre]`). Returns a negative\n * number when `a` sorts before `b`, positive when after, zero when equal.\n *\n * Tolerant by design: a leading `v` is stripped, unparsable numeric parts\n * count as `0`, and semver prerelease rules apply (release > prerelease;\n * numeric identifiers compare numerically, everything else lexically, a\n * shorter identifier list sorts first). Enough for release tags; not a full\n * semver validator.\n */\nexport function compareVersions(a: string, b: string): number {\n const left = splitVersion(a)\n const right = splitVersion(b)\n const depth = Math.max(left.core.length, right.core.length)\n for (let index = 0; index < depth; index += 1) {\n const delta = (left.core[index] ?? 0) - (right.core[index] ?? 0)\n if (delta !== 0) return Math.sign(delta)\n }\n // A release outranks any prerelease of the same core version.\n if (left.pre.length === 0 && right.pre.length === 0) return 0\n if (left.pre.length === 0) return 1\n if (right.pre.length === 0) return -1\n const width = Math.max(left.pre.length, right.pre.length)\n for (let index = 0; index < width; index += 1) {\n const l = left.pre[index]\n const r = right.pre[index]\n if (l === undefined) return -1\n if (r === undefined) return 1\n const lNumeric = /^\\d+$/.test(l)\n const rNumeric = /^\\d+$/.test(r)\n let delta: number\n if (lNumeric && rNumeric) delta = Number(l) - Number(r)\n else if (lNumeric) delta = -1 // numeric identifiers sort below alphanumeric\n else if (rNumeric) delta = 1\n else delta = l < r ? -1 : l > r ? 1 : 0\n if (delta !== 0) return Math.sign(delta)\n }\n return 0\n}\n\n/** True when `candidate` is strictly newer than `current`. */\nexport function isNewerVersion(candidate: string, current: string): boolean {\n return compareVersions(candidate, current) > 0\n}\n\n/** Split a tolerant version string into numeric core + prerelease ids. */\nfunction splitVersion(value: string): { core: number[]; pre: string[] } {\n // Split on the FIRST dash only: `1.0.0-alpha-1` has prerelease `alpha-1`,\n // not `alpha` (a split on every dash would drop the `-1`).\n const cleaned = value.trim().replace(/^v/i, '')\n const dash = cleaned.indexOf('-')\n const coreText = dash < 0 ? cleaned : cleaned.slice(0, dash)\n const preText = dash < 0 ? undefined : cleaned.slice(dash + 1)\n const core = coreText === ''\n ? [0]\n : coreText.split('.').map((part) => {\n const parsed = Number.parseInt(part, 10)\n return Number.isFinite(parsed) ? parsed : 0\n })\n const pre = preText === undefined ? [] : preText.split('.')\n return { core, pre }\n}\n\n/**\n * Extract the published version from the registry's `/latest` manifest\n * (`{ name, version, … }`). Throws on anything unexpected so callers treat a\n * shape change as a failed attempt, never as bogus data.\n */\nexport function parseLatestVersion(payload: unknown): string {\n if (typeof payload !== 'object' || payload === null) {\n throw new Error('npm latest payload is not an object')\n }\n const version = (payload as { version?: unknown }).version\n if (typeof version !== 'string' || !/^\\d+\\.\\d+\\./.test(version)) {\n throw new Error('npm latest payload has no usable version')\n }\n return version\n}\n\n/** Fetch and parse the published `latest` version. Rejects on any failure. */\nexport async function fetchLatestVersion(\n fetchImpl: typeof fetch = fetch,\n): Promise<string> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)\n try {\n const response = await fetchImpl(NPM_LATEST_URL, { signal: controller.signal })\n if (!response.ok) {\n throw new Error(`registry responded ${response.status}`)\n }\n return parseLatestVersion(await response.json())\n } finally {\n clearTimeout(timer)\n }\n}\n\n/** What the cache remembers about the last check. */\nexport interface UpdateCheckRecord {\n /** When the last attempt completed (success or failure), epoch ms. */\n at: number\n /** The last successfully learned upstream version, if any. */\n version?: string | undefined\n}\n\n/** Storage seam so tests can stand in for `localStorage`. */\nexport interface UpdateCheckStore {\n read(): UpdateCheckRecord | undefined\n write(record: UpdateCheckRecord): void\n}\n\n/** The `localStorage` key holding {@link UpdateCheckRecord}. */\nexport const UPDATE_CHECK_CACHE_KEY = '@mars-sea/dsh-commandcode-provider/update-check'\n\n/**\n * A {@link UpdateCheckStore} backed by `localStorage`. Tolerates a missing or\n * throwing storage (SSR-ish contexts, private modes): reads yield `undefined`,\n * writes are dropped.\n */\nexport function localStorageUpdateStore(\n storage: Storage | undefined = typeof localStorage === 'undefined' ? undefined : localStorage,\n): UpdateCheckStore {\n return {\n read(): UpdateCheckRecord | undefined {\n if (storage === undefined) return undefined\n try {\n const raw = storage.getItem(UPDATE_CHECK_CACHE_KEY)\n if (raw === null) return undefined\n const parsed: unknown = JSON.parse(raw)\n if (typeof parsed !== 'object' || parsed === null) return undefined\n const at = (parsed as { at?: unknown }).at\n if (typeof at !== 'number' || !Number.isFinite(at)) return undefined\n const version = (parsed as { version?: unknown }).version\n return {\n at,\n version: typeof version === 'string' && version !== '' ? version : undefined,\n }\n } catch {\n return undefined\n }\n },\n write(record: UpdateCheckRecord): void {\n if (storage === undefined) return\n try {\n storage.setItem(UPDATE_CHECK_CACHE_KEY, JSON.stringify(record))\n } catch {\n // Quota/private-mode failures must never break the page.\n }\n },\n }\n}\n\n/**\n * Run one throttled update check. Resolves with the newest published version\n * when it is newer than `currentVersion`, otherwise `undefined`.\n *\n * Within the throttle window (or on failure) the cached version answers, so\n * the hint keeps working offline; past the window the registry is consulted\n * again and the attempt time is refreshed either way.\n */\nexport async function checkForUpdate(options: {\n currentVersion: string\n now: number\n store: UpdateCheckStore\n fetchImpl?: typeof fetch\n}): Promise<string | undefined> {\n const { currentVersion, now, store } = options\n const hintOf = (version: string | undefined): string | undefined =>\n version !== undefined && isNewerVersion(version, currentVersion) ? version : undefined\n\n const cache = store.read()\n if (cache !== undefined && now - cache.at < UPDATE_CHECK_INTERVAL_MS) {\n return hintOf(cache.version)\n }\n\n let learned: string | undefined\n try {\n learned = await fetchLatestVersion(options.fetchImpl)\n } catch {\n // Degrade silently: record the attempt below and fall back to the cache.\n }\n const version = learned ?? cache?.version\n store.write({ at: now, version })\n return hintOf(version)\n}\n","/**\n * React component for the \"Command Code\" settings page (browser half).\n *\n * Renders as a `settings.section` entry — a page at the same settings-nav\n * level as General / Models / Plugins. The shell supplies the nav row and\n * renders this body inside the content column. All copy comes from the\n * `settings.commandcode` locale namespace; all state comes from the\n * `CommandCodeSettingsController` injected by the slot registration.\n *\n * Layout, top to bottom:\n * 1. Accounts — one card per account with its status, quota, actions and\n * dedicated models. Every account operation commits immediately.\n * 2. Models — the plan filter and the visible-model allowlist.\n * 3. Privacy & security — zero data retention and the command guard.\n * 4. Integrations & display — web search and the sidebar quota card.\n * 5. Advanced (collapsed) — API base and the network limits.\n * Sections 2–5 are flat groups of rows (title and description left, control\n * right, as on the harness's own settings pages), a staged form written by\n * the floating save bar.\n *\n * Styles are injected once by the client entry (see src/client/index.ts) and\n * class-prefixed `cc-` to stay local.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { Button, Menu } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { MenuEntry } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { CommandCodeCredits } from '../adapter.ts'\nimport type { CommandCodeAccountUsage, CommandCodeUsageReport } from '../usage-wire.ts'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport type { CatalogModelOption, SettingsPageState, StagedField } from './settings.ts'\nimport { COMMAND_GUARD_DEFAULT_LEVEL_CHOICE } from './settings.ts'\nimport type { LoginPageState } from './login.ts'\nimport { loginHint, loginStateForTarget } from './login.ts'\nimport { buildModelSelectOptions, catalogIsReady, groupModelSelectOptions, staleModelIds, tierHeadingFor, toggleModelSelection } from './model-select.ts'\nimport type { UsagePageState } from './usage.ts'\nimport { usageCardState, formatMoney, formatMoneyExact, formatResetAt, formatSuccessRate, formatTokensCompact, windowRatio } from './usage.ts'\nimport { PLUGIN_RELEASES_URL, PLUGIN_VERSION } from './version.ts'\nimport { checkForUpdate, localStorageUpdateStore } from './update.ts'\n\n/** Props composed by the slot registration: locale seat + injected face. */\nexport interface CommandCodeSettingsProps {\n t: Translate<SettingsCommandCodeKey>\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n useCommandCodeUsage<T>(selector: (state: UsagePageState) => T): T\n useCommandCodeLogin<T>(selector: (state: LoginPageState) => T): T\n edit(field: string, text: string): void\n resetField(field: string): void\n save(): void\n discard(): void\n refreshUsage(): void\n beginLogin(targetRef?: string): void\n cancelLogin(): void\n createAccount(input: { label: string; key?: string }): Promise<string | undefined>\n renameAccount(ref: string, label: string): Promise<boolean>\n removeAccount(ref: string): Promise<boolean>\n setAccountKey(target: string, key: string): Promise<boolean>\n clearAccountKey(target: string): Promise<boolean>\n setActiveAccount(id: string): Promise<boolean>\n setAccountModels(target: string, ids: string[]): Promise<boolean>\n editVisibleModels(ids: string[]): void\n clearVisibleModels(): void\n}\n\n/** The section fields folded into the collapsible Advanced card. */\ntype AdvancedField = 'apiBase' | 'requestTimeoutMs' | 'streamIdleTimeoutMs' | 'transportMaxRetries'\nconst ADVANCED_FIELDS: readonly AdvancedField[] = [\n 'apiBase',\n 'requestTimeoutMs',\n 'streamIdleTimeoutMs',\n 'transportMaxRetries',\n]\n\n/** The \"customized\" tag and reset link a staged field shows once it differs from the default. */\nfunction FieldOverride({ label, state, disabled, t, onReset }: {\n label: string\n state: StagedField\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onReset(): void\n}) {\n if (!state.overridden && !state.clear) return null\n return (\n <button type=\"button\" className=\"cc-linkButton\" disabled={disabled} onClick={onReset} aria-label={`${label} — ${t('reset')}`}>\n {t('reset')}\n </button>\n )\n}\n\n/**\n * One settings row, laid out like the harness's own General page: the title\n * and description on the left, the control on the right, a hairline between\n * rows.\n */\nfunction SettingRow({ title, titleFor, titleId, tag, description, error, control, className }: {\n title: string\n /** Makes the title a `<label>` for this control id. */\n titleFor?: string\n titleId?: string\n tag?: ReactNode\n description?: ReactNode\n /** Replaces the description while set. */\n error?: string | undefined\n control?: ReactNode\n className?: string\n}) {\n return (\n <div className={className === undefined ? 'cc-row' : `cc-row ${className}`}>\n <div className=\"cc-rowText\">\n <div className=\"cc-rowTitleLine\">\n {titleFor !== undefined\n ? <label className=\"cc-rowTitle\" id={titleId} htmlFor={titleFor}>{title}</label>\n : <span className=\"cc-rowTitle\" id={titleId}>{title}</span>}\n {tag}\n </div>\n {error !== undefined ? <p className=\"cc-rowError\">{error}</p> : null}\n {error === undefined && description !== undefined ? <div className=\"cc-rowDesc\">{description}</div> : null}\n </div>\n {control !== undefined ? <div className=\"cc-rowControl\">{control}</div> : null}\n </div>\n )\n}\n\n/** The tag a row title carries while its field overrides the default. */\nfunction OverrideTag({ state, t }: { state: StagedField; t: Translate<SettingsCommandCodeKey> }) {\n return state.overridden ? <span className=\"cc-badge\">{t('overridden')}</span> : null\n}\n\n/** One text/number field row. */\nfunction Field({\n id,\n label,\n hint,\n state,\n disabled,\n numeric,\n wide,\n placeholder,\n onEdit,\n onReset,\n t,\n}: {\n id: string\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n numeric?: boolean\n /** A wider input for URLs. */\n wide?: boolean\n placeholder?: string | undefined\n onEdit(text: string): void\n onReset(): void\n t: Translate<SettingsCommandCodeKey>\n}) {\n return (\n <SettingRow\n title={label}\n titleFor={id}\n tag={<OverrideTag state={state} t={t} />}\n description={hint}\n error={state.invalid ? invalidCopy(state.invalidReason, t) : undefined}\n control={\n <>\n <FieldOverride label={label} state={state} disabled={disabled} t={t} onReset={onReset} />\n <input\n id={id}\n className={`cc-input ${wide ? 'cc-rowInputWide' : 'cc-rowInput'}${state.invalid ? ' cc-inputInvalid' : ''}`}\n type=\"text\"\n inputMode={numeric ? 'numeric' : undefined}\n aria-invalid={state.invalid || undefined}\n value={state.text}\n placeholder={placeholder}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.value)}\n />\n </>\n }\n />\n )\n}\n\n/** The per-field error copy for a staged draft's failure reason. */\nfunction invalidCopy(reason: StagedField['invalidReason'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'tooSmall') return t('numberTooSmall')\n if (reason === 'tooLarge') return t('numberTooLarge')\n return t('invalidNumber')\n}\n\n/**\n * One boolean field row rendered as a switch. The staged text is `'true'` /\n * `'false'` / `''` (unset → `defaultChecked`); toggling stages the string the\n * boolean field spec parses back into a real boolean on save.\n */\nfunction ToggleField({\n id,\n label,\n hint,\n state,\n disabled,\n defaultChecked,\n onEdit,\n onReset,\n t,\n}: {\n id: string\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n defaultChecked: boolean\n onEdit(text: string): void\n onReset(): void\n t: Translate<SettingsCommandCodeKey>\n}) {\n const checked = state.text === '' ? defaultChecked : state.text === 'true'\n return (\n <SettingRow\n title={label}\n titleFor={id}\n tag={<OverrideTag state={state} t={t} />}\n description={hint}\n control={\n <>\n <FieldOverride label={label} state={state} disabled={disabled} t={t} onReset={onReset} />\n <input\n id={id}\n className=\"cc-toggle\"\n type=\"checkbox\"\n role=\"switch\"\n checked={checked}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.checked ? 'true' : 'false')}\n />\n </>\n }\n />\n )\n}\n\n/**\n * One fixed-choice field rendered as a segmented control. The staged text is\n * one of `options`' values or `''` (unset → `defaultValue`); picking the\n * default while unset stages nothing new.\n */\nfunction SegmentedField({\n label,\n hint,\n state,\n disabled,\n options,\n defaultValue,\n className,\n onEdit,\n onReset,\n t,\n}: {\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n options: ReadonlyArray<{ value: string; label: string }>\n defaultValue: string\n className?: string\n onEdit(text: string): void\n onReset(): void\n t: Translate<SettingsCommandCodeKey>\n}) {\n const current = state.text === '' ? defaultValue : state.text\n const index = Math.max(0, options.findIndex((option) => option.value === current))\n return (\n <SettingRow\n title={label}\n tag={<OverrideTag state={state} t={t} />}\n description={hint}\n {...(className === undefined ? {} : { className })}\n control={\n <>\n <FieldOverride label={label} state={state} disabled={disabled} t={t} onReset={onReset} />\n {/* The indicator is placed arithmetically from the count and the\n picked index (the platform SegmentedControl's technique), so it\n can slide without measuring the DOM. */}\n <div\n className=\"cc-segmented\"\n role=\"radiogroup\"\n aria-label={label}\n style={{ '--cc-segment-count': options.length, '--cc-segment-index': index } as CSSProperties}\n >\n <span className=\"cc-segmentIndicator\" aria-hidden=\"true\" />\n {options.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={current === option.value}\n className=\"cc-segment\"\n disabled={disabled}\n onClick={() => {\n if (current !== option.value) onEdit(option.value)\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n </>\n }\n />\n )\n}\n\n/** One stat tile in the account card's summary grid. */\nfunction UsageStat({ label, value, sub }: { label: string; value: string; sub?: string | undefined }) {\n return (\n <div className=\"cc-usageStat\">\n <span className=\"cc-usageStatLabel\">{label}</span>\n <span className=\"cc-usageStatValue\">{value}</span>\n {sub !== undefined && sub !== '' ? <span className=\"cc-usageStatSub\">{sub}</span> : null}\n </div>\n )\n}\n\n/** One window-limit row: label, used/cap, a fill bar, and the reset time. */\nfunction UsageWindow({\n label,\n limit,\n t,\n}: {\n label: string\n limit: NonNullable<CommandCodeCredits['fiveHour']>\n t: Translate<SettingsCommandCodeKey>\n}) {\n const { used, cap, exceeded, resetAt } = limit\n const ratio = windowRatio(used, cap)\n const reset = formatResetAt(resetAt)\n return (\n <div className=\"cc-usageWindow\">\n <div className=\"cc-usageWindowHead\">\n <span className=\"cc-usageWindowLabel\">{label}</span>\n {exceeded ? <span className=\"cc-usageExceeded\">{t('usageExceeded')}</span> : null}\n <span className=\"cc-usageWindowValue\">{cap > 0 ? `${formatMoney(used)} / ${formatMoney(cap)}` : formatMoney(used)}</span>\n </div>\n <div className=\"cc-usageBar\" role=\"progressbar\" aria-label={label} aria-valuemin={0} aria-valuemax={100} aria-valuenow={Math.round(ratio * 100)}>\n <div className={exceeded ? 'cc-usageBarFill cc-usageBarFillWarn' : 'cc-usageBarFill'} style={{ width: `${ratio * 100}%` }} />\n </div>\n {reset !== '' ? <p className=\"cc-usageWindowReset\">{t('usageReset')} {reset}</p> : null}\n </div>\n )\n}\n\n/**\n * One pool account's facts (identity, totals, credits, window limits)\n * rendered inside an account row's details.\n */\nfunction AccountReport({ entry, fetchedAt, t, summaryOnly = false, headless = false }: {\n entry: CommandCodeAccountUsage\n /**\n * When the shared usage snapshot was fetched — shares the account's bottom\n * meta row with the billing period end so the two timestamps occupy one\n * line (period/partial facts left, fetch freshness right).\n */\n fetchedAt?: number | undefined\n t: Translate<SettingsCommandCodeKey>\n /** Collapsed card mode: identity, errors and quota windows without the stat grids. */\n summaryOnly?: boolean\n /** Omit the identity header (the account row already shows it). */\n headless?: boolean\n}) {\n const report = entry.report\n const account = report.account\n const accountName = account === undefined ? '' : account.userName || account.name\n const credits = report.credits\n const plan = report.plan\n const planName = plan?.name ?? ''\n const planStatus = plan !== undefined && plan.status !== '' && plan.status !== 'active' ? plan.status : ''\n const showPeriod = plan !== undefined && plan.currentPeriodEnd > 0\n const showPartial = report.failures.length > 0 && report.blocked === undefined\n\n return (\n <div className=\"cc-accountReport\">\n {!headless ? (\n <div className=\"cc-usageHead\">\n <h4 className=\"cc-usageTitle\">{entry.label}</h4>\n {accountName !== '' ? <span className=\"cc-usageAccount\">{accountName}</span> : null}\n {planName !== '' ? <span className=\"cc-usagePlan\">{planName}</span> : null}\n </div>\n ) : null}\n {planStatus !== '' ? <p className=\"cc-usagePlanStatus\">{planStatus}</p> : null}\n\n {!entry.configured ? <p className=\"cc-usageHint\">{t('usageUnconfigured')}</p> : null}\n\n {report.blocked !== undefined ? (\n <div className=\"cc-usageBlocked\" role=\"alert\">\n <p className=\"cc-usageBlockedTitle\">{blockedTitle(report.blocked, t)}</p>\n <p className=\"cc-usageBlockedHint\">{blockedHint(report.blocked, t)}</p>\n {/* Keep the per-endpoint failures visible alongside the summary:\n they carry the actual status or transport error for diagnosis. */}\n {report.failures.length > 0 ? (\n <p className=\"cc-usageBlockedDetail\" title={report.failures.join('; ')}>\n {report.failures.join(' · ')}\n </p>\n ) : null}\n </div>\n ) : null}\n\n {!summaryOnly && report.usage !== undefined ? (\n <div className=\"cc-usageStats cc-usageStatsActivity\">\n <UsageStat\n label={t('usageRequests')}\n value={String(report.usage.completedCount)}\n sub={`${t('usageFailed')} ${report.usage.failedCount}`}\n />\n <UsageStat label={t('usageSuccessRate')} value={`${formatSuccessRate(report.usage.successRate)}%`} />\n <UsageStat\n label={t('usageCost')}\n value={formatMoneyExact(report.usage.totalCost)}\n sub={`${formatMoney(report.usage.totalCredits)} credits`}\n />\n <UsageStat\n label={t('usageTokens')}\n value={formatTokensCompact(report.usage.totalTokensIn + report.usage.totalTokensOut)}\n sub={`${formatTokensCompact(report.usage.totalTokensIn)} ${t('usageTokensIn')} / ${formatTokensCompact(report.usage.totalTokensOut)} ${t('usageTokensOut')}`}\n />\n </div>\n ) : null}\n\n {!summaryOnly && credits !== undefined ? (\n <div className=\"cc-usageStats cc-usageStatsBalance\">\n <UsageStat label={t('usageMonthly')} value={credits.monthlyReported === false ? '—' : formatMoney(credits.monthlyCredits)} />\n <UsageStat label={t('usagePurchased')} value={credits.purchasedReported === false ? '—' : formatMoney(credits.purchasedCredits)} />\n <UsageStat label={t('usageFree')} value={credits.freeReported === false ? '—' : formatMoney(credits.freeCredits)} />\n </div>\n ) : null}\n\n {credits?.fiveHour !== undefined || credits?.weekly !== undefined ? (\n <div className=\"cc-usageWindows\">\n {credits.fiveHour !== undefined ? (\n <UsageWindow label={t('usageFiveHour')} limit={credits.fiveHour} t={t} />\n ) : null}\n {credits.weekly !== undefined ? (\n <UsageWindow label={t('usageWeekly')} limit={credits.weekly} t={t} />\n ) : null}\n </div>\n ) : null}\n\n {showPeriod || showPartial || fetchedAt !== undefined ? (\n <div className=\"cc-usageMeta\">\n {showPeriod ? (\n <p className=\"cc-usageUpdated\">{t('usagePeriodEnd')} {new Date(plan.currentPeriodEnd).toLocaleDateString()}</p>\n ) : null}\n {showPartial ? (\n <p className=\"cc-usagePartial\" title={report.failures.join('; ')}>{t('usagePartial')}</p>\n ) : null}\n <span className=\"cc-usageMetaSpacer\" />\n {fetchedAt !== undefined ? (\n <p className=\"cc-usageUpdated\">{t('usageUpdated')} {new Date(fetchedAt).toLocaleTimeString()}</p>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n\n/** The headline copy for a report whose every endpoint failed the same way. */\nfunction blockedTitle(reason: CommandCodeUsageReport['blocked'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'invalid-key') return t('usageKeyInvalid')\n if (reason === 'service-unavailable') return t('usageServiceUnavailable')\n if (reason === 'invalid-response') return t('usageInvalidResponse')\n return t('usageNetworkError')\n}\n\n/** The actionable hint under a blocked report's headline. */\nfunction blockedHint(reason: CommandCodeUsageReport['blocked'], t: Translate<SettingsCommandCodeKey>): string {\n if (reason === 'invalid-key') return t('usageKeyInvalidHint')\n if (reason === 'service-unavailable') return t('usageServiceUnavailableHint')\n if (reason === 'invalid-response') return t('usageInvalidResponseHint')\n return t('usageNetworkHint')\n}\n\n/**\n * A checkbox multi-select dropdown for picking catalog models (the\n * routing-rule rows and the visible-models filter share it). The trigger\n * shows the selection count; the Menu lists every catalog model with a\n * checkbox, toggled by clicking the row. A search box under the trigger\n * (inside the Menu anchor, so focusing it never trips the outside-click\n * close) filters the list by id/display-name substring, and items group\n * under plan-tier headings in picker order. Selected ids the catalog no\n * longer carries still render — flagged stale — so a saved selection never\n * silently loses an entry, and the VisibleModelsCard offers a one-click\n * cleanup.\n *\n * With `deferCommit` the toggles collect in a local draft that is handed to\n * `onSelect` once, when the menu closes: the per-account picker writes\n * immediately, and one write per click would be a burst of document writes.\n */\nfunction ModelMultiSelect({ id, selected: committed, catalog, disabled, deferCommit = false, ownerOf, t, onSelect }: {\n id: string\n selected: string[]\n catalog: CatalogModelOption[]\n disabled: boolean\n deferCommit?: boolean\n /** Names the other account a model currently belongs to, if any. */\n ownerOf?: (modelId: string) => string | undefined\n t: Translate<SettingsCommandCodeKey>\n onSelect(ids: string[]): void\n}) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n const [draft, setDraft] = useState<string[] | undefined>(undefined)\n const selected = draft ?? committed\n // The search box must not inherit a stale query from a previous open.\n useEffect(() => {\n if (open) setQuery('')\n }, [open])\n const close = () => {\n setOpen(false)\n if (draft !== undefined) {\n setDraft(undefined)\n const changed = draft.length !== committed.length || draft.some((modelId) => !committed.includes(modelId))\n if (changed) onSelect(draft)\n }\n }\n // Tier headings come from the catalog entries themselves (the Host stamps\n // each entry's plan-tier key on the Remote); rebuild only when the catalog\n // changes.\n const tiers = useMemo(\n () => Object.fromEntries(\n catalog.flatMap((model) => model.tier === undefined ? [] : [[model.id, model.tier] as const]),\n ),\n [catalog],\n )\n // The catalog is sorted for picking; append any selected ids the catalog no\n // longer carries (removed upstream) so the current selection stays visible.\n const options = buildModelSelectOptions(catalog, selected, query)\n const groups = groupModelSelectOptions(options, (modelId) => tierHeadingFor(modelId, tiers))\n const items: MenuEntry[] = groups.flatMap((group) => [\n ...(group.heading === undefined\n ? []\n : [{ type: 'label' as const, id: `cc-tier-${group.heading}`, text: group.heading }]),\n ...group.options.map((option) => ({\n id: option.value,\n label: (\n <span className=\"cc-checkRow\">\n <input\n type=\"checkbox\"\n className=\"cc-check\"\n checked={selected.includes(option.value)}\n readOnly\n tabIndex={-1}\n />\n <span className=\"cc-checkName\">{option.label}</span>\n {option.stale ? <span className=\"cc-badge\">{t('modelStale')}</span> : null}\n {!selected.includes(option.value) && ownerOf?.(option.value) !== undefined ? (\n <span className=\"cc-badgeMuted\">{t('accountModelOwner', { name: ownerOf(option.value)! })}</span>\n ) : null}\n </span>\n ),\n })),\n ])\n // The search box lives INSIDE the Menu anchor (which renders in place\n // inside the Menu's root span): a pointerdown there counts as \"inside\",\n // so focusing/typing never trips the Menu's outside-click close. A box\n // rendered as a sibling would close the Menu on the first click.\n return (\n <Menu\n open={open}\n onClose={close}\n onSelect={(modelId) => {\n const next = toggleModelSelection(selected, modelId)\n if (deferCommit) setDraft(next)\n else onSelect(next)\n }}\n selectedIds={selected}\n items={items}\n footer={options.length === 0 ? [{\n type: 'label' as const,\n id: 'cc-model-search-empty',\n text: t('modelSearchEmpty'),\n }] : []}\n portal\n anchor={\n <span className=\"cc-modelSelectAnchor\">\n <button\n id={id}\n type=\"button\"\n className=\"cc-selector\"\n disabled={disabled || catalog.length === 0}\n onClick={() => (open ? close() : setOpen(true))}\n >\n <span className=\"cc-selectorText\">\n {selected.length === 0 ? t('modelPick') : t('modelCount', { count: selected.length })}\n </span>\n <span className=\"cc-selectorCaret\" aria-hidden=\"true\" />\n </button>\n {open ? (\n <input\n type=\"search\"\n className=\"cc-input cc-modelSearch\"\n placeholder={t('modelSearchPlaceholder')}\n aria-label={t('modelSearchPlaceholder')}\n value={query}\n disabled={disabled}\n autoFocus\n onChange={(event) => setQuery(event.target.value)}\n />\n ) : null}\n </span>\n }\n />\n )\n}\n\n/** The visible-model filter row: an allowlist over the catalog. Empty = show all. */\nfunction VisibleModelsRow({ t, state, disabled, onSelect, onClear }: {\n t: Translate<SettingsCommandCodeKey>\n state: SettingsPageState\n disabled: boolean\n onSelect(ids: string[]): void\n onClear(): void\n}) {\n const count = state.visibleModels.length\n const pickT: Translate<SettingsCommandCodeKey> = (key, params) => {\n if (key === 'modelPick') return t('visibleModelsPick')\n if (key === 'modelCount') return t('visibleModelsCount', params)\n return t(key, params)\n }\n // Selected ids the live catalog no longer carries (retired upstream):\n // kept, flagged stale in the dropdown, removable in one click. Never\n // auto-dropped — an empty catalog (fetch failure) must not wipe the list.\n // \"Stale\" is only meaningful against a catalog we actually hold, so both the\n // cleanup button and its hint are gated on catalogIsReady: before the first\n // fetch lands (and after a failure) the empty catalog makes every selection\n // look retired, turning the one-click cleanup into a button that silently\n // empties the allowlist. The explicit \"show all\" entry stays available\n // either way — clearing the list is then the user's stated intent rather\n // than an inference from missing data.\n const readiness = { catalogIds: state.catalogModels.map((model) => model.id), catalogFailed: state.catalogFailed }\n const staleIds = staleModelIds(state.visibleModels, readiness)\n const catalogReady = catalogIsReady(readiness)\n return (\n <SettingRow\n title={t('visibleModelsTitle')}\n titleFor=\"cc-visible-models\"\n description={\n <>\n <p>{t('visibleModelsHint')}</p>\n {staleIds.length > 0 && catalogReady ? <p>{t('visibleModelsStaleHint', { count: staleIds.length })}</p> : null}\n </>\n }\n error={state.catalogFailed ? t('modelCatalogFailed') : undefined}\n control={\n <>\n {catalogReady && staleIds.length > 0 ? (\n <button\n type=\"button\"\n className=\"cc-linkButton\"\n disabled={disabled}\n onClick={() => onSelect(state.visibleModels.filter((id) => !staleIds.includes(id)))}\n >\n {t('visibleModelsCleanStale', { count: staleIds.length })}\n </button>\n ) : null}\n {count > 0 ? (\n <button type=\"button\" className=\"cc-linkButton\" disabled={disabled} onClick={onClear}>\n {t('visibleModelsShowAll')}\n </button>\n ) : null}\n <ModelMultiSelect\n id=\"cc-visible-models\"\n selected={state.visibleModels}\n catalog={state.catalogModels}\n disabled={disabled}\n t={pickT}\n onSelect={onSelect}\n />\n </>\n }\n />\n )\n}\n\n/**\n * One titled group of rows. No card surface: like the harness's own settings\n * pages, a group is a heading over hairline-separated rows.\n */\nfunction SettingsGroup({ title, action, children }: { title: string; action?: ReactNode; children: ReactNode }) {\n return (\n <section className=\"cc-group\" aria-label={title}>\n <div className=\"cc-groupHead\">\n <h3 className=\"cc-groupTitle\">{title}</h3>\n {action}\n </div>\n <div className=\"cc-rows\">{children}</div>\n </section>\n )\n}\n\n/** The staged-field callbacks every form card shares. */\ninterface FormCardProps {\n state: SettingsPageState\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onEdit(field: string, text: string): void\n onReset(field: string): void\n}\n\n/**\n * Models: the plan filter and the allowlist sit together because both decide\n * what the model picker lists (the allowlist applies after the plan filter).\n */\nfunction ModelsCard({ state, disabled, t, onEdit, onReset, onSelect, onClear }: FormCardProps & {\n onSelect(ids: string[]): void\n onClear(): void\n}) {\n return (\n <SettingsGroup title={t('modelsTitle')}>\n <ToggleField\n id=\"cc-filter-models-by-plan\"\n label={t('filterModelsByPlan')}\n hint={t('filterModelsByPlanHint')}\n state={state.filterModelsByPlan}\n disabled={disabled}\n defaultChecked\n onEdit={(text) => onEdit('filterModelsByPlan', text)}\n onReset={() => onReset('filterModelsByPlan')}\n t={t}\n />\n <VisibleModelsRow t={t} state={state} disabled={disabled} onSelect={onSelect} onClear={onClear} />\n </SettingsGroup>\n )\n}\n\n/**\n * Privacy & security: the two opt-ins that change where data goes. ZDR\n * restricts which upstream serves a request; the command guard sends command\n * text to a decision model with no ZDR upstream and can skip an approval the\n * user would otherwise have seen, so both start off.\n */\nfunction PrivacyCard({ state, disabled, t, onEdit, onReset }: FormCardProps) {\n // Keep a customized level visible even after the staged guard switch is\n // turned off, otherwise a pending edit would disappear from the page while\n // still participating in Save.\n const showGuardLevel = state.commandGuard.text === 'true'\n || state.commandGuardLevel.overridden\n || state.commandGuardLevel.clear\n return (\n <SettingsGroup title={t('privacyTitle')}>\n <ToggleField\n id=\"cc-zdr\"\n label={t('zdr')}\n hint={t('zdrHint')}\n state={state.zdr}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('zdr', text)}\n onReset={() => onReset('zdr')}\n t={t}\n />\n <ToggleField\n id=\"cc-command-guard\"\n label={t('commandGuard')}\n hint={t('commandGuardHint')}\n state={state.commandGuard}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('commandGuard', text)}\n onReset={() => onReset('commandGuard')}\n t={t}\n />\n {showGuardLevel ? (\n <SegmentedField\n className=\"cc-rowNested\"\n label={t('commandGuardLevel')}\n hint={t('commandGuardLevelHint')}\n state={state.commandGuardLevel}\n disabled={disabled}\n options={[\n { value: 'high', label: t('commandGuardLevelHigh') },\n { value: 'medium', label: t('commandGuardLevelMedium') },\n { value: 'low', label: t('commandGuardLevelLow') },\n ]}\n defaultValue={COMMAND_GUARD_DEFAULT_LEVEL_CHOICE}\n onEdit={(text) => onEdit('commandGuardLevel', text)}\n onReset={() => onReset('commandGuardLevel')}\n t={t}\n />\n ) : null}\n </SettingsGroup>\n )\n}\n\n/** Integrations & display: surfaces outside chat that reuse this provider. */\nfunction IntegrationsCard({ state, disabled, t, onEdit, onReset }: FormCardProps) {\n return (\n <SettingsGroup title={t('integrationsTitle')}>\n <ToggleField\n id=\"cc-web-search\"\n label={t('webSearch')}\n hint={t('webSearchHint')}\n state={state.webSearch}\n disabled={disabled}\n defaultChecked\n onEdit={(text) => onEdit('webSearch', text)}\n onReset={() => onReset('webSearch')}\n t={t}\n />\n {/* Opt-in, and off by default: the sidebar quota card is a display\n surface, so an unset document shows nothing on the left. */}\n <ToggleField\n id=\"cc-show-sidebar-quota\"\n label={t('showSidebarQuota')}\n hint={t('showSidebarQuotaHint')}\n state={state.showSidebarQuota}\n disabled={disabled}\n defaultChecked={false}\n onEdit={(text) => onEdit('showSidebarQuota', text)}\n onReset={() => onReset('showSidebarQuota')}\n t={t}\n />\n </SettingsGroup>\n )\n}\n\n/**\n * The collapsed \"Advanced\" card: the API base and the network limits. Starts\n * collapsed on every visit; while collapsed, a badge names the customized\n * count and an invalid number (which blocks save) is surfaced on the header.\n */\nfunction AdvancedSection({ state, disabled, t, onEdit, onReset }: FormCardProps) {\n const [expanded, setExpanded] = useState(false)\n const overridden = ADVANCED_FIELDS.filter((field) => state[field].overridden).length\n const invalid = ADVANCED_FIELDS.some((field) => state[field].invalid)\n return (\n <section className=\"cc-group\" aria-label={t('advancedSettings')}>\n <button\n type=\"button\"\n className=\"cc-groupHead cc-disclosure\"\n aria-expanded={expanded}\n aria-controls=\"cc-advanced-body\"\n onClick={() => setExpanded((value) => !value)}\n >\n <span className=\"cc-groupTitle\">{t('advancedSettings')}</span>\n {overridden > 0 ? (\n <span className=\"cc-badge\">\n {overridden === 1 ? t('advancedOverriddenOne') : t('advancedOverriddenMany', { count: overridden })}\n </span>\n ) : null}\n {!expanded && invalid ? (\n <span className=\"cc-badge cc-badgeWarn\">{t('advancedInvalid')}</span>\n ) : null}\n <span className=\"cc-spacer\" />\n <span className={expanded ? 'cc-chevron cc-chevronUp' : 'cc-chevron'} aria-hidden=\"true\" />\n </button>\n {expanded ? (\n <div id=\"cc-advanced-body\" className=\"cc-rows\">\n <p className=\"cc-groupDesc\">{t('advancedSettingsHint')}</p>\n <Field\n id=\"cc-api-base\"\n label={t('apiBase')}\n hint={t('apiBaseHint')}\n state={state.apiBase}\n disabled={disabled}\n wide\n onEdit={(text) => onEdit('apiBase', text)}\n onReset={() => onReset('apiBase')}\n t={t}\n />\n <Field\n id=\"cc-request-timeout\"\n label={t('requestTimeoutMs')}\n hint={t('requestTimeoutMsHint')}\n state={state.requestTimeoutMs}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('requestTimeoutMs', text)}\n onReset={() => onReset('requestTimeoutMs')}\n t={t}\n />\n <Field\n id=\"cc-stream-idle-timeout\"\n label={t('streamIdleTimeoutMs')}\n hint={t('streamIdleTimeoutMsHint')}\n state={state.streamIdleTimeoutMs}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('streamIdleTimeoutMs', text)}\n onReset={() => onReset('streamIdleTimeoutMs')}\n t={t}\n />\n <Field\n id=\"cc-transport-max-retries\"\n label={t('transportMaxRetries')}\n hint={t('transportMaxRetriesHint')}\n state={state.transportMaxRetries}\n disabled={disabled}\n numeric\n onEdit={(text) => onEdit('transportMaxRetries', text)}\n onReset={() => onReset('transportMaxRetries')}\n t={t}\n />\n </div>\n ) : null}\n {expanded && invalid ? (\n <p className=\"cc-rowError\" role=\"status\">{t('advancedInvalid')}</p>\n ) : null}\n </section>\n )\n}\n\n/** One row of the unified account list: a stored account merged with its usage entry. */\ninterface AccountRowModel {\n /** Slot id: `default` or the extra account's credential reference. */\n id: string\n label: string\n /** Credential reference for extra accounts; undefined for the default slot. */\n ref: string | undefined\n isDefault: boolean\n /** Whether this page can manage the row (false for literal-only composition entries). */\n managed: boolean\n /** Whether a key resolves for this account (stored credential or a Host-side source). */\n configured: boolean\n /** Whether a stored credential exists this page could delete. */\n storedKey: boolean\n keyWritable: boolean\n usage: CommandCodeAccountUsage | undefined\n}\n\n/**\n * Merge the controller's accounts with the usage report. The default slot is\n * always first; report entries this page cannot manage (literal keys from the\n * composition config) still render, read-only, so the list names every\n * account the pool rotates through.\n */\nfunction accountRows(state: SettingsPageState, usage: UsagePageState, t: Translate<SettingsCommandCodeKey>): AccountRowModel[] {\n const report = new Map((usage.report?.accounts ?? []).map((entry) => [entry.id, entry]))\n const defaultUsage = report.get('default')\n const rows: AccountRowModel[] = [{\n id: 'default',\n label: t('accountDefault'),\n ref: undefined,\n isDefault: true,\n managed: true,\n configured: state.apiKeyConfigured || defaultUsage?.configured === true,\n storedKey: state.apiKeyConfigured,\n keyWritable: state.apiKeyWritable,\n usage: defaultUsage,\n }]\n for (const account of state.accounts) {\n const entry = report.get(account.id)\n rows.push({\n id: account.id,\n label: account.label,\n ref: account.ref,\n isDefault: false,\n managed: true,\n configured: account.configured || entry?.configured === true,\n storedKey: account.configured,\n keyWritable: account.writable,\n usage: entry,\n })\n }\n const known = new Set(rows.map((row) => row.id))\n for (const entry of usage.report?.accounts ?? []) {\n if (known.has(entry.id)) continue\n known.add(entry.id)\n rows.push({\n id: entry.id,\n label: entry.label,\n ref: undefined,\n isDefault: false,\n managed: false,\n configured: entry.configured,\n storedKey: false,\n keyWritable: false,\n usage: entry,\n })\n }\n return rows\n}\n\n/** The row's status dot: error for a rejected key, warning while cooling down. */\nfunction statusDotClass(row: AccountRowModel): string {\n const entry = row.usage\n if (!row.configured || entry?.mark === 'invalid-credential') return 'cc-tabDot cc-tabDotError'\n if (entry !== undefined && (entry.mark !== '' || entry.cooldownUntil > 0)) return 'cc-tabDot cc-tabDotWarn'\n return 'cc-tabDot cc-tabDotOk'\n}\n\n/** One compact quota meter for a row's summary line. */\nfunction MiniMeter({ label, limit }: { label: string; limit: NonNullable<CommandCodeCredits['fiveHour']> }) {\n const ratio = windowRatio(limit.used, limit.cap)\n const percent = limit.cap > 0 ? `${Math.round(ratio * 100)}%` : formatMoney(limit.used)\n return (\n <span className=\"cc-miniMeter\" title={limit.cap > 0 ? `${formatMoney(limit.used)} / ${formatMoney(limit.cap)}` : undefined}>\n <span className=\"cc-miniMeterLabel\">{label}</span>\n <span className=\"cc-miniMeterTrack\" aria-hidden=\"true\">\n <span className={limit.exceeded ? 'cc-miniMeterFill cc-usageBarFillWarn' : 'cc-miniMeterFill'} style={{ width: `${ratio * 100}%` }} />\n </span>\n <span className=\"cc-miniMeterValue\">{percent}</span>\n </span>\n )\n}\n\n/**\n * The monthly credit balance for a row's summary line: the billing endpoint's\n * `monthlyCredits` is what is LEFT, shown as the amount alone.\n */\nfunction MonthlyBalance({ label, remaining }: { label: string; remaining: number }) {\n return (\n <span className=\"cc-miniMeter\">\n <span className=\"cc-miniMeterLabel\">{label}</span>\n <span className=\"cc-miniMeterValue\">{formatMoney(Math.max(0, remaining))}</span>\n </span>\n )\n}\n\n/** A single-input inline form (paste key, rename) with confirm/cancel. */\nfunction InlineInput({ id, label, secret, initial, placeholder, confirmLabel, disabled, t, onSubmit, onCancel }: {\n id: string\n label: string\n secret?: boolean\n initial?: string\n placeholder?: string\n confirmLabel: string\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onSubmit(value: string): void\n onCancel(): void\n}) {\n const [value, setValue] = useState(initial ?? '')\n const [visible, setVisible] = useState(false)\n const ready = value.trim() !== ''\n return (\n <form\n className=\"cc-inlineForm\"\n onSubmit={(event) => {\n event.preventDefault()\n if (ready && !disabled) onSubmit(value)\n }}\n >\n <input\n id={id}\n className=\"cc-input\"\n type={secret && !visible ? 'password' : 'text'}\n aria-label={label}\n autoComplete=\"off\"\n spellCheck={false}\n autoFocus\n placeholder={placeholder}\n value={value}\n disabled={disabled}\n onChange={(event) => setValue(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Escape') onCancel()\n }}\n />\n <div className=\"cc-inlineActions\">\n {secret && value !== '' ? (\n <button type=\"button\" className=\"cc-reset\" onClick={() => setVisible((shown) => !shown)}>\n {visible ? t('hide') : t('show')}\n </button>\n ) : null}\n <span className=\"cc-spacer\" />\n <Button variant=\"ghost\" size=\"sm\" type=\"button\" onClick={onCancel}>{t('cancel')}</Button>\n <Button variant=\"primary\" size=\"sm\" type=\"submit\" disabled={!ready || disabled}>{confirmLabel}</Button>\n </div>\n </form>\n )\n}\n\n/** A destructive confirmation bar shown in place of a menu action. */\nfunction ConfirmBar({ text, confirmLabel, disabled, t, onConfirm, onCancel }: {\n text: string\n confirmLabel: string\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onConfirm(): void\n onCancel(): void\n}) {\n return (\n <div className=\"cc-confirmBar\" role=\"alertdialog\" aria-label={text}>\n <p className=\"cc-confirmText\">{text}</p>\n <div className=\"cc-inlineActions\">\n <span className=\"cc-spacer\" />\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel}>{t('cancel')}</Button>\n <Button variant=\"outline\" size=\"sm\" className=\"cc-dangerButton\" disabled={disabled} onClick={onConfirm}>{confirmLabel}</Button>\n </div>\n </div>\n )\n}\n\ntype RowMode = 'key' | 'rename' | 'remove' | 'clearKey' | undefined\n\n/** One account row: identity, status, quota summary, actions and expandable details. */\nfunction AccountItem({ row, rows, state, usage, login, disabled, pinned, t, actions }: {\n row: AccountRowModel\n rows: readonly AccountRowModel[]\n state: SettingsPageState\n usage: UsagePageState\n login: LoginPageState\n disabled: boolean\n pinned: boolean\n t: Translate<SettingsCommandCodeKey>\n actions: AccountActions\n}) {\n const [expanded, setExpanded] = useState(false)\n const [menuOpen, setMenuOpen] = useState(false)\n const [mode, setMode] = useState<RowMode>(undefined)\n const entry = row.usage\n const report = entry?.report\n const accountName = report?.account === undefined ? '' : report.account.userName || report.account.name\n const planName = report?.plan?.name ?? ''\n const credits = report?.credits\n // Only an explicit `false` means the balance was omitted (an older Host\n // never sends the flag and always sent a real number).\n const monthlyReported = credits !== undefined && credits.monthlyReported !== false\n const multi = rows.length > 1\n const loginTarget = row.ref\n const { visible: loginState, busyElsewhere } = loginStateForTarget(login, loginTarget)\n const loginBusy = loginState.phase === 'starting' || loginState.phase === 'waiting'\n const showLogin = loginState.phase !== 'idle'\n const locked = disabled || !row.managed\n const keyActions = !locked && row.keyWritable\n\n const items: MenuEntry[] = []\n if (row.managed && multi) {\n items.push(pinned\n ? { id: 'unpin', label: t('accountActionUnpin'), disabled: locked }\n : { id: 'pin', label: t('accountActionPin'), disabled: locked || !row.configured })\n }\n if (row.managed) {\n if (items.length > 0) items.push({ type: 'separator', id: 'sep-key' })\n items.push(\n { id: 'login', label: t('accountActionLogin'), disabled: !keyActions || loginBusy || busyElsewhere },\n { id: 'key', label: t('accountActionKey'), disabled: !keyActions },\n )\n if (!row.isDefault) items.push({ id: 'rename', label: t('accountActionRename'), disabled: locked })\n if (row.isDefault && row.storedKey) {\n items.push(\n { type: 'separator', id: 'sep-danger' },\n { id: 'clearKey', label: t('accountActionClearKey'), disabled: !keyActions, danger: true },\n )\n }\n if (!row.isDefault) {\n items.push(\n { type: 'separator', id: 'sep-danger' },\n { id: 'remove', label: t('accountActionRemove'), disabled: locked, danger: true },\n )\n }\n }\n\n const onAction = (id: string) => {\n setMenuOpen(false)\n if (id === 'pin') void actions.setActive(row.id)\n else if (id === 'unpin') void actions.setActive('')\n else if (id === 'login') actions.beginLogin(loginTarget)\n else if (id === 'key' || id === 'rename' || id === 'remove' || id === 'clearKey') setMode(id)\n }\n\n const models = state.accountModels[row.id] ?? []\n const ownerOf = (modelId: string): string | undefined => {\n for (const [account, list] of Object.entries(state.accountModels)) {\n if (account === row.id || !list.includes(modelId)) continue\n return rows.find((candidate) => candidate.id === account)?.label ?? account\n }\n return undefined\n }\n\n return (\n <div className={row.usage?.active ? 'cc-accountItem cc-accountItemActive' : 'cc-accountItem'}>\n <div className=\"cc-accountHead\">\n <button\n type=\"button\"\n className=\"cc-accountToggle\"\n aria-expanded={expanded}\n aria-controls={`cc-account-${row.id}-details`}\n onClick={() => setExpanded((value) => !value)}\n >\n <span className={statusDotClass(row)} aria-hidden=\"true\" />\n <span className=\"cc-accountName\">{row.label}</span>\n {accountName !== '' && accountName !== row.label ? <span className=\"cc-usageAccount\">{accountName}</span> : null}\n {planName !== '' ? <span className=\"cc-usagePlan\">{planName}</span> : null}\n {entry?.active && multi ? <span className=\"cc-badge\">{t('usageActive')}</span> : null}\n {pinned ? <span className=\"cc-badge\">{t('accountStatusPinned')}</span> : null}\n {!row.configured ? <span className=\"cc-badgeMuted\">{t('apiKeyUnset')}</span> : null}\n {entry?.mark === 'invalid-credential' ? <span className=\"cc-usagePlanStatus\">{t('usageInvalidKey')}</span> : null}\n {entry !== undefined && entry.mark !== 'invalid-credential' && (entry.cooldownUntil > 0 || entry.mark === 'rate-limit') ? (\n <span className=\"cc-usagePlanStatus\">\n {t('usageCooldown')}{entry.cooldownUntil > 0 ? ` ${formatResetAt(entry.cooldownUntil)}` : ''}\n </span>\n ) : null}\n <span className=\"cc-spacer\" />\n <span className={expanded ? 'cc-chevron cc-chevronUp' : 'cc-chevron'} aria-hidden=\"true\" />\n </button>\n {items.length > 0 ? (\n <Menu\n open={menuOpen}\n onClose={() => setMenuOpen(false)}\n onSelect={onAction}\n items={items}\n align=\"end\"\n portal\n anchor={\n <button\n type=\"button\"\n className=\"cc-iconButton\"\n aria-label={`${row.label} — ${t('accountActions')}`}\n title={t('accountActions')}\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n onClick={() => setMenuOpen((value) => !value)}\n >\n <span className=\"cc-kebab\" aria-hidden=\"true\" />\n </button>\n }\n />\n ) : null}\n </div>\n\n {credits !== undefined && (credits.fiveHour !== undefined || credits.weekly !== undefined || monthlyReported) ? (\n <div className=\"cc-accountMeters\">\n {credits.fiveHour !== undefined ? <MiniMeter label={t('usageFiveHour')} limit={credits.fiveHour} /> : null}\n {credits.weekly !== undefined ? <MiniMeter label={t('usageWeekly')} limit={credits.weekly} /> : null}\n {monthlyReported ? (\n <MonthlyBalance label={t('usageMonthlyLeft')} remaining={credits.monthlyCredits} />\n ) : null}\n </div>\n ) : null}\n\n {!row.configured && row.managed && mode === undefined && !showLogin ? (\n <div className=\"cc-accountSetup\">\n <p className=\"cc-hint\">{row.keyWritable ? t('accountNoKeyHint') : t('apiKeyLocked')}</p>\n {keyActions ? (\n <div className=\"cc-inlineActions\">\n <Button variant=\"primary\" size=\"sm\" disabled={loginBusy || busyElsewhere} onClick={() => actions.beginLogin(loginTarget)}>\n {t('accountAddLogin')}\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setMode('key')}>{t('accountAddPaste')}</Button>\n </div>\n ) : null}\n </div>\n ) : null}\n\n {showLogin ? <LoginStatus state={loginState} t={t} onCancel={actions.cancelLogin} /> : null}\n\n {mode === 'key' ? (\n <InlineInput\n id={`cc-account-${row.id}-key`}\n label={t('accountKeyPlaceholder')}\n secret\n placeholder={t('accountKeyPlaceholder')}\n confirmLabel={t('accountApply')}\n disabled={disabled || state.accountBusy}\n t={t}\n onCancel={() => setMode(undefined)}\n onSubmit={(value) => {\n void actions.setKey(row.id, value).then((ok) => {\n if (ok) setMode(undefined)\n })\n }}\n />\n ) : null}\n {mode === 'rename' && row.ref !== undefined ? (\n <InlineInput\n id={`cc-account-${row.id}-rename`}\n label={t('accountActionRename')}\n initial={row.label}\n confirmLabel={t('accountApply')}\n disabled={disabled || state.accountBusy}\n t={t}\n onCancel={() => setMode(undefined)}\n onSubmit={(value) => {\n void actions.rename(row.ref!, value).then((ok) => {\n if (ok) setMode(undefined)\n })\n }}\n />\n ) : null}\n {mode === 'remove' && row.ref !== undefined ? (\n <ConfirmBar\n text={t('accountRemoveConfirm', { name: row.label })}\n confirmLabel={t('accountConfirmRemove')}\n disabled={disabled || state.accountBusy}\n t={t}\n onCancel={() => setMode(undefined)}\n onConfirm={() => {\n void actions.remove(row.ref!).then((ok) => {\n if (ok) setMode(undefined)\n })\n }}\n />\n ) : null}\n {mode === 'clearKey' ? (\n <ConfirmBar\n text={t('accountClearKeyConfirm')}\n confirmLabel={t('accountConfirmClear')}\n disabled={disabled || state.accountBusy}\n t={t}\n onCancel={() => setMode(undefined)}\n onConfirm={() => {\n void actions.clearKey(row.id).then((ok) => {\n if (ok) setMode(undefined)\n })\n }}\n />\n ) : null}\n\n {expanded ? (\n <div id={`cc-account-${row.id}-details`} className=\"cc-accountDetails\">\n {entry !== undefined ? (\n <AccountReport entry={entry} fetchedAt={usage.fetchedAt} t={t} headless />\n ) : (\n <p className=\"cc-usageHint\">{usage.status === 'loading' ? t('usageLoading') : t('usageUnconfigured')}</p>\n )}\n {multi && row.managed ? (\n <SettingRow\n className=\"cc-rowFlush\"\n title={t('accountModels')}\n titleFor={`cc-account-${row.id}-models`}\n description={t('accountModelsHint')}\n error={state.catalogFailed ? t('modelCatalogFailed') : undefined}\n control={\n <ModelMultiSelect\n id={`cc-account-${row.id}-models`}\n selected={models}\n catalog={state.catalogModels}\n disabled={disabled || state.accountBusy}\n deferCommit\n ownerOf={ownerOf}\n t={t}\n onSelect={(ids) => void actions.setModels(row.id, ids)}\n />\n }\n />\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n\n/** The live status of one browser sign-in: link while waiting, outcome after. */\nfunction LoginStatus({ state, t, onCancel }: {\n state: LoginPageState\n t: Translate<SettingsCommandCodeKey>\n onCancel(): void\n}) {\n const hint = loginHint(state, t)\n const busy = state.phase === 'starting' || state.phase === 'waiting'\n return (\n <div className=\"cc-loginStatus\" role=\"status\">\n <p className={hint.className} title={hint.title}>{hint.text}</p>\n {state.authUrl !== undefined ? (\n <a className=\"cc-loginLink\" href={state.authUrl} target=\"_blank\" rel=\"noreferrer\">{t('loginOpenLink')}</a>\n ) : null}\n {busy ? <button type=\"button\" className=\"cc-reset\" onClick={onCancel}>{t('loginCancel')}</button> : null}\n </div>\n )\n}\n\n/** The immediate account operations the list and its rows call. */\ninterface AccountActions {\n create(input: { label: string; key?: string }): Promise<string | undefined>\n rename(ref: string, label: string): Promise<boolean>\n remove(ref: string): Promise<boolean>\n setKey(target: string, key: string): Promise<boolean>\n clearKey(target: string): Promise<boolean>\n setActive(id: string): Promise<boolean>\n setModels(target: string, ids: string[]): Promise<boolean>\n beginLogin(targetRef?: string): void\n cancelLogin(): void\n}\n\n/**\n * The add-account panel. Both paths store the account at once: pasting a key\n * writes key then row; browser sign-in stores a keyless row first (the Host\n * only signs in to a reference the stored list names) and drops it again if\n * the sign-in does not complete, so a failed attempt leaves no empty account.\n */\nfunction AddAccountPanel({ state, login, disabled, t, actions, pendingRef, setPendingRef, onClose }: {\n state: SettingsPageState\n login: LoginPageState\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n actions: AccountActions\n /** The account stored for an in-flight sign-in; its row stays hidden until the sign-in lands. */\n pendingRef: string | undefined\n setPendingRef(ref: string | undefined): void\n onClose(): void\n}) {\n const [label, setLabel] = useState('')\n const [pasting, setPasting] = useState(false)\n const [loginFailure, setLoginFailure] = useState<string | undefined>(undefined)\n const fallbackName = t('accountNameN', { n: state.accounts.length + 2 })\n const pending = pendingRef === undefined ? undefined : loginStateForTarget(login, pendingRef).visible\n const busy = state.accountBusy || pending?.phase === 'starting' || pending?.phase === 'waiting'\n const loginBusyElsewhere = login.phase === 'starting' || login.phase === 'waiting'\n\n useEffect(() => {\n if (pendingRef === undefined || login.targetRef !== pendingRef) return\n if (login.phase === 'success') {\n const named = label.trim() === '' && login.userName !== undefined && login.userName !== ''\n setPendingRef(undefined)\n void (named ? actions.rename(pendingRef, login.userName!) : Promise.resolve(true)).then(onClose)\n return\n }\n if (login.phase === 'failed' || login.phase === 'unavailable') {\n setLoginFailure(loginHint(login, t).text)\n setPendingRef(undefined)\n void actions.remove(pendingRef)\n }\n }, [login, pendingRef, setPendingRef, label, actions, onClose, t])\n\n const startLogin = async () => {\n setLoginFailure(undefined)\n const ref = await actions.create({ label: label.trim() === '' ? fallbackName : label })\n if (ref === undefined) return\n setPendingRef(ref)\n actions.beginLogin(ref)\n }\n\n return (\n <div className=\"cc-addPanel\" aria-label={t('accountAdd')}>\n <span className=\"cc-panelTitle\">{t('accountAdd')}</span>\n <input\n className=\"cc-input\"\n type=\"text\"\n aria-label={t('accountNamePlaceholder')}\n placeholder={t('accountNamePlaceholder')}\n value={label}\n disabled={disabled || busy}\n onChange={(event) => setLabel(event.target.value)}\n />\n {pending !== undefined && pending.phase !== 'idle' ? (\n <LoginStatus state={pending} t={t} onCancel={actions.cancelLogin} />\n ) : null}\n {loginFailure !== undefined ? <p className=\"cc-loginError\">{loginFailure}</p> : null}\n {pasting ? (\n <InlineInput\n id=\"cc-add-account-key\"\n label={t('accountKeyPlaceholder')}\n secret\n placeholder={t('accountKeyPlaceholder')}\n confirmLabel={t('accountAddConfirm')}\n disabled={disabled || busy}\n t={t}\n onCancel={() => setPasting(false)}\n onSubmit={(key) => {\n void actions.create({ label: label.trim() === '' ? fallbackName : label, key }).then((ref) => {\n if (ref !== undefined) onClose()\n })\n }}\n />\n ) : (\n <>\n <p className=\"cc-hint\">{t('accountAddHint')}</p>\n <div className=\"cc-inlineActions\">\n <Button variant=\"primary\" size=\"sm\" disabled={disabled || busy || loginBusyElsewhere} onClick={() => void startLogin()}>\n {t('accountAddLogin')}\n </Button>\n <Button variant=\"ghost\" size=\"sm\" disabled={disabled || busy} onClick={() => setPasting(true)}>\n {t('accountAddPaste')}\n </Button>\n <span className=\"cc-spacer\" />\n <Button variant=\"ghost\" size=\"sm\" disabled={busy} onClick={onClose}>{t('cancel')}</Button>\n </div>\n </>\n )}\n </div>\n )\n}\n\n/**\n * The unified account card: every account the pool rotates through, one row\n * each, with its status and quota inline. Replaces the former split between\n * a credentials card, a usage card and a routing-rules card, so one account's\n * facts no longer have to be cross-read across three surfaces.\n */\nfunction AccountsCard({ t, state, usage, login, disabled, actions, onRefresh }: {\n t: Translate<SettingsCommandCodeKey>\n state: SettingsPageState\n usage: UsagePageState\n login: LoginPageState\n disabled: boolean\n actions: AccountActions\n onRefresh(): void\n}) {\n const [adding, setAdding] = useState(false)\n const [pendingRef, setPendingRef] = useState<string | undefined>(undefined)\n const closeAdd = useCallback(() => setAdding(false), [])\n const { loading, shouldRefresh } = usageCardState(usage)\n // Ask the Host on first paint: CLI auth and composition keys are not\n // represented by browser credential references.\n useEffect(() => {\n if (shouldRefresh) onRefresh()\n }, [shouldRefresh, onRefresh])\n const rows = accountRows(state, usage, t).filter((row) => row.ref === undefined || row.ref !== pendingRef)\n const multi = rows.length > 1\n const pinnedRow = rows.find((row) => row.id === state.activeAccount)\n return (\n <section className=\"cc-group\" aria-label={t('accountsTitle')}>\n <div className=\"cc-groupHead\">\n <h3 className=\"cc-groupTitle\">{t('accountsTitle')}</h3>\n <span className=\"cc-spacer\" />\n <button type=\"button\" className=\"cc-linkButton\" disabled={loading} onClick={onRefresh}>\n {loading ? t('usageRefreshing') : t('usageRefresh')}\n </button>\n </div>\n <p className=\"cc-groupDesc\">{multi ? t('accountsRotationHint') : t('accountsHint')}</p>\n {multi ? (\n <div className=\"cc-accountMode\">\n <span>{pinnedRow !== undefined ? t('accountModePinned', { name: pinnedRow.label }) : t('accountModeAuto')}</span>\n {pinnedRow !== undefined ? (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled || state.accountBusy} onClick={() => void actions.setActive('')}>\n {t('accountActionUnpin')}\n </button>\n ) : null}\n </div>\n ) : null}\n {usage.status === 'error' ? (\n <p className=\"cc-rowError\" role=\"status\">\n {t('usageError')}{usage.error !== undefined && usage.error !== '' ? ` — ${usage.error}` : ''}\n </p>\n ) : null}\n {state.accountFailed !== undefined ? <p className=\"cc-rowError\" role=\"status\">{t('accountOpFailed')}</p> : null}\n <div className=\"cc-accountList\">\n {rows.map((row) => (\n <AccountItem\n key={row.id}\n row={row}\n rows={rows}\n state={state}\n usage={usage}\n login={login}\n disabled={disabled}\n pinned={state.activeAccount === row.id}\n t={t}\n actions={actions}\n />\n ))}\n </div>\n {adding ? (\n <AddAccountPanel\n state={state}\n login={login}\n disabled={disabled}\n t={t}\n actions={actions}\n pendingRef={pendingRef}\n setPendingRef={setPendingRef}\n onClose={closeAdd}\n />\n ) : (\n <button type=\"button\" className=\"cc-addButton\" disabled={disabled} onClick={() => setAdding(true)}>\n <span className=\"cc-addGlyph\" aria-hidden=\"true\" />\n {t('accountAdd')}\n </button>\n )}\n </section>\n )\n}\n\n/**\n * Show the save bar's \"saved\" confirmation for a short window after each accepted save.\n * The controller only counts saves (`savedCount`); the flash timing lives\n * here so the state machine stays timer-free.\n */\nfunction useSavedFlash(tick: number): boolean {\n const [visible, setVisible] = useState(false)\n // The count lives in the shared controller and outlives this component, so\n // a remount (switching settings pages, reopening settings) sees a non-zero\n // count it did not witness. Only a save landing while mounted may flash.\n const seen = useRef(tick)\n useEffect(() => {\n if (tick === seen.current) return\n seen.current = tick\n setVisible(true)\n const timer = setTimeout(() => setVisible(false), 2500)\n return () => clearTimeout(timer)\n }, [tick])\n return visible\n}\n\n/**\n * The update hint: one throttled npm-registry check per page open (the\n * throttle and all failure handling live in ./update.ts). Resolves to the\n * newest published version when it is newer than this build, else undefined —\n * every failure mode degrades to no hint at all.\n */\nfunction usePluginUpdate(): string | undefined {\n const [available, setAvailable] = useState<string | undefined>(undefined)\n useEffect(() => {\n let cancelled = false\n void checkForUpdate({\n currentVersion: PLUGIN_VERSION,\n now: Date.now(),\n store: localStorageUpdateStore(),\n }).then((version) => {\n if (!cancelled) setAvailable(version)\n // A rejected checkForUpdate would be a bug (it catches internally);\n // swallow it regardless — the footer must never break the page.\n }, () => {})\n return () => {\n cancelled = true\n }\n }, [])\n return available\n}\n\ntype SaveBarTone = 'pending' | 'error' | 'success'\n\ninterface SaveBarView {\n visible: boolean\n tone: SaveBarTone\n message: string\n /** Whether Discard/Save apply (hidden while only the saved confirmation shows). */\n actions: boolean\n}\n\n/**\n * What the save bar says. It exists only while there is something to act on\n * or to confirm: pending edits, a save in flight, a failure, or the brief\n * confirmation after a save landed. Account operations never reach it, they\n * commit on their own.\n */\nfunction saveBarView(state: SettingsPageState, savedVisible: boolean, t: Translate<SettingsCommandCodeKey>): SaveBarView {\n if (state.failed) return { visible: true, tone: 'error', message: t('saveFailed'), actions: state.dirty }\n if (state.dirty || state.saving) {\n return state.invalid\n ? { visible: true, tone: 'error', message: t('saveInvalid'), actions: true }\n : { visible: true, tone: 'pending', message: t('unsavedChanges'), actions: true }\n }\n if (savedVisible) return { visible: true, tone: 'success', message: t('saved'), actions: false }\n return { visible: false, tone: 'success', message: '', actions: false }\n}\n\n/** The save bar's leading status mark: a soft dot while pending, a glyph once there is an outcome. */\nfunction SaveBarIcon({ tone }: { tone: SaveBarTone }) {\n if (tone === 'pending') return <span className=\"cc-saveBarIcon\" aria-hidden=\"true\"><span className=\"cc-saveBarPulse\" /></span>\n return (\n <span className=\"cc-saveBarIcon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"8\" cy=\"8\" r=\"6.5\" />\n {tone === 'success' ? <path d=\"M5.2 8.2l1.9 1.9 3.7-3.9\" /> : <path d=\"M8 4.8v3.6M8 11.1v.1\" />}\n </svg>\n </span>\n )\n}\n\n/**\n * The floating save bar: pinned to the bottom of the settings scrollport and\n * slid out of view when there is nothing to save. It stays mounted so it can\n * animate out, and keeps showing its last message while it does (the state\n * that hid it has no message of its own).\n */\nfunction SaveBar({ view, state, t, onDiscard, onSave }: {\n view: SaveBarView\n state: SettingsPageState\n t: Translate<SettingsCommandCodeKey>\n onDiscard(): void\n onSave(): void\n}) {\n const last = useRef(view)\n if (view.visible) last.current = view\n const shown = view.visible ? view : last.current\n return (\n <div className=\"cc-saveBarDock\">\n <div\n className={`cc-saveBar cc-saveBar-${shown.tone}${view.visible ? ' cc-saveBarShown' : ''}`}\n role=\"region\"\n aria-label={t('save')}\n aria-hidden={!view.visible}\n >\n <SaveBarIcon tone={shown.tone} />\n <p className=\"cc-saveBarText\" role=\"status\" aria-live=\"polite\" title={shown.message}>{shown.message}</p>\n {shown.actions ? (\n <div className=\"cc-saveBarActions\">\n {/* Own buttons rather than the primitives: they are sized to sit\n concentrically inside the bar (see .cc-saveBar). */}\n <button\n type=\"button\"\n className=\"cc-saveBarButton cc-saveBarGhost\"\n disabled={!view.visible || !state.dirty || state.saving}\n onClick={onDiscard}\n >\n {t('discard')}\n </button>\n <button\n type=\"button\"\n className=\"cc-saveBarButton cc-saveBarPrimary\"\n disabled={!view.visible || !state.dirty || state.invalid || state.saving}\n onClick={onSave}\n >\n {t(state.saving ? 'saving' : 'save')}\n </button>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\n/** The settings page body: accounts, then the staged provider settings. */\nexport function CommandCodeSettingsPage(props: CommandCodeSettingsProps) {\n const { t } = props\n const state = props.useCommandCodeSettings((snapshot) => snapshot)\n const usage = props.useCommandCodeUsage((snapshot) => snapshot)\n const login = props.useCommandCodeLogin((snapshot) => snapshot)\n const disabled = !state.writable\n const savedVisible = useSavedFlash(state.savedCount)\n const updateVersion = usePluginUpdate()\n // One stable object: the add panel's effect depends on it, and a fresh\n // object per render would re-run that effect on every store notification.\n const {\n createAccount, renameAccount, removeAccount, setAccountKey, clearAccountKey,\n setActiveAccount, setAccountModels, beginLogin, cancelLogin,\n } = props\n const actions = useMemo<AccountActions>(() => ({\n create: createAccount,\n rename: renameAccount,\n remove: removeAccount,\n setKey: setAccountKey,\n clearKey: clearAccountKey,\n setActive: setActiveAccount,\n setModels: setAccountModels,\n beginLogin,\n cancelLogin,\n }), [createAccount, renameAccount, removeAccount, setAccountKey, clearAccountKey, setActiveAccount, setAccountModels, beginLogin, cancelLogin])\n const bar = saveBarView(state, savedVisible, t)\n const form = { state, disabled, t, onEdit: props.edit, onReset: props.resetField }\n return (\n <section className={bar.visible ? 'cc-section cc-sectionWithBar' : 'cc-section'} aria-label={t('title')}>\n <h2 className=\"cc-title\">{t('title')}</h2>\n <p className=\"cc-intro\">{t('intro')}</p>\n {!state.writable ? <p className=\"cc-readOnly\" role=\"status\">{t('readOnly')}</p> : null}\n <AccountsCard\n t={t}\n state={state}\n usage={usage}\n login={login}\n disabled={disabled}\n actions={actions}\n onRefresh={props.refreshUsage}\n />\n <ModelsCard {...form} onSelect={props.editVisibleModels} onClear={props.clearVisibleModels} />\n <PrivacyCard {...form} />\n <IntegrationsCard {...form} />\n <AdvancedSection {...form} />\n <p className=\"cc-version\">\n Command Code Provider v{PLUGIN_VERSION}\n {updateVersion !== undefined ? (\n <>\n {' · '}\n <a\n className=\"cc-versionLink\"\n href={PLUGIN_RELEASES_URL}\n target=\"_blank\"\n rel=\"noreferrer\"\n title={t('updateHint')}\n >\n v{updateVersion} {t('updateAvailable')}\n </a>\n </>\n ) : null}\n </p>\n <SaveBar view={bar} state={state} t={t} onDiscard={props.discard} onSave={props.save} />\n </section>\n )\n}\n","/**\n * The shared login row: one field row that starts the Host-side browser\n * login, links to the Studio authorization page while the attempt is live,\n * and reports the outcome — rendered by BOTH the settings page (`section.tsx`)\n * and the Models-page provider card (`card.tsx`) so the two surfaces share\n * one component and one hint state machine.\n *\n * The hint copy/class logic lives in the JSX-free `./login.ts`\n * (`loginHint`/`loginFailureCopy`) so node tests can drive every phase; this\n * file only renders it.\n *\n * @module dsh-commandcode-provider/client/login-row\n */\n\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport { loginHint, loginStateForTarget } from './login.ts'\nimport type { LoginPageState } from './login.ts'\n\n/** One login row's props (same face both surfaces supply). */\nexport interface LoginRowProps {\n state: LoginPageState\n /** Only the matching attempt appears in this row; omitted means default. */\n targetRef?: string\n disabled: boolean\n disabledHint?: string | undefined\n t: Translate<SettingsCommandCodeKey>\n onBegin(): void\n onCancel(): void\n}\n\n/** The sign-in alternative to pasting a key (settings page + Models card). */\nexport function LoginRow({ state, targetRef, disabled, disabledHint, t, onBegin, onCancel }: LoginRowProps) {\n const { visible: visibleState, busyElsewhere } = loginStateForTarget(state, targetRef)\n const busy = visibleState.phase === 'starting' || visibleState.phase === 'waiting'\n const hint = loginHint(visibleState, t)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <span className=\"cc-label\">{t('loginTitle')}</span>\n <span className=\"cc-badges\">\n {busy ? (\n <button type=\"button\" className=\"cc-reset\" onClick={onCancel}>{t('loginCancel')}</button>\n ) : (\n <button type=\"button\" className=\"cc-reset\" disabled={disabled || busyElsewhere} onClick={onBegin}>{t('loginButton')}</button>\n )}\n </span>\n </div>\n {visibleState.authUrl !== undefined ? (\n <p className=\"cc-hint\">\n <a className=\"cc-loginLink\" href={visibleState.authUrl} target=\"_blank\" rel=\"noreferrer\">{t('loginOpenLink')}</a>\n </p>\n ) : null}\n <p className={hint.className} title={hint.title}>{disabled && !busy && disabledHint !== undefined ? disabledHint : hint.text}</p>\n </div>\n )\n}\n","/**\n * The Command Code configuration panel inside the harness Models settings page\n * (browser half). Rendered through the `settings.models.provider-card` keyed\n * slot available in dsh 0.1.2 (rc.1), registered with\n * `entryKey = 'llm-commandcode'` (the plugin's settings namespace, the key the\n * Models page dispatches for every Command Code provider row).\n *\n * The official Models page opens one editor card per provider row through its\n * own 编辑 button. For a namespace the page does not curate a layout for\n * (`llm-commandcode`), that editor is a bare shell — a pointer to\n * `settings.yaml` above a permanently disabled apply button. This panel takes\n * its place: the slot outlet renders right beside the official editor inside\n * the same row card, so the component watches the outlet's siblings and, while\n * the official editor is open, hides the useless shell and shows the real\n * controls in its slot — the credential/route badges, the API-key field,\n * official sign-in, and the discard/save footer. Closed, it renders nothing\n * and the row looks exactly like any other provider row.\n *\n * The slot's owner props (`configured`, `keyConfigured`) mirror what the\n * Models page already knows; the authoritative credential facts still come\n * from this plugin's `CommandCodeSettingsController` shared with the dedicated\n * settings page, so the two surfaces can never disagree about whether a key\n * is stored.\n *\n * A controller-less render (panel mounted before the section registered its\n * inject face — the composition runs one apply) degrades to the stateless\n * registration notice inside the opened panel.\n *\n * Styles ride the page stylesheet the client entry injects once (`cc-`\n * prefixed classes); the card adds no CSS of its own.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport type { SettingsPageState, StagedField } from './settings.ts'\nimport type { LoginPageState } from './login.ts'\nimport { LoginRow } from './login-row.tsx'\n\n/**\n * The Models-page extension slots, merged into the SlotMap with the exact\n * declarations dsh 0.1.2 (rc.1)'s ui-settings-models ships. The merge must\n * stay structurally identical to upstream's (kind/scope/owner), or a future\n * dsh carrying its own declaration would fail the duplicate-merge check at\n * compile time.\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n /** One provider card's adapter extension area, keyed by the row's settingsNs. */\n 'settings.models.provider-card': { kind: 'keyed'; scope: 'root'; owner: ProviderCardExtrasOwnerProps }\n /** Ordered extension area after the provider rows and the add controls. */\n 'settings.models.footer': { kind: 'list'; scope: 'root'; owner: ModelsFooterOwnerProps }\n }\n}\n\n/** The provider directory row as the Models page dispatches it. */\nexport interface ProviderDirectoryRow {\n /** The provider route id (`commandcode` for this plugin). */\n readonly provider: string\n /** The row's display name. */\n readonly displayName: string\n /** The settings namespace the row configures (the slot's dispatch key). */\n readonly settingsNs: string\n /** The settings path the row's profile lives at. */\n readonly settingsPath: readonly string[]\n /** Whether the provider route is live. */\n readonly active: boolean\n /** Whether the adapter declares the route as shipped. */\n readonly declared?: boolean\n}\n\n/** Owner share of one provider-card extension occurrence (upstream's shape). */\nexport interface ProviderCardExtrasOwnerProps {\n /** The card's directory row. */\n readonly provider: ProviderDirectoryRow\n /** Whether any layer configures this provider (its profile resolves). */\n readonly configured: boolean\n /** The row's referenced api-key credential, confirmed configured by the page's join. */\n readonly keyConfigured: boolean\n}\n\n/** Owner share of the footer area (the section supplies nothing). */\nexport interface ModelsFooterOwnerProps {\n /** Marker field: footer owner props are intentionally empty. */\n children?: never\n}\n\n/** Owner props the Models page supplies at its dispatch sites. */\nexport type ProviderCardOwnerProps = ProviderCardExtrasOwnerProps\n\n/**\n * The slot whose outlet anchors this panel inside the Models row — the\n * renderer's own `data-slot` attribute value, stable across builds (unlike\n * CSS-module class hashes).\n */\nexport const CARD_SLOT_KEY = 'settings.models.provider-card'\n\n/** The DOM facts the sibling lookup reads (satisfied by real Elements). */\nexport interface SlotWrapperSiblings {\n previousElementSibling: { className: string } | null\n nextElementSibling: { className: string } | null\n}\n\n/**\n * Find the official editor card among the slot outlet's siblings, or null\n * while it is closed. The Models page renders the editor as an immediate\n * sibling of the outlet wrapper — after it in a provider row (the target of\n * the row's 编辑 toggle), before it in the first-run setup card and the\n * add-provider card, where it is always open. The editor is the only such\n * sibling whose CSS module class carries the `editor` stem\n * (`<hash>_editor`); the row header and the add card's provider select\n * never do, so the lookup needs no hash knowledge.\n */\nexport function adjacentEditorCard(wrapper: SlotWrapperSiblings | null): { className: string } | null {\n if (wrapper === null) return null\n for (const sibling of [wrapper.previousElementSibling, wrapper.nextElementSibling]) {\n if (sibling !== null && typeof sibling.className === 'string' && sibling.className.includes('editor')) {\n return sibling\n }\n }\n return null\n}\n\n/** The closed-panel style: the outlet stays mounted as the detection anchor. */\nconst HIDDEN_STYLE = { display: 'none' } as const\n\n/** Injected face the card's slot registration supplies. */\nexport interface CommandCodeCardProps {\n t: Translate<SettingsCommandCodeKey>\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n useCommandCodeLogin<T>(selector: (state: LoginPageState) => T): T\n edit(field: string, text: string): void\n save(): void\n discard(): void\n beginLogin(): void\n cancelLogin(): void\n}\n\n/** The card's two postures. */\ntype CardMode =\n | { kind: 'registration' }\n | { kind: 'live'; ready: boolean; controllerConfigured: boolean; writable: boolean; apiKeyWritable: boolean }\n\n/**\n * Decide the card's posture from one settings snapshot. Pure: the component\n * subscribes once and passes the snapshot in, so hook order never depends\n * on the registration→live transition. (The owner facts stay on the\n * component — only the snapshot decides the posture.)\n */\nexport function cardMode(\n snapshot: SettingsPageState | undefined,\n): CardMode {\n if (snapshot === undefined) return { kind: 'registration' }\n return {\n kind: 'live',\n ready: snapshot.available,\n controllerConfigured: snapshot.apiKeyConfigured,\n writable: snapshot.writable,\n apiKeyWritable: snapshot.apiKeyWritable,\n }\n}\n\n/** Status badge for the credential state (green when configured). */\nfunction StatusBadge({ ok, okLabel, pendingLabel }: {\n ok: boolean\n okLabel: string\n pendingLabel: string\n}) {\n return <span className={ok ? 'cc-badge' : 'cc-badgeMuted'}>{ok ? okLabel : pendingLabel}</span>\n}\n\n/** Compact key field for the not-configured card. */\nfunction CardKeyField({ state, disabled, t, onEdit }: {\n state: StagedField\n disabled: boolean\n t: Translate<SettingsCommandCodeKey>\n onEdit(text: string): void\n}) {\n const [visible, setVisible] = useState(false)\n return (\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <label className=\"cc-label\" htmlFor=\"cc-card-api-key\">{t('apiKey')}</label>\n <span className=\"cc-badges\">\n <button type=\"button\" className=\"cc-reset\" disabled={disabled} onClick={() => setVisible((value) => !value)}>\n {visible ? t('hide') : t('show')}\n </button>\n </span>\n </div>\n <input\n id=\"cc-card-api-key\"\n className=\"cc-input\"\n type={visible ? 'text' : 'password'}\n autoComplete=\"off\"\n spellCheck={false}\n value={state.text}\n disabled={disabled}\n onChange={(event) => onEdit(event.target.value)}\n />\n <p className=\"cc-hint\">{t('apiKeyHint')}</p>\n </div>\n )\n}\n\n/**\n * The slot component body. Dispatched on every Command Code provider card of\n * the Models page (saved row, first-run setup posture, and add-provider\n * draft).\n *\n * Closed (the official 编辑 toggle off) the panel renders nothing: the row\n * head the Models page owns already names the provider and shows the\n * credential dot, so a page full of providers stays compact. Opening the\n * official editor mounts the editor shell as the outlet's sibling; the panel\n * watches for it, hides the shell (it carries only the settings.yaml hint and\n * a disabled apply for this namespace), and shows the real controls — badges,\n * API-key field, sign-in, discard/save.\n */\nexport function CommandCodeProviderCard(props: CommandCodeCardProps & ProviderCardOwnerProps) {\n const { t } = props\n // Single subscription: the whole snapshot drives posture + body together.\n const state = props.useCommandCodeSettings !== undefined\n ? props.useCommandCodeSettings((snapshot) => snapshot)\n : undefined\n const mode = cardMode(state)\n const login = props.useCommandCodeLogin !== undefined\n ? props.useCommandCodeLogin((snapshot) => snapshot)\n : undefined\n const dirty = state?.dirty ?? false\n const saving = state?.saving ?? false\n const invalid = state?.invalid ?? false\n const failed = state?.failed ?? false\n const savingBlocked = !dirty || invalid\n const configured = mode.kind === 'live' && mode.ready ? mode.controllerConfigured : props.keyConfigured\n const disabled = mode.kind === 'live' && (!mode.writable || (state !== undefined && !mode.apiKeyWritable))\n const showBody = mode.kind === 'live' && mode.ready && state !== undefined\n // The official editor's open state lives in the Models page's own component\n // state and never reaches this slot's props; the outlet wrapper is the\n // stable neighbor, so watch its siblings for the editor's mount/unmount.\n // The outlet stays mounted either way — it is the observation anchor — so\n // the closed panel hides its own root instead of unmounting.\n const rootRef = useRef<HTMLDivElement | null>(null)\n const [editorOpen, setEditorOpen] = useState(false)\n useEffect(() => {\n const root = rootRef.current\n if (root === null || typeof MutationObserver === 'undefined') return\n const wrapper = root.closest(`[data-slot=\"${CARD_SLOT_KEY}\"]`) ?? root.parentElement\n if (wrapper === null) return\n const row = wrapper.parentElement\n if (row === null) return\n let hiddenEditor: HTMLElement | null = null\n const sync = () => {\n const editor = adjacentEditorCard(wrapper) as HTMLElement | null\n setEditorOpen(editor !== null)\n if (editor !== null) {\n // React pins no inline style on the editor shell, so this survives\n // the shell's own re-renders; a shell that unmounts and remounts is\n // re-hidden by the next observation.\n editor.style.display = 'none'\n hiddenEditor = editor\n }\n }\n sync()\n const observer = new MutationObserver(sync)\n observer.observe(row, { childList: true })\n return () => {\n observer.disconnect()\n // If the shell outlives the panel (plugin reload), give it back: the\n // settings.yaml hint is the honest fallback face again.\n if (hiddenEditor !== null) hiddenEditor.style.display = ''\n }\n }, [])\n return (\n <div\n ref={rootRef}\n className=\"cc-providerCard\"\n data-cc-models-card=\"true\"\n style={editorOpen ? undefined : HIDDEN_STYLE}\n >\n {editorOpen && mode.kind === 'registration' ? <p className=\"cc-hint\">{t('cardRegistrationHint')}</p> : null}\n {editorOpen && mode.kind === 'live' && !mode.ready ? <p className=\"cc-hint\">{t('cardLoadingHint')}</p> : null}\n {editorOpen && showBody ? (\n <>\n <div className=\"cc-field\">\n <div className=\"cc-fieldHead\">\n <span className=\"cc-label\">{t('cardTitle')}</span>\n <span className=\"cc-badges\">\n <StatusBadge ok={configured} okLabel={t('apiKeySet')} pendingLabel={t('apiKeyUnset')} />\n {props.provider.active ? <span className=\"cc-badge\">{t('cardRouteActive')}</span> : null}\n </span>\n </div>\n </div>\n <CardKeyField\n state={state.apiKey}\n disabled={disabled}\n t={t}\n onEdit={(text) => props.edit('apiKey', text)}\n />\n {login !== undefined ? (\n <LoginRow\n state={login}\n disabled={disabled}\n t={t}\n onBegin={props.beginLogin}\n onCancel={props.cancelLogin}\n />\n ) : null}\n <div className=\"cc-footer\">\n {failed ? <p className=\"cc-failed\" role=\"status\">{t('saveFailed')}</p> : null}\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={!dirty || saving}\n onClick={props.discard}\n >\n {t('discard')}\n </button>\n <button\n type=\"button\"\n className=\"cc-reset\"\n disabled={savingBlocked || saving}\n onClick={props.save}\n >\n {t(saving ? 'saving' : 'save')}\n </button>\n </div>\n </>\n ) : null}\n </div>\n )\n}\n","/**\n * Bilingual copy for the Command Code **plans & quota panel** (the sidebar\n * footer card and the center-column dashboard it opens).\n *\n * The panel follows the harness's active language: `PANEL_LOCALE_NS` is a\n * registered locale namespace (`ctx.locale.register`), both panel slot\n * registrations declare it, and the renderer hands the component a `t` seat\n * whose identity changes on a language switch (so a memoized panel re-renders).\n * {@link buildPanelView} takes that translator as an input and builds every\n * string through it — the projection stays React-free and testable, and no\n * component carries copy of its own.\n *\n * The settings page keeps its own `settings.commandcode` namespace (see\n * `./locales.ts`); the two never mix.\n *\n * @module dsh-commandcode-provider/client/panel-copy\n */\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Copy of the plans & quota panel (footer card + dashboard). */\n 'panel.commandcode': PanelKey\n }\n}\n\n/**\n * The plans & quota panel key set. `zh` is the source of truth for the key set\n * (repo convention); en must carry the exact same keys — a mismatch is a\n * compile error at the register site.\n */\nexport type PanelKey =\n /** Footer card title and panel heading. */\n | 'nav'\n /** Panel sub-heading under the title. */\n | 'subtitle'\n /** Refresh button / in-flight label. */\n | 'refresh'\n | 'refreshing'\n /** Dashboard exit: the button's accessible name and its tooltip. */\n | 'close'\n | 'closeHint'\n /** First-paint fetch. */\n | 'loading'\n /** No credential at all: how to get one. */\n | 'noKey'\n | 'noKeyHint'\n /** Report section headings. */\n | 'plan'\n | 'credits'\n | 'limits'\n | 'usage'\n /** Monthly credit state and its tiles. */\n | 'monthly'\n | 'monthlyLimit'\n | 'monthlyUsed'\n | 'remaining'\n | 'purchased'\n | 'free'\n /** Usage-window rows (long labels in the dashboard, short in the footer). */\n | 'fiveHour'\n | 'weekly'\n | 'fiveHourShort'\n | 'weeklyShort'\n | 'windowUnlimited'\n | 'exceeded'\n | 'exhausted'\n | 'resets'\n /** Usage tiles. */\n | 'requests'\n | 'failed'\n | 'successRate'\n | 'spend'\n | 'tokens'\n | 'tokensIn'\n | 'tokensOut'\n /** Meta line. */\n | 'periodEnds'\n | 'updated'\n | 'partial'\n /** Rotation state on an account. */\n | 'active'\n | 'coolingDown'\n | 'invalidKey'\n /** Footer-card plan fallbacks. */\n | 'unconfigured'\n | 'unavailable'\n /** Whole-report failures (mirrors the settings card's blocked taxonomy). */\n | 'errorInvalidKey'\n | 'errorInvalidKeyHint'\n | 'errorServiceUnavailable'\n | 'errorServiceUnavailableHint'\n | 'errorNetwork'\n | 'errorNetworkHint'\n | 'errorInvalidResponse'\n | 'errorInvalidResponseHint'\n /** A fetch that failed for any other reason. */\n | 'errorGeneric'\n\n/** The locale namespace both panel slots bind their `t` seat to. */\nexport const PANEL_LOCALE_NS = 'panel.commandcode'\n\n/** A panel translator: one key in, one localized string out. */\nexport type PanelTranslator = (key: PanelKey) => string\n\n/** The panel's Simplified Chinese string table (the key-set source of truth). */\nexport const PANEL_COPY_ZH: Record<PanelKey, string> = {\n nav: 'Command Code',\n subtitle: '套餐、额度与配额窗口',\n refresh: '刷新',\n refreshing: '刷新中…',\n close: '关闭',\n closeHint: '返回会话',\n loading: '正在获取账户用量…',\n noKey: '尚未配置 API 密钥',\n noKeyHint: '在 设置 → Command Code 中粘贴密钥或登录后,点击刷新。',\n plan: '套餐',\n credits: '额度',\n limits: '配额窗口',\n usage: '用量',\n monthly: '月额度',\n monthlyLimit: '月额度上限',\n monthlyUsed: '本月已用',\n remaining: '剩余',\n purchased: '已购',\n free: '赠送',\n fiveHour: '5 小时窗口',\n weekly: '每周窗口',\n fiveHourShort: '5 小时',\n weeklyShort: '每周',\n windowUnlimited: '不限',\n exceeded: '已超限',\n exhausted: '已用尽',\n resets: '重置于',\n requests: '请求',\n failed: '失败',\n successRate: '成功率',\n spend: '花费',\n tokens: 'Token',\n tokensIn: '入',\n tokensOut: '出',\n periodEnds: '账期截止',\n updated: '更新于',\n partial: '部分端点数据不可用',\n active: '当前使用',\n coolingDown: '限额冷却中',\n invalidKey: '密钥无效',\n unconfigured: '未配置',\n unavailable: '无数据',\n errorInvalidKey: 'API 密钥无效或已过期',\n errorInvalidKeyHint: '服务端拒绝了全部请求(401)。请检查该账户的密钥,或到 commandcode.ai 控制台重新生成。',\n errorServiceUnavailable: 'Command Code 服务暂时不可用',\n errorServiceUnavailableHint: '服务端返回错误(5xx),请稍后点击刷新重试。',\n errorNetwork: '无法连接 Command Code 服务',\n errorNetworkHint: '所有请求都没有到达服务端。请检查网络连接或 API 地址设置。',\n errorInvalidResponse: 'Command Code 响应无法读取',\n errorInvalidResponseHint: '请求已收到响应,但内容无法解析。请检查宿主的 HTTP 代理或响应解压配置。',\n errorGeneric: '用量获取失败',\n}\n\n/** The panel's English string table (must mirror {@link PANEL_COPY_ZH}). */\nexport const PANEL_COPY_EN: Record<PanelKey, string> = {\n nav: 'Command Code',\n subtitle: 'Plans, credits and quota windows',\n refresh: 'Refresh',\n refreshing: 'Refreshing…',\n close: 'Close',\n closeHint: 'Back to the conversation',\n loading: 'Loading account usage…',\n noKey: 'No API key configured',\n noKeyHint: 'Paste a key — or sign in — under Settings → Command Code, then refresh.',\n plan: 'Plan',\n credits: 'Credits',\n limits: 'Quota windows',\n usage: 'Usage',\n monthly: 'Monthly',\n monthlyLimit: 'Monthly limit',\n monthlyUsed: 'Monthly used',\n remaining: 'Remaining',\n purchased: 'Purchased',\n free: 'Free',\n fiveHour: '5-hour window',\n weekly: 'Weekly window',\n fiveHourShort: '5-hour',\n weeklyShort: 'Weekly',\n windowUnlimited: 'unlimited',\n exceeded: 'Exceeded',\n exhausted: 'Used up',\n resets: 'Resets',\n requests: 'Requests',\n failed: 'failed',\n successRate: 'Success rate',\n spend: 'Spend',\n tokens: 'Tokens',\n tokensIn: 'in',\n tokensOut: 'out',\n periodEnds: 'Period ends',\n updated: 'Updated',\n partial: 'Some endpoint data unavailable',\n active: 'Active',\n coolingDown: 'Cooling down',\n invalidKey: 'Invalid key',\n unconfigured: 'Not configured',\n unavailable: 'No data',\n errorInvalidKey: 'API key invalid or expired',\n errorInvalidKeyHint: 'The server rejected every request (401). Check the key for this account, or generate a new one in the commandcode.ai console.',\n errorServiceUnavailable: 'The Command Code service is temporarily unavailable',\n errorServiceUnavailableHint: 'The server returned errors (5xx). Try Refresh again in a moment.',\n errorNetwork: 'Could not reach the Command Code service',\n errorNetworkHint: 'No request reached the server. Check your network connection or the API base setting.',\n errorInvalidResponse: 'Could not read the Command Code response',\n errorInvalidResponseHint: 'The requests received responses, but their bodies could not be parsed. Check the host HTTP proxy or response decoding.',\n errorGeneric: 'Could not fetch account usage',\n}\n\n/** Every panel key, in the English table's declaration order. */\nexport const PANEL_KEYS: readonly PanelKey[] = Object.keys(PANEL_COPY_EN) as PanelKey[]\n\n/**\n * The English translator. Used as the fallback when no locale seat is\n * available (a defensive path: every supported engine supplies one) and as the\n * default in tests that only assert the projection's figures.\n */\nexport function panelTextEN(key: PanelKey): string {\n return PANEL_COPY_EN[key] ?? key\n}\n","/**\n * View layer for the Command Code plans & quota panel (the sidebar footer card\n * and the dashboard it opens in the center column).\n *\n * Deliberately JSX-free and React-free, mirroring `./settings.ts` and\n * `./usage.ts`: it turns the shared usage snapshot into one presentation\n * tree that both React components render, and it owns the one shared side\n * effect (the throttled background refresh that keeps the sidebar card\n * current). Node tests drive everything here without a DOM.\n *\n * Every displayed string is decided here, as a `PanelKey` plus a `text`\n * record resolved through the injected translator — so the components carry no\n * formatting, pluralization, or copy of their own, and the panel follows the\n * harness's active language (`./panel-copy.ts` owns both dictionaries and the\n * `panel.commandcode` locale namespace; the slots hand the translator in).\n *\n * @module dsh-commandcode-provider/client/panel\n */\n\nimport type { CommandCodeUsageReport } from '../adapter.ts'\nimport type { CommandCodeAccountUsage } from '../usage-wire.ts'\nimport type { UsagePageState } from './usage.ts'\nimport {\n formatMoney,\n formatMoneyExact,\n formatSuccessRate,\n formatTokensCompact,\n} from './usage.ts'\nimport { PANEL_KEYS, panelTextEN } from './panel-copy.ts'\nimport type { PanelKey, PanelTranslator } from './panel-copy.ts'\n\n/** One quota window (5-hour or weekly) in display form. */\nexport interface PanelWindowView {\n /** Row-label key into the view's `text` record. */\n label: PanelKey\n /** `used / cap`, or just `used` when the window is uncapped. */\n value: string\n /** The window reports a cap, so `percent` is meaningful. */\n capped: boolean\n /** Percentage actually consumed (may exceed 100 when over the cap). */\n percent: number\n /** Fill width for the bar, clamped to [0, 100]. */\n barPercent: number\n /** Window is over its cap. */\n exceeded: boolean\n /** Local reset time, empty when the endpoint reported none. */\n resetsAt: string\n}\n\n/**\n * Monthly credit state, derived exactly the way the official CLI derives it\n * (`getCreditDepletionPct` in `command-code/dist/cli.mjs`): the plan's credit\n * total is the LIMIT, and the billing endpoint's `credits.monthlyCredits` is\n * the REMAINING balance, so consumption is `limit - remaining`. The CLI's own\n * wording for the same two numbers is `Plan: N% used, X credits left`.\n *\n * Purchased and free credits are separate balances that extend what an account\n * can spend, so they are reported as their own tiles rather than folded into\n * the limit.\n */\nexport interface PanelMonthlyView {\n /**\n * A ratio is meaningful — the plan published a credit total AND the billing\n * endpoint published the balance left of it. When false the view draws no\n * bar: a percentage needs both halves, and inventing either one is how a\n * failed billing call turns into a confident \"100% used\".\n */\n known: boolean\n /** Plan credit total for the period (the limit); a dash when unreported. */\n limit: string\n /** Consumed this period (`limit - remaining`); a dash until both are known. */\n used: string\n /** Credits still available; a dash when the balance was not reported. */\n remaining: string\n /** Purchased top-up balance. */\n purchased: string\n /** Promotional balance. */\n free: string\n /** Consumption as a percentage of the limit; 0 when there is no ratio. */\n percent: number\n /** Fill width for the bar, clamped to [0, 100]. */\n barPercent: number\n /** The plan's credits are used up. */\n exhausted: boolean\n /** Billing period end, local date; empty when unreported. */\n periodEnds: string\n}\n\n/** One compact bar in the sidebar footer card. */\nexport interface PanelFooterBar {\n /** Row label key (short forms: `Monthly`, `5-hour`, `Weekly`). */\n label: PanelKey\n /** Printed right-hand percentage, e.g. `32%`; empty when there is no ratio. */\n percent: string\n /** Fill width, clamped to [0, 100]. */\n barPercent: number\n /** Render in the warning colour. */\n warn: boolean\n /**\n * This window's own spend against its limit, e.g. `$1.32 / $6.00`. RENDERED,\n * not just a tooltip: the card exists to show these figures, and the\n * magnitudes are small dollar amounts (the endpoint reports a Pro account's\n * five-hour cap as `3` and its weekly cap as `6`).\n */\n detail: string\n}\n\n/** One usage tile. */\nexport interface PanelStatView {\n label: PanelKey\n value: string\n /** Secondary line, empty when there is none. */\n sub: string\n}\n\n/** One pool account's report, ready to render. */\nexport interface PanelAccountView {\n id: string\n label: string\n /** The account's display name (user name, else account name); empty when unreported. */\n owner: string\n /** Subscription display name; empty when unreported. */\n planName: string\n /** Subscription status when it is not a plain `active`; empty otherwise. */\n planStatus: string\n /** Rotation/credential state ('invalidKey' / 'coolingDown'); undefined when plain. */\n mark: PanelKey | undefined\n /** Known cooldown end, appended to the cooling-down badge; empty otherwise. */\n cooldownUntil: string\n /** No credential resolved for this slot. */\n unconfigured: boolean\n /** Billing period end, empty when unreported. */\n periodEnds: string\n /** Whether the account currently serves requests. */\n active: boolean\n /** Monthly credit state; undefined when neither endpoint reported it. */\n monthly: PanelMonthlyView | undefined\n windows: PanelWindowView[]\n stats: PanelStatView[]\n}\n\n/** What actually went wrong, once — for the alert box. */\nexport interface PanelFailureView {\n title: PanelKey\n /** The actionable line under the title. */\n hint: PanelKey\n /** The underlying transport message, shown small; empty when there is none. */\n detail: string\n}\n\n/** The whole panel, in render order. */\nexport interface PanelView {\n /** Every localized string this view references, by key. */\n text: Partial<Record<PanelKey, string>>\n /** Footer-card plan text (`Go`, `Pro`, …), or a state word. */\n planName: string\n /** Footer-card rotation/credential state line; empty when nothing to say. */\n status: string\n /**\n * The compact bars the sidebar footer card stacks: the two quota windows an\n * account actually runs into, 5-hour first then weekly. The monthly\n * limit/usage bar belongs to the DASHBOARD alone — it moves once a billing\n * period, whereas these two are what stop a session — so it is deliberately\n * absent here. A window with no cap is left out: there is no ratio to draw.\n */\n footerBars: PanelFooterBar[]\n /**\n * This period's spend in dollars, formatted; empty when the usage endpoint\n * reported nothing. NOT drawn as its own row — the card's visible figures are\n * the two windows' own spend (see {@link PanelFooterBar.detail}), and a\n * separate period total would sit next to the weekly window's near-identical\n * figure — so it rides the tooltip and the accessible name instead.\n */\n cost: string\n /**\n * The footer card's accessible name and tooltip: `Command Code · Pro ·\n * 5-hour $0.04 / $3.00 (1%) · Weekly $1.32 / $6.00 (22%) · Spend $1.32`.\n * Always starts with the visible title, so the accessible name contains the\n * visible label.\n */\n footTitle: string\n /** Every account, in rotation order (empty when there is nothing to show). */\n accounts: PanelAccountView[]\n /** Id of the account the panel opens on (the serving one), if any. */\n selectedId: string | undefined\n /** That account's view, for the footer card; undefined with no accounts. */\n selected: PanelAccountView | undefined\n /** A fetch is in flight and no data has landed for this paint. */\n loading: boolean\n /** No credential is configured at all. */\n noKey: boolean\n /** Report-level failure box; undefined when the report is usable. */\n failure: PanelFailureView | undefined\n /** A fetch failed while data is still on screen. */\n staleError: string | undefined\n /** Endpoint-level partial failure note; undefined when every endpoint answered. */\n partial: PanelKey | undefined\n /** Freshness line, empty when nothing has been fetched. */\n updatedAt: string\n}\n\n/** Inputs {@link buildPanelView} needs beyond the usage snapshot. */\nexport interface PanelViewInput {\n usage: UsagePageState\n /** Whether any account holds a credential (the settings controller's fact). */\n apiKeyConfigured: boolean\n /**\n * Locale translator for every label the view composes. The panel slots bind\n * their `t` seat to the `panel.commandcode` namespace and pass it here, so\n * the projection follows the harness language; omitting it falls back to\n * English (the tests' default, and the defensive path when no locale face is\n * installed).\n */\n t?: PanelTranslator\n}\n\n/** A quota window's state as the wire carries it. */\ninterface WindowInput {\n used: number\n cap: number\n exceeded: boolean\n resetAt: number\n}\n\n/** `$1.23`, and `$0.0123` only when the amount is too small for cents to show it. */\nfunction money(value: number): string {\n if (value === 0) return formatMoney(0)\n return Math.abs(value) < 0.01 ? formatMoneyExact(value) : formatMoney(value)\n}\n\n/**\n * What a figure shows when the endpoint that carries it did not report one.\n * A dash, never a zero: the panel exists to state what the account has spent,\n * so \"we were not told\" has to look different from \"nothing\".\n */\nconst UNREPORTED = '—'\n\n/** Local reset time; empty when the endpoint reported none. */\nfunction resetText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleString()\n}\n\n/** Local short date; empty when unset. */\nfunction dateText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleDateString()\n}\n\n/** Local time-of-day; empty when unset. */\nfunction timeText(ms: number): string {\n if (ms <= 0) return ''\n return new Date(ms).toLocaleTimeString()\n}\n\n/**\n * Consumption as a percentage, NOT clamped at 100 — an over-quota window\n * reports its real overshoot (150%), which is what the printed figure should\n * say. Bar widths clamp separately via {@link barPercent}.\n */\nfunction rawPercent(used: number, cap: number): number {\n if (cap <= 0) return 0\n return Math.round((used / cap) * 100)\n}\n\n/** A percentage usable as a CSS width, clamped into [0, 100]. */\nfunction barPercent(percent: number): number {\n return Math.min(100, Math.max(0, percent))\n}\n\n/** Build one quota-window view. */\nfunction windowView(label: PanelKey, limit: WindowInput): PanelWindowView {\n const percent = rawPercent(limit.used, limit.cap)\n const capped = limit.cap > 0\n return {\n label,\n // Spend only: an uncapped window has no denominator, so its row pairs this\n // figure with the \"unlimited\" label instead of a `used / cap` it lacks.\n value: capped ? `${money(limit.used)} / ${money(limit.cap)}` : money(limit.used),\n capped,\n percent,\n barPercent: barPercent(percent),\n exceeded: limit.exceeded,\n resetsAt: resetText(limit.resetAt),\n }\n}\n\n/**\n * Build the monthly credit view from the two endpoints that carry it.\n *\n * The limit is the PLAN's credit total, not the billing endpoint's\n * `monthlyCredits` — that field is a remaining balance (see\n * {@link PanelMonthlyView}). Unknown plans (no `monthlyCredits` on the plan\n * record) therefore still show their balances, just without a ratio.\n *\n * The trap this guards: a MISSING balance is not a consumed one. The billing\n * endpoint is one of four the report fetches in parallel, so it fails on its\n * own while the plan still arrives — and reading the absent balance as 0 would\n * turn that partial failure into `limit - 0 = limit`, i.e. a confident \"100%\n * used, quota exhausted\" for an account that may have spent nothing. The\n * official CLI draws no meter unless the credits payload is present at all\n * (`hasCreditsInfo`), so \"unreported\" is the upstream-faithful reading here\n * too. Every derived figure stays a placeholder until the balance reported.\n */\nfunction monthlyView(report: CommandCodeUsageReport): PanelMonthlyView | undefined {\n const credits = report.credits\n const plan = report.plan\n if (credits === undefined && plan === undefined) return undefined\n\n const limitValue = plan?.monthlyCredits ?? null\n // Only an EXPLICIT `false` means the balance was omitted. An unset flag comes\n // from a Host half older than the field, which always sent a real number, so\n // it must keep rendering instead of turning into a dash everywhere.\n const remainingReported = credits !== undefined && credits.monthlyReported !== false\n const remaining = remainingReported ? Math.max(0, credits.monthlyCredits) : 0\n // A ratio needs BOTH halves: the plan's total and the balance left of it.\n const known = limitValue !== null && limitValue > 0 && remainingReported\n const used = known ? Math.max(0, limitValue - remaining) : 0\n const percent = known ? rawPercent(used, limitValue) : 0\n\n return {\n known,\n limit: limitValue !== null ? money(limitValue) : UNREPORTED,\n used: known ? money(used) : UNREPORTED,\n remaining: remainingReported ? money(remaining) : UNREPORTED,\n purchased: credits !== undefined && credits.purchasedReported !== false ? money(Math.max(0, credits.purchasedCredits)) : UNREPORTED,\n free: credits !== undefined && credits.freeReported !== false ? money(Math.max(0, credits.freeCredits)) : UNREPORTED,\n percent,\n barPercent: barPercent(percent),\n exhausted: known && remaining <= 0,\n periodEnds: dateText(plan?.currentPeriodEnd ?? 0),\n }\n}\n\n/** Build one account's view. */\nfunction accountView(entry: CommandCodeAccountUsage, t: PanelTranslator): PanelAccountView {\n const { report } = entry\n const account = report.account\n const plan = report.plan\n const credits = report.credits\n const usage = report.usage\n\n const stats: PanelStatView[] = []\n if (usage !== undefined) {\n stats.push({\n label: 'requests',\n value: String(usage.completedCount),\n sub: `${usage.failedCount} ${t('failed')}`,\n })\n stats.push({ label: 'successRate', value: `${formatSuccessRate(usage.successRate)}%`, sub: '' })\n stats.push({\n label: 'spend',\n value: formatMoneyExact(usage.totalCost),\n sub: `${formatMoney(usage.totalCredits)} credits`,\n })\n stats.push({\n label: 'tokens',\n value: formatTokensCompact(usage.totalTokensIn + usage.totalTokensOut),\n sub: `${formatTokensCompact(usage.totalTokensIn)} ${t('tokensIn')} / ${formatTokensCompact(usage.totalTokensOut)} ${t('tokensOut')}`,\n })\n }\n\n const windows: PanelWindowView[] = []\n // One row per window the endpoint actually REPORTED. An account on an\n // unlimited plan reports none, and drawing two zero-cap rows for it would\n // invent a limit the account does not have; a window that reported\n // `cap === 0` is uncapped spend and does get a row, labelled as such.\n if (credits?.fiveHour !== undefined) windows.push(windowView('fiveHour', credits.fiveHour))\n if (credits?.weekly !== undefined) windows.push(windowView('weekly', credits.weekly))\n\n // Rotation/credential state: the serving account first, then the two marks\n // the pool can carry, then a cooldown whose end time is known.\n let mark: PanelKey | undefined\n if (entry.active) mark = 'active'\n else if (entry.mark === 'invalid-credential') mark = 'invalidKey'\n else if (entry.cooldownUntil > 0 || entry.mark === 'rate-limit') mark = 'coolingDown'\n\n return {\n id: entry.id,\n label: entry.label,\n owner: account === undefined ? '' : account.userName || account.name,\n planName: plan?.name ?? '',\n planStatus: plan !== undefined && plan.status !== '' && plan.status !== 'active' ? plan.status : '',\n mark,\n cooldownUntil: entry.cooldownUntil > 0 ? resetText(entry.cooldownUntil) : '',\n unconfigured: !entry.configured,\n periodEnds: dateText(plan?.currentPeriodEnd ?? 0),\n active: entry.active,\n monthly: monthlyView(report),\n windows,\n stats,\n }\n}\n\n/** The report-level failure box, or undefined when the report is usable. */\nfunction failureView(state: UsagePageState): PanelFailureView | undefined {\n const blockedEntry = state.report?.accounts.find((entry) => entry.report.blocked !== undefined)\n const blocked = blockedEntry?.report.blocked\n // Preserve each endpoint's status or transport error beside the summary.\n const detail = (blockedEntry?.report.failures ?? []).join(' · ')\n if (blocked === 'invalid-key') {\n return { title: 'errorInvalidKey', hint: 'errorInvalidKeyHint', detail }\n }\n if (blocked === 'service-unavailable') {\n return { title: 'errorServiceUnavailable', hint: 'errorServiceUnavailableHint', detail }\n }\n if (blocked === 'network') {\n return { title: 'errorNetwork', hint: 'errorNetworkHint', detail }\n }\n if (blocked === 'invalid-response') {\n return { title: 'errorInvalidResponse', hint: 'errorInvalidResponseHint', detail }\n }\n // A transport-level failure (unmounted Remote, offline browser) arrives as\n // the controller's own error rather than as a blocked report.\n if (state.status === 'error' && state.report === undefined) {\n return { title: 'errorGeneric', hint: 'errorGeneric', detail: state.error ?? '' }\n }\n return undefined\n}\n\n/**\n * Every panel string, resolved once per projection through the translator.\n * One object with all keys (rather than per-field lookups in the components)\n * keeps the copy table and the render sites in lockstep: a key cannot be read\n * from `text` unless {@link PANEL_KEYS} declares it.\n */\nfunction panelStrings(t: PanelTranslator): Record<PanelKey, string> {\n const out = {} as Record<PanelKey, string>\n for (const key of PANEL_KEYS) out[key] = t(key)\n return out\n}\n\n/**\n * Project the shared usage snapshot into the panel's render tree.\n *\n * Deduplication matches the settings card: hand-edited settings can name one\n * credential twice.\n */\nexport function buildPanelView(input: PanelViewInput): PanelView {\n const { usage } = input\n const t = input.t ?? panelTextEN\n const seen = new Set<string>()\n const entries = (usage.report?.accounts ?? []).filter((entry) => {\n if (seen.has(entry.id)) return false\n seen.add(entry.id)\n return true\n })\n const accounts = entries.map((entry) => accountView(entry, t))\n const selectedEntry = entries.find((entry) => entry.active) ?? entries[0]\n const selectedView = accounts.find((view) => view.id === selectedEntry?.id)\n\n // The footer card stacks BOTH quota windows — the two limits an account\n // actually runs into — 5-hour first (the tighter and nearer one), then\n // weekly. `barPercent` clamps the fill; the printed percentage keeps the true\n // consumption, so an over-cap window still reads 150%.\n const footerBars: PanelFooterBar[] = []\n const windowBars: Array<[PanelKey, WindowInput | undefined]> = [\n ['fiveHourShort', selectedEntry?.report.credits?.fiveHour],\n ['weeklyShort', selectedEntry?.report.credits?.weekly],\n ]\n for (const [label, window] of windowBars) {\n if (window === undefined || window.cap <= 0) continue\n const percent = rawPercent(window.used, window.cap)\n footerBars.push({\n label,\n percent: `${percent}%`,\n barPercent: barPercent(percent),\n warn: window.exceeded,\n detail: `${money(window.used)} / ${money(window.cap)}`,\n })\n }\n\n // The card's one non-ratio figure: what this period has cost in dollars.\n const totalCost = selectedEntry?.report.usage?.totalCost\n const cost = totalCost === undefined ? '' : money(totalCost)\n\n let status = ''\n if (entries.length > 0 && !entries.some(entry => entry.configured)) status = t('unconfigured')\n else if (selectedView?.mark !== undefined && selectedView.mark !== 'active') status = t(selectedView.mark)\n else if (selectedEntry === undefined) status = t('unavailable')\n\n const planName = selectedView !== undefined && selectedView.planName !== '' ? selectedView.planName : t('nav')\n // `planName` falls back to the panel name, so it is only a second part when it\n // actually names a plan — otherwise the title would read `Command Code ·\n // Command Code`.\n const titleParts = planName === t('nav') ? [planName] : [t('nav'), planName]\n for (const bar of footerBars) {\n const figures = bar.detail === '' ? '' : ` ${bar.detail}`\n titleParts.push(`${t(bar.label)}${figures} (${bar.percent})`)\n }\n if (cost !== '') titleParts.push(`${t('spend')} ${cost}`)\n\n return {\n text: panelStrings(t),\n planName,\n status,\n footerBars,\n cost,\n footTitle: titleParts.join(' · '),\n accounts,\n selectedId: selectedEntry?.id,\n selected: selectedView,\n loading: usage.status === 'loading' && usage.report === undefined,\n noKey: entries.length > 0 && !entries.some(entry => entry.configured),\n failure: failureView(usage),\n staleError: usage.status === 'error' && usage.report !== undefined ? usage.error ?? '' : undefined,\n partial: (usage.report?.accounts.some((entry) => entry.report.failures.length > 0 && entry.report.blocked === undefined) ?? false)\n ? 'partial'\n : undefined,\n updatedAt: timeText(usage.fetchedAt ?? 0),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auto refresh (one shared loop, started by whichever surface mounts first)\n// ---------------------------------------------------------------------------\n\n/**\n * How often the panel re-reads the report while a surface is mounted. The\n * quota windows move slowly and one report costs four upstream calls, so this\n * is a background freshness tick, not a live meter.\n */\nexport const PANEL_AUTO_REFRESH_MS = 120_000\n\n/** The narrow face of `CommandCodeUsageController` this module drives. */\nexport interface RefreshSource {\n state(): UsagePageState\n refresh(): Promise<void>\n}\n\n/** Timer seam: injectable so tests never wait on real time. */\nexport interface AutoRefreshTimer {\n set(callback: () => void, ms: number): unknown\n clear(handle: unknown): void\n}\n\n/** The default timer (the client bundle runs in a browser; node tests inject one). */\nconst REAL_TIMER: AutoRefreshTimer = {\n set: (callback, ms) => setTimeout(callback, ms),\n clear: (handle) => clearTimeout(handle as ReturnType<typeof setTimeout>),\n}\n\n/** Live mount count of {@link startPanelAutoRefresh}. */\nlet references = 0\n/** Owner ticket of the running loop, if any. */\nlet activeTicket: number | undefined\n/** Ticket handed to the next starter. */\nlet ticketSeq = 0\n/** Pending timer handle of the running loop. */\nlet handle: unknown\n\n/**\n * Start the shared auto refresh. One fetch when the surface appears (the\n * sidebar row is the point of the panel — it must be current, not wait for a\n * click), then a tick every {@link PANEL_AUTO_REFRESH_MS} while a surface\n * stays mounted.\n *\n * Reference-counted: the sidebar entry and the dashboard can be mounted at\n * once, so only the first start fetches and only the last stop halts the loop.\n * Every tick goes through `usage.refresh()`, which already collapses a\n * concurrent fetch onto the in-flight one — a tick never double-fetches\n * against the settings page's own refresh.\n *\n * @param usage - the shared usage controller.\n * @param isConfigured - whether a credential exists right now (re-read per tick).\n * @param timer - timer seam for tests.\n * @returns the disposer that drops this surface's reference.\n */\nexport function startPanelAutoRefresh(\n usage: RefreshSource,\n isConfigured: () => boolean,\n timer: AutoRefreshTimer = REAL_TIMER,\n): () => void {\n references += 1\n const ticket = ++ticketSeq\n const tick = (): void => {\n if (activeTicket !== ticket) return\n if (isConfigured()) void usage.refresh()\n handle = timer.set(tick, PANEL_AUTO_REFRESH_MS)\n }\n\n if (activeTicket === undefined) {\n activeTicket = ticket\n handle = timer.set(tick, PANEL_AUTO_REFRESH_MS)\n // First paint: refresh immediately so the row is never blank on arrival.\n if (isConfigured()) void usage.refresh()\n }\n\n let stopped = false\n return () => {\n if (stopped) return\n stopped = true\n references -= 1\n // Still mounted elsewhere: drop this reference only. Note the check is the\n // REFCOUNT, not this surface's ticket — the surface that started the loop\n // is not necessarily the last one to unmount, and a first-unmounted owner\n // must not be the reason a tick keeps firing.\n if (references > 0) return\n activeTicket = undefined\n if (handle !== undefined) {\n timer.clear(handle)\n handle = undefined\n }\n }\n}\n\n/**\n * Drop every live reference and halt the loop without a timer.\n *\n * Exported for tests only: the loop's state is module-level on purpose (two\n * surfaces, one upstream poll), so a test that mounts a surface must be able\n * to start from a clean slate. Production code releases through the disposer\n * {@link startPanelAutoRefresh} returns — the plugin's fiber unwinds it.\n */\nexport function resetPanelAutoRefresh(): void {\n references = 0\n activeTicket = undefined\n handle = undefined\n}\n","/**\n * React components for the Command Code plans & quota panel (browser half):\n * the sidebar footer card and the dashboard it opens in the center column.\n *\n * Both render one {@link PanelView} projected by `./panel.ts` — no fact is\n * derived here. Strings arrive already localized in `view.text`: the slots\n * declare the `panel.commandcode` locale namespace, so the renderer hands this\n * component a `t` seat that is passed into `buildPanelView` — the panel follows\n * the harness's active language (a language switch mints a new `t`, so the\n * surfaces re-render without an extra channel).\n *\n * The footer card is the panel's home: the sidebar shell renders it in the foot\n * area directly above the Settings seat, so each quota window's own spend and\n * limit — the 5-hour and the weekly one — are on screen without opening\n * anything. Clicking it selects the `main` panel this file also renders — and\n * unlike a `sidebar.panellist` row, whose button chrome and label the SHELL\n * owns, this entry owns its whole surface and therefore calls `open()` itself.\n *\n * Styles ride the stylesheet `./panel-styles.ts` returns, injected once by\n * the client entry; classes are `ccp-` prefixed to stay clear of the settings\n * page's `cc-` set.\n *\n * @module dsh-commandcode-provider/client/panel-view\n */\n\nimport { useEffect, useState } from 'react'\nimport { Button } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SnapshotStore } from './snapshot-store.ts'\nimport type { UsagePageState } from './usage.ts'\nimport type { SettingsPageState } from './settings.ts'\nimport { buildPanelView } from './panel.ts'\nimport type { PanelAccountView, PanelStatView, PanelView, PanelWindowView } from './panel.ts'\nimport { panelTextEN } from './panel-copy.ts'\nimport type { PanelKey } from './panel-copy.ts'\n// SlotMap merge for `main` / `sidebar.footer.action` (load-bearing: the slots\n// this file's components register into are typed only by that augmentation).\nimport './panel-slots.ts'\n\n/**\n * Owner share of the sidebar-foot action hole: the shell renders the foot area\n * and hands each action only the column fold state. There is no button chrome\n * and no `label` seat — the entry is the whole surface.\n */\nexport interface SidebarFooterActionOwnerProps {\n /** Whether the sidebar renders wide content (false = 56px rail). */\n wide: boolean\n}\n\n/**\n * The injected face both panel slots carry. Bound by the client entry so the\n * components stay unaware of the settings controller, the login controller,\n * the layout service and the module-level auto-refresh loop.\n *\n * NOTE the split from {@link PanelComponentProps}: this is the face the\n * registration's `inject` factory RETURNS, and the renderer does not hand it to\n * the component verbatim. `bindInjectSources` destructures the `hooks`\n * compartment OUT of the face and re-exposes each member as a `use<Name>` prop\n * (`commandCodeUsage` → `useCommandCodeUsage`). A component that reads\n * `props.hooks.*` therefore finds `undefined` at runtime and crashes on render\n * — which the slot renderer contains by ABDICATING the entry, so the surface\n * vanishes with no visible error. Read the `useX` seats instead.\n */\nexport interface PanelInjected {\n hooks: {\n commandCodeUsage: SnapshotStore<UsagePageState>\n commandCodeSettings: SnapshotStore<SettingsPageState>\n }\n /** Fetch the report now (the dashboard's Refresh action). */\n refresh(): void\n /**\n * Leave the dashboard and show the Conversation again\n * (`ctx.layout.selectPanel(null)`; the current Session is untouched).\n */\n close(): void\n /** Start the shared background poll for this mount; returns its disposer. */\n startAutoRefresh(): () => void\n /** Select this panel in the center column (`ctx.layout.selectPanel`). */\n open(): void\n}\n\n/**\n * The props a panel component actually receives: the bound `useX` seats (what\n * {@link PanelInjected}'s `hooks` compartment becomes), the pass-through\n * actions, and no raw `hooks` key.\n *\n * `buildPanelView` is cheap (one pass over the account list) and recomputing it\n * per notification is what keeps a store update from ever rendering a stale\n * quota, so the selector is deliberately the whole snapshot.\n */\nexport interface PanelComponentProps {\n useCommandCodeUsage<T>(selector: (state: UsagePageState) => T): T\n useCommandCodeSettings<T>(selector: (state: SettingsPageState) => T): T\n /**\n * Locale seat for the `panel.commandcode` namespace, bound by the\n * registration's own `locale` declaration. Optional so a missing locale face\n * degrades to English instead of crashing the surface.\n */\n t?: Translate<PanelKey>\n refresh(): void\n close(): void\n startAutoRefresh(): () => void\n open(): void\n}\n\n/** Props of the sidebar footer card: the panel face plus the shell's fold state. */\nexport interface CommandCodeFooterEntryProps extends PanelComponentProps, SidebarFooterActionOwnerProps {}\n\n/** The panel's view, recomputed from both seats on every notification. */\nfunction usePanelView(props: PanelComponentProps): PanelView {\n const usage = props.useCommandCodeUsage((state) => state)\n const settings = props.useCommandCodeSettings((state) => state)\n return buildPanelView({\n usage,\n apiKeyConfigured: settings.anyAccountConfigured,\n t: props.t ?? panelTextEN,\n })\n}\n\n/**\n * The quota ring. One glyph serves the rail button, the footer card's top row\n * and the dashboard header: a faint track plus an arc whose sweep is the\n * consumption, drawn from 12 o'clock. Circumference 2πr = 45.55 at r = 7.25.\n */\nfunction Ring({ percent, warn, size }: { percent: number; warn: boolean; size: number }) {\n const clamped = Math.min(100, Math.max(0, percent))\n const circumference = 45.55\n // Rounded to three decimals: the raw product lands on floats like\n // 34.162499999999994, which is a needless DOM diff churn.\n const dashoffset = Math.round(circumference * (1 - clamped / 100) * 1000) / 1000\n return (\n <span className=\"ccp-glyph\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 20 20\" width={size} height={size} focusable=\"false\">\n <circle cx=\"10\" cy=\"10\" r=\"7.25\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" opacity=\"0.4\" />\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"7.25\"\n fill=\"none\"\n stroke={warn ? 'var(--dsw-alias-state-error-primary)' : 'currentColor'}\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeDasharray={String(circumference)}\n strokeDashoffset={String(dashoffset)}\n transform=\"rotate(-90 10 10)\"\n />\n </svg>\n </span>\n )\n}\n\n/** One labelled bar. `compact` drops the reset line; the footer draws its own. */\nfunction QuotaBar({ label, value, percent, barPercent, warn, resetsAt, resetsLabel }: {\n label: string\n value: string\n percent: string\n barPercent: number\n warn: string\n resetsAt: string\n resetsLabel: string\n}) {\n const clamped = Math.min(100, Math.max(0, barPercent))\n return (\n <div className=\"ccp-window\">\n <div className=\"ccp-windowHead\">\n <span className=\"ccp-windowLabel\">{label}</span>\n {warn !== '' ? <span className=\"ccp-warnTag\">{warn}</span> : null}\n <span className=\"ccp-spacer\" />\n {value !== '' ? <span className=\"ccp-windowValue\">{value}</span> : null}\n <span className=\"ccp-windowPct\">{percent}</span>\n </div>\n <div className=\"ccp-bar\" role=\"progressbar\" aria-label={label} aria-valuemin={0} aria-valuemax={100} aria-valuenow={clamped}>\n <div className={warn !== '' ? 'ccp-barFill ccp-barFillWarn' : 'ccp-barFill'} style={{ width: `${clamped}%` }} />\n </div>\n {resetsAt !== '' ? <p className=\"ccp-windowReset\">{resetsLabel} {resetsAt}</p> : null}\n </div>\n )\n}\n\n/** A labelled figure. */\nfunction Tile({ label, value, sub }: { label: string; value: string; sub?: string }) {\n return (\n <div className=\"ccp-tile\">\n <span className=\"ccp-tileLabel\">{label}</span>\n <span className=\"ccp-tileValue\">{value}</span>\n {sub !== undefined && sub !== '' ? <span className=\"ccp-tileSub\">{sub}</span> : null}\n </div>\n )\n}\n\n/** One usage tile. */\nfunction StatTile({ stat, label }: { stat: PanelStatView; label: string }) {\n return <Tile label={label} value={stat.value} sub={stat.sub} />\n}\n\n/** The rotation/credential badge line for one account. */\nfunction markText(account: PanelAccountView, text: (key: PanelKey) => string): string {\n if (account.mark === undefined) return ''\n if (account.mark === 'coolingDown' && account.cooldownUntil !== '') {\n return `${text('coolingDown')} · ${account.cooldownUntil}`\n }\n return text(account.mark)\n}\n\n/** `Default account` → `D`; used for the card's monogram chip. */\nfunction initial(label: string): string {\n const trimmed = label.trim()\n return trimmed === '' ? '?' : trimmed[0]!.toUpperCase()\n}\n\n/**\n * One account's full report: the monthly limit/usage bar, the two quota\n * windows, then the credit and usage totals.\n */\nfunction AccountCard({ account, view }: { account: PanelAccountView; view: PanelView }) {\n const text = (key: PanelKey): string => view.text[key] ?? key\n const mark = markText(account, text)\n const monthly = account.monthly\n\n return (\n <section className=\"ccp-card\" aria-label={account.label}>\n <header className=\"ccp-cardHead\">\n <span className=\"ccp-avatar\" aria-hidden=\"true\">{initial(account.label)}</span>\n <span className=\"ccp-cardIdentity\">\n <span className=\"ccp-cardTitle\">{account.label}</span>\n {account.owner !== '' ? <span className=\"ccp-cardOwner\">{account.owner}</span> : null}\n </span>\n <span className=\"ccp-spacer\" />\n {account.planName !== '' ? <span className=\"ccp-badge\">{account.planName}</span> : null}\n {account.planStatus !== '' ? <span className=\"ccp-badge ccp-badgeWarn\">{account.planStatus}</span> : null}\n {mark !== '' ? (\n <span className={account.mark === 'invalidKey' ? 'ccp-badge ccp-badgeError' : 'ccp-badgeMuted'}>{mark}</span>\n ) : null}\n {account.periodEnds !== '' ? (\n <span className=\"ccp-meta\">{text('periodEnds')} {account.periodEnds}</span>\n ) : null}\n </header>\n\n {account.unconfigured ? <p className=\"ccp-hint\">{text('unconfigured')}</p> : null}\n\n {monthly !== undefined && monthly.known ? (\n <QuotaBar\n label={text('monthly')}\n value={`${monthly.used} / ${monthly.limit}`}\n percent={`${monthly.percent}%`}\n barPercent={monthly.barPercent}\n warn={monthly.exhausted ? text('exhausted') : ''}\n resetsAt=\"\"\n resetsLabel=\"\"\n />\n ) : (\n <div className=\"ccp-planRow\">\n {/* The plan is a fact the card already shows in its header badge; what\n is missing here is the RATIO, so the row names the plan whenever\n the report carries one and falls back to a placeholder only when\n the report itself is silent. */}\n <span className=\"ccp-fieldLabel\">{text('plan')}</span>\n <span className=\"ccp-planName\">{account.planName !== '' ? account.planName : text('unavailable')}</span>\n </div>\n )}\n\n {/* A balance the billing endpoint DID report, so a card without a ratio\n still states something true instead of nothing. */}\n {monthly !== undefined && monthly.remaining !== '—' ? (\n <div className=\"ccp-planRow\">\n <span className=\"ccp-fieldLabel\">{text('remaining')}</span>\n <span className=\"ccp-planName\">{monthly.remaining}</span>\n </div>\n ) : null}\n\n {account.windows.length > 0 ? (\n <div className=\"ccp-windows\">\n {account.windows.map((window: PanelWindowView) => (\n <QuotaBar\n key={window.label}\n label={text(window.label)}\n value={window.value}\n percent={window.capped ? `${window.percent}%` : text('windowUnlimited')}\n barPercent={window.barPercent}\n warn={window.exceeded ? text('exceeded') : ''}\n resetsAt={window.resetsAt}\n resetsLabel={text('resets')}\n />\n ))}\n </div>\n ) : null}\n\n {monthly !== undefined ? (\n <div className=\"ccp-block\">\n <h4 className=\"ccp-blockTitle\">{text('credits')}</h4>\n <div className=\"ccp-tiles\">\n <Tile label={text('monthlyLimit')} value={monthly.limit} />\n <Tile label={text('monthlyUsed')} value={monthly.used} />\n <Tile label={text('remaining')} value={monthly.remaining} />\n <Tile label={text('purchased')} value={monthly.purchased} />\n <Tile label={text('free')} value={monthly.free} />\n </div>\n </div>\n ) : null}\n\n {account.stats.length > 0 ? (\n <div className=\"ccp-block\">\n <h4 className=\"ccp-blockTitle\">{text('usage')}</h4>\n <div className=\"ccp-tiles\">\n {account.stats.map((stat) => (\n <StatTile key={stat.label} stat={stat} label={text(stat.label)} />\n ))}\n </div>\n </div>\n ) : null}\n </section>\n )\n}\n\n/**\n * The center-column dashboard, registered into the layout's keyed `main` slot\n * under the same id the footer card selects, so the two are one navigation\n * entry: the card shows the plan, the monthly bar and the quota window; the\n * panel shows everything, including the per-account breakdown.\n */\nexport function CommandCodePanel(props: PanelComponentProps) {\n const view = usePanelView(props)\n const text = (key: PanelKey): string => view.text[key] ?? key\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\n\n const startAutoRefresh = props.startAutoRefresh\n useEffect(() => startAutoRefresh(), [startAutoRefresh])\n\n const accounts = view.accounts\n const selected = accounts.find((account) => account.id === selectedId)\n ?? view.selected\n ?? accounts[0]\n\n return (\n <div className=\"ccp-main\" role=\"region\" aria-label={text('nav')}>\n <div className=\"ccp-mainInner\">\n <header className=\"ccp-header\">\n <div className=\"ccp-headerText\">\n <h2 className=\"ccp-title\">{text('nav')}</h2>\n <p className=\"ccp-subtitle\">{text('subtitle')}</p>\n </div>\n <span className=\"ccp-spacer\" />\n {view.updatedAt !== '' ? <span className=\"ccp-meta\">{text('updated')} {view.updatedAt}</span> : null}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={view.loading}\n onClick={() => props.refresh()}\n >\n {view.loading ? text('refreshing') : text('refresh')}\n </Button>\n {/* The dashboard REPLACES the conversation in the center column, and\n this panel is the only surface that selects it — without an exit\n the user cannot get back to the session at all (issue #41), since\n clicking the sidebar card only re-selects this same panel. The\n glyph is the button's whole content, so its accessible name and\n tooltip carry the meaning. */}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ccp-close\"\n aria-label={text('close')}\n title={text('closeHint')}\n onClick={() => props.close()}\n >\n <span aria-hidden=\"true\">×</span>\n </Button>\n </header>\n\n {view.noKey ? (\n <div className=\"ccp-notice\">\n <p className=\"ccp-noticeTitle\">{text('noKey')}</p>\n <p className=\"ccp-noticeHint\">{text('noKeyHint')}</p>\n </div>\n ) : null}\n\n {view.failure !== undefined ? (\n <div className=\"ccp-notice ccp-noticeError\" role=\"alert\">\n <p className=\"ccp-noticeTitle\">{text(view.failure.title)}</p>\n <p className=\"ccp-noticeHint\">{text(view.failure.hint)}</p>\n {view.failure.detail !== '' ? <p className=\"ccp-noticeDetail\">{view.failure.detail}</p> : null}\n </div>\n ) : null}\n\n {!view.noKey && view.failure === undefined && accounts.length === 0 && view.loading ? (\n <p className=\"ccp-hint\">{text('loading')}</p>\n ) : null}\n\n {view.staleError !== undefined && view.staleError !== '' ? (\n <p className=\"ccp-hint\" role=\"status\">{text('errorGeneric')} — {view.staleError}</p>\n ) : null}\n\n {accounts.length > 1 ? (\n <div className=\"ccp-tabs\" role=\"tablist\" aria-label={text('nav')}>\n {accounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected?.id === account.id}\n className={selected?.id === account.id ? 'ccp-tab ccp-tabActive' : 'ccp-tab'}\n onClick={() => setSelectedId(account.id)}\n >\n {account.label}\n </button>\n ))}\n </div>\n ) : null}\n\n {selected !== undefined ? <AccountCard account={selected} view={view} /> : null}\n\n {view.partial !== undefined ? <p className=\"ccp-hint\">{text(view.partial)}</p> : null}\n </div>\n </div>\n )\n}\n\n/**\n * The sidebar footer card, registered into `sidebar.footer.action` — the list\n * the shell renders in the sidebar's foot area directly ABOVE the Settings\n * seat, so the panel reads as a bottom-pinned sibling of Settings rather than\n * a global panel icon at the top of the column.\n *\n * The shell wraps nothing here, so this component owns the surface: the\n * button, its chrome and its accessible name. In the expanded column it draws\n * the title row, then one block per quota window (5-hour, then weekly) — the\n * window's own spend and limit (`$1.32 / $6.00`), its percentage and its bar —\n * and nothing else: the card's figures are the two windows the account runs\n * into, so the period total stays in the tooltip rather than taking a third\n * line. In the 56px rail it collapses to a 36px icon button carrying the ring,\n * matching the shell's own rail geometry. `wide` comes from the shell as an\n * owner prop — unlike the old `sidebar.panellist` row, this slot really does\n * supply it.\n *\n * Rendering is gated on the settings page's `showSidebarQuota` toggle, which\n * defaults OFF: a fresh install shows no quota surface in the sidebar and runs\n * no background poll. The gate reads the STORED document (the settings\n * controller's `sidebarQuota` fact), so an unsaved draft cannot show the card,\n * while a landed save flips it live. The entry is still REGISTERED — this is a\n * render decision, not a slot registration, so nothing churns the slot ledger.\n */\nexport function CommandCodeFooterEntry(props: CommandCodeFooterEntryProps) {\n // The card is opt-in (`showSidebarQuota`, default off) and follows the\n // STORED document, never the settings page's staged draft — see\n // `SettingsPageState.sidebarQuota`. While it is hidden this component renders\n // NOTHING — no expanded card, no rail icon — and starts no background usage\n // poll; the dashboard cell stays registered but has no trigger, which is\n // exactly what \"hide the quota display\" means.\n const visible = props.useCommandCodeSettings((snapshot) => snapshot.sidebarQuota)\n const view = usePanelView(props)\n\n const startAutoRefresh = props.startAutoRefresh\n useEffect(() => {\n if (!visible) return undefined\n return startAutoRefresh()\n }, [visible, startAutoRefresh])\n\n if (!visible) return null\n\n const text = (key: PanelKey): string => view.text[key] ?? key\n // The ring tracks the tightest window — the 5-hour one whenever it is capped,\n // which is the limit an account actually runs into first. `footerBars` is\n // ordered that way, so the leading bar is the headline.\n const headline = view.footerBars[0]\n // The tooltip doubles as the accessible name; it always begins with the\n // visible title, so the label the user reads is contained in the name.\n const title = view.footTitle\n\n if (!props.wide) {\n return (\n <button\n type=\"button\"\n className=\"ccp-railButton\"\n aria-label={title}\n title={title}\n onClick={() => props.open()}\n >\n <Ring percent={headline?.barPercent ?? 0} warn={headline?.warn ?? false} size={18} />\n </button>\n )\n }\n\n return (\n <button\n type=\"button\"\n className=\"ccp-foot\"\n aria-label={title}\n title={title}\n onClick={() => props.open()}\n >\n <span className=\"ccp-footTop\">\n <Ring percent={headline?.barPercent ?? 0} warn={headline?.warn ?? false} size={16} />\n <span className=\"ccp-footName\">{text('nav')}</span>\n <span className=\"ccp-spacer\" />\n {view.status !== '' ? (\n <span className=\"ccp-badgeMuted\">{view.status}</span>\n ) : view.planName !== text('nav') ? (\n <span className=\"ccp-badge\">{view.planName}</span>\n ) : null}\n </span>\n\n {view.footerBars.map((bar) => (\n <span className=\"ccp-footRow\" key={bar.label}>\n <span className=\"ccp-footHead\">\n <span className=\"ccp-footLabel\">{text(bar.label)}</span>\n <span className=\"ccp-spacer\" />\n {bar.detail !== '' ? <span className=\"ccp-footAmount\">{bar.detail}</span> : null}\n <span className=\"ccp-footPct\">{bar.percent}</span>\n </span>\n <span className=\"ccp-footBar\">\n <span\n className={bar.warn ? 'ccp-footFill ccp-footFillWarn' : 'ccp-footFill'}\n style={{ width: `${bar.barPercent}%` }}\n />\n </span>\n </span>\n ))}\n </button>\n )\n}\n","/** Shared, JSON-only billing facts. No Host or browser runtime imports. */\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from './usage-wire.ts'\n\nexport interface CostTokens {\n uncachedInputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheWriteTokens: number\n}\n\n/** Requests with identical model/rates are folded into one group. */\nexport interface CostUsageGroup {\n provider: string\n model: string\n at: number | null\n contextTokens: number\n tokens: CostTokens\n}\n\nexport interface SessionCostFacts {\n pricingKey: number\n groups: CostUsageGroup[]\n}\n\nexport const zeroCostTokens = (): CostTokens => ({ uncachedInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 })\nexport const COST_TOKEN_KEYS = ['uncachedInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens'] as const\n\nexport function peakHour(at: number, windows: ReadonlyArray<readonly [number, number]>): boolean {\n const time = new Date(at)\n return time.getUTCDay() !== 0 && time.getUTCDay() !== 6\n && windows.some(([start, end]) => time.getUTCHours() >= start && time.getUTCHours() < end)\n}\n\n/**\n * All prompt billing buckets determine a request's band, never cumulative session input.\n *\n * A tiered model returns the matching band and does NOT then apply `peak`: the\n * page publishes those two dimensions independently, no row carries both today,\n * and the generator would report a tiered row on every sync — so the combination\n * becoming real is visible before it reaches a user. This ordering is a latent\n * choice, not a verified upstream rule.\n */\nexport function requestRates(price: CommandCodeModelPrice, at: number | null, contextTokens: number, table: CommandCodePriceTable): CommandCodeModelRates {\n // The first band whose bound accepts the prompt. ORDER IS LOAD-BEARING, and\n // both producers enforce it: the generator refuses non-ascending bounds or a\n // bounded last band, and the wire parser rejects the same shapes — so a\n // conforming table cannot present bands out of order, and this `find` cannot\n // select a band a later one should have won.\n const tier = price.contextTiers?.find(tier => tier.maxContext === undefined || contextTokens <= tier.maxContext)\n if (tier !== undefined) return tier\n return price.peak !== undefined && at !== null && peakHour(at, table.peakHours) ? price.peak : price\n}\n\n/** Cache version and wire guard: changing bands/rates must refold historical groups. */\nexport function pricingKey(table: CommandCodePriceTable): number {\n const rates = (r: CommandCodeModelRates) => [r.inputCost, r.outputCost, r.cacheReadCost, r.cacheWriteCost ?? null]\n const canonical = JSON.stringify(['commandCodeCost-v1', table.peakHours, table.models.map(p => [p.id, p.slug, p.free === true, rates(p), p.peak ? rates(p.peak) : null, p.contextTiers?.map(t => [t.maxContext ?? null, rates(t)]) ?? null])])\n let hash = 2166136261\n for (const c of canonical) hash = Math.imul(hash ^ c.charCodeAt(0), 16777619) >>> 0\n return hash\n}\n\n/** Only safe to merge requests whose billing classification is identical. */\nexport function costGroupKey(group: CostUsageGroup, table: CommandCodePriceTable): string {\n const price = table.models.find(p => p.id === group.model || p.slug === group.model)\n return JSON.stringify([group.provider, group.model, price === undefined ? null : requestRates(price, group.at, group.contextTokens, table), group.at === null])\n}\n","/**\n * Session-cost view model for the composer readout.\n *\n * Deliberately JSX-free and React-free, mirroring `./panel.ts`: it turns the\n * session's token accounting plus the Host's price table into one presentation\n * value AND the exact text the two surfaces of the harness's token-usage UI\n * receive — the amount appended to the shipped pill, and the rows appended to\n * the shipped usage dialog. Node tests therefore drive the whole calculation,\n * and every user-visible string, without a DOM.\n *\n * The figures it prices are the session's DURABLE cumulative buckets, which is\n * what the composer's own \"N tokens\" pill reads too (`tokenUsage`), so the two\n * surfaces can never disagree about how much was used. Dollars are computed\n * here because Command Code publishes per-token rates and bills against\n * dollar-denominated windows; the account's own reported `totalCost` is a\n * billing PERIOD figure, not this session's.\n *\n * Three rules are load-bearing:\n *\n * 1. **Only Command Code usage is priced.** A session served by another\n * provider must render nothing, never a Command Code estimate.\n * 2. **A missing rate is never invented.** The pricing page publishes\n * input/output/cache-read rates for every model but a cache-WRITE rate for\n * only some, so unpriced cache-write tokens are surfaced as such rather than\n * charged at a guessed multiple of the input rate.\n * 3. **Unpriceable means invisible.** No usage, no model, no table, an unknown\n * model, or all-zero buckets renders nothing at all — a confident `$0.00`\n * would be a lie, and this module never returns one.\n *\n * @module dsh-commandcode-provider/client/session-cost\n */\n\nimport { COST_TOKEN_KEYS, pricingKey, requestRates, peakHour, zeroCostTokens, type SessionCostFacts } from '../cost-facts.ts'\nimport type { CommandCodeModelPrice, CommandCodeModelRates, CommandCodePriceTable } from '../usage-wire.ts'\nimport { formatMoney, formatMoneyExact, formatTokensCompact } from './usage.ts'\n\n/** Tokens per published rate unit — the pricing page quotes USD per million. */\nconst TOKENS_PER_RATE_UNIT = 1_000_000\n\n/** The provider route whose usage this surface prices. */\nconst COMMANDCODE_PROVIDER = 'commandcode'\n\n/**\n * The English copy for this surface.\n *\n * A plain constant, NOT the `settings.commandcode` locale namespace: like the\n * plans & quota panel, the readout stays English on a Chinese harness. Do not\n * route it through `ctx.locale`.\n */\nexport const SESSION_COST_COPY = {\n /** Shown instead of an amount when the model costs nothing on every plan. */\n free: 'Free',\n /**\n * The separator the readout prefixes itself with, so the cost reads as the\n * last item of the token-usage pill's text run rather than a control beside\n * it. Rendered with the same colour and margins the shipped pill uses\n * between its own items.\n */\n separator: '·',\n /** The heading the tooltip leads with. */\n panelTitle: 'Session cost',\n /** Marks an estimate from published rates rather than an invoice. */\n approximate: '≈',\n /** Tooltip line for the unpriced cache-write tokens. */\n unpricedCacheWrite: 'cache write tokens have no published rate',\n /** Tooltip line naming the rate half in force. */\n peakRates: 'peak rates',\n /** Tooltip line naming the rate half in force. */\n offPeakRates: 'off-peak rates',\n /** Tooltip line explaining the approximate marker. */\n approximateNote: 'estimate from published rates, not the provider invoice',\n /** Row/tooltip label for uncached prompt tokens. */\n uncachedInput: 'uncached input',\n /** Row/tooltip label for completion tokens. */\n output: 'output',\n /** Row/tooltip label for cache-served input tokens. */\n cacheRead: 'cache read',\n /** Row/tooltip label for cache-written input tokens. */\n cacheWrite: 'cache write',\n} as const\n\n/**\n * The session's cumulative token buckets, as the `tokenUsage` projection\n * carries them. Declared structurally and defensively: this bundle does not\n * depend on the session-controller package, and a bucket the provider never\n * reported is absent rather than zero.\n */\nexport interface SessionUsageBuckets {\n readonly uncachedInputTokens?: number\n readonly outputTokens?: number\n readonly cacheReadTokens?: number\n readonly cacheWriteTokens?: number\n}\n\n/** One entry of the `modelSelection` projection. */\nexport interface SessionModelSelection {\n readonly provider: string\n readonly model: string\n}\n\n/**\n * The `modelSelection` projection: the selection the latest request consumed,\n * and the one the next request will use (falling back to the former).\n */\nexport interface SessionModelSelectionProjection {\n readonly lastUsed: SessionModelSelection | null\n readonly next: SessionModelSelection | null\n}\n\n/** Everything the view needs, already read off the seats by the component. */\nexport interface SessionCostInput {\n /** Durable billing groups; absent on older Hosts means no trustworthy estimate. */\n facts?: SessionCostFacts | undefined\n /** The durable cumulative token buckets, or undefined before any request. */\n usage: SessionUsageBuckets | undefined\n /** The session's model selection fold, or undefined on an older Host. */\n selection: SessionModelSelectionProjection | undefined\n /** The Host's price table, or undefined until it lands. */\n table: CommandCodePriceTable | undefined\n /** Legacy caller field; historical request timestamps alone determine rates. */\n now: number\n}\n\n/** One bucket's line in the usage dialog. */\nexport interface SessionCostBucketRow {\n /** Stable key. */\n key: 'uncachedInput' | 'cacheRead' | 'cacheWrite' | 'output'\n /** Row label. */\n label: string\n /** Tokens charged in this bucket; a bucket that charged nothing withholds its\n * row rather than printing a meaningless zero. */\n tokens: number\n /** What this bucket cost, or undefined when the table has no rate for it. */\n costText: string | undefined\n}\n\n/** The composer readout's presentation value. */\nexport interface SessionCostView {\n /** Priced total in dollars. */\n total: number\n /** Visible amount text, e.g. `$0.0123` (or the free word, when free). */\n value: string\n /** Full tooltip/accessible text, including the bucket breakdown. */\n title: string\n /** Per-bucket lines for the usage dialog, in reading order. */\n rows: SessionCostBucketRow[]\n /** Caveat lines for the pill's tooltip (rate half, approximation, unpriced). */\n notes: string[]\n /** The model costs nothing on every plan right now. */\n free: boolean\n /** The model's `peak` rates are in force. */\n peak: boolean\n /** Cache-write tokens the table has no rate for (never guessed, so the\n * total is a floor rather than an estimate). */\n unpricedCacheWriteTokens: number\n /** Published-rate totals are estimates rather than provider invoices. */\n approximate: boolean\n}\n\n/** A finite, non-negative count — anything else reads as absent. */\nfunction count(value: number | undefined): number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0\n}\n\n/**\n * Whether `now` falls inside a peak-pricing window, per the windows that travel\n * with the price table. Monday–Friday (UTC) only, and each window is\n * end-exclusive — the same rule the Host snapshot applies when it labels the\n * model picker. The schedule is read from the wire rather than restated so\n * there is one definition of the windows, on the Host.\n */\nexport function isPeakHour(now: number, peakHours: ReadonlyArray<readonly [number, number]>): boolean {\n const at = new Date(now)\n const day = at.getUTCDay()\n if (day === 0 || day === 6) return false\n const hour = at.getUTCHours()\n return peakHours.some(([start, end]) => hour >= start && hour < end)\n}\n\n/**\n * Index a price table for lookup. Rows are keyed by catalog id and by pricing\n * slug, both exact and lowercased, because a session reports a catalog id while\n * a row no catalog model claims is served under the page's slug.\n */\nfunction indexTable(table: CommandCodePriceTable): Map<string, CommandCodeModelPrice> {\n const index = new Map<string, CommandCodeModelPrice>()\n for (const price of table.models) {\n for (const key of [price.id, price.slug]) {\n if (typeof key !== 'string' || key === '') continue\n if (!index.has(key)) index.set(key, price)\n const lower = key.toLowerCase()\n if (!index.has(lower)) index.set(lower, price)\n }\n }\n return index\n}\n\n/**\n * The dollar cost of each bucket, plus the total and the unpriced remainder.\n *\n * Every bucket is charged at its own published rate; the cache-write bucket\n * contributes only when the model publishes a rate for it, otherwise its tokens\n * are returned as {@link SessionCostView.unpricedCacheWriteTokens} and its own\n * cost stays undefined so the panel can say so instead of printing a zero.\n */\ninterface SessionCostBreakdown {\n uncachedInput: number\n cacheRead: number\n cacheWrite: number | undefined\n output: number\n total: number\n unpricedCacheWriteTokens: number\n}\n\nfunction costOf(\n usage: SessionUsageBuckets,\n rates: CommandCodeModelRates,\n free: boolean,\n): SessionCostBreakdown {\n if (free) {\n return { uncachedInput: 0, cacheRead: 0, cacheWrite: 0, output: 0, total: 0, unpricedCacheWriteTokens: 0 }\n }\n const perUnit = (tokens: number, rate: number): number => (tokens * rate) / TOKENS_PER_RATE_UNIT\n const uncachedInput = perUnit(count(usage.uncachedInputTokens), rates.inputCost)\n const output = perUnit(count(usage.outputTokens), rates.outputCost)\n const cacheRead = perUnit(count(usage.cacheReadTokens), rates.cacheReadCost)\n const cacheWriteTokens = count(usage.cacheWriteTokens)\n const cacheWrite = rates.cacheWriteCost === undefined\n ? undefined\n : perUnit(cacheWriteTokens, rates.cacheWriteCost)\n return {\n uncachedInput,\n cacheRead,\n cacheWrite,\n output,\n total: uncachedInput + output + cacheRead + (cacheWrite ?? 0),\n unpricedCacheWriteTokens: rates.cacheWriteCost === undefined ? cacheWriteTokens : 0,\n }\n}\n\n/**\n * Amount text for a session cost.\n *\n * The panel's `money()` convention (2 decimals, 4 below a cent) is right for\n * billing windows, but a live session total starts far below a cent, where\n * `toFixed(4)` would print a flat `$0.0000` — which reads as broken rather than\n * as small. So a total under $0.0001 is stated as a bound instead.\n */\nexport function sessionCostAmount(total: number): string {\n if (!Number.isFinite(total) || total <= 0) return formatMoney(0)\n if (total < 0.0001) return `<$0.0001`\n return total < 0.01 ? formatMoneyExact(total) : formatMoney(total)\n}\n\n/** One `label value` clause of the tooltip. */\nfunction clause(label: string, tokens: number): string | undefined {\n return tokens > 0 ? `${label} ${formatTokensCompact(tokens)}` : undefined\n}\n\n/**\n * Build the composer readout, or undefined when there is nothing honest to show.\n *\n * Undefined is the correct answer for a session with no usage yet, a session\n * another provider served, a model the price table does not know, and a table\n * that has not landed — the pill simply is not there.\n */\nexport function buildSessionCostView(input: SessionCostInput): SessionCostView | undefined {\n const { usage, table, facts } = input\n if (!usage || !table || !facts || facts.pricingKey !== pricingKey(table)) return undefined\n const totals = zeroCostTokens()\n const index = indexTable(table)\n const breakdown: SessionCostBreakdown = { uncachedInput: 0, cacheRead: 0, cacheWrite: 0, output: 0, total: 0, unpricedCacheWriteTokens: 0 }\n let free = true\n let peak = false\n let partial = false\n let priced = false\n const notes: string[] = []\n for (const group of facts.groups) {\n for (const key of COST_TOKEN_KEYS) totals[key] += group.tokens[key]\n if (group.provider !== COMMANDCODE_PROVIDER) { partial = true; continue }\n const price = index.get(group.model)\n if (!price) { partial = true; continue }\n const isFree = price.free === true\n free &&= isFree\n if (price.peak && group.at === null) {\n partial = true\n notes.push('request time unavailable; off-peak lower bound')\n }\n const rates = requestRates(price, group.at, group.contextTokens, table)\n const part = costOf(group.tokens, rates, isFree)\n priced ||= isFree || part.total > 0\n for (const key of ['uncachedInput', 'cacheRead', 'output', 'total', 'unpricedCacheWriteTokens'] as const) breakdown[key] += part[key]\n breakdown.cacheWrite = (breakdown.cacheWrite ?? 0) + (part.cacheWrite ?? 0)\n if (price.peak) {\n const isPeak = group.at !== null && peakHour(group.at, table.peakHours)\n peak ||= isPeak\n notes.push(isPeak ? SESSION_COST_COPY.peakRates : SESSION_COST_COPY.offPeakRates)\n }\n }\n // Both projections must describe the same durable cut. Never decorate token\n // rows from a newer/older fold, and never price an old Host's cumulative usage.\n if (COST_TOKEN_KEYS.some(key => totals[key] !== count(usage[key])) || !priced) return undefined\n const { total, unpricedCacheWriteTokens } = breakdown\n partial ||= unpricedCacheWriteTokens > 0\n free &&= !partial\n if (partial) notes.push('Command Code priced subtotal only; unpriced or other-provider usage excluded')\n notes.push(SESSION_COST_COPY.approximateNote)\n const uncachedInput = totals.uncachedInputTokens\n const output = totals.outputTokens\n const cacheRead = totals.cacheReadTokens\n const cacheWrite = totals.cacheWriteTokens\n // No billed token of any kind means there is nothing to report yet: a `$0.00`\n // pill on a session that has not made a request would be noise, not\n // information, and on a free model it would be redundant.\n if (uncachedInput === 0 && output === 0 && cacheRead === 0 && cacheWrite === 0) return undefined\n\n // Free priced groups do not establish zero spending for unpriced groups.\n // Keep the pure-Free label and real sub-cent amounts, but never a zero subtotal.\n if (!free && total <= 0) return undefined\n\n const value = free\n ? SESSION_COST_COPY.free\n : `${partial ? '≥' : SESSION_COST_COPY.approximate}${sessionCostAmount(total)}`\n const money = (amount: number | undefined): string | undefined =>\n amount === undefined ? undefined : sessionCostAmount(amount)\n // Reading order mirrors the prompt's own order: what was charged at the input\n // rate, then the two cache buckets, then what the model produced.\n const rows: SessionCostBucketRow[] = [\n { key: 'uncachedInput', label: SESSION_COST_COPY.uncachedInput, tokens: uncachedInput, costText: money(breakdown.uncachedInput) },\n { key: 'cacheRead', label: SESSION_COST_COPY.cacheRead, tokens: cacheRead, costText: money(breakdown.cacheRead) },\n { key: 'cacheWrite', label: SESSION_COST_COPY.cacheWrite, tokens: cacheWrite, costText: unpricedCacheWriteTokens === cacheWrite && cacheWrite > 0 ? undefined : money(breakdown.cacheWrite) },\n { key: 'output', label: SESSION_COST_COPY.output, tokens: output, costText: money(breakdown.output) },\n ]\n if (unpricedCacheWriteTokens > 0) notes.push(SESSION_COST_COPY.unpricedCacheWrite)\n // Empty clauses are dropped BEFORE joining: `clause()` returns undefined for a\n // bucket with no tokens, and joining the raw list would leave a `· ·` gap for\n // every absent bucket — a tooltip that reads as a rendering bug.\n const title = ([\n `${SESSION_COST_COPY.panelTitle} ${free ? SESSION_COST_COPY.free : sessionCostAmount(total)}`,\n clause(SESSION_COST_COPY.uncachedInput, uncachedInput),\n clause(SESSION_COST_COPY.output, output),\n clause(SESSION_COST_COPY.cacheRead, cacheRead),\n clause(SESSION_COST_COPY.cacheWrite, cacheWrite),\n ...notes,\n ] as Array<string | undefined>).filter((part): part is string => part !== undefined).join(' · ')\n\n return {\n total,\n value,\n title,\n rows,\n notes: [...new Set(notes)],\n free,\n peak,\n unpricedCacheWriteTokens,\n approximate: !free,\n }\n}\n\n/**\n * The two nodes the text appended to the harness's token-usage pill is made of.\n *\n * The separator is a node of its own because it carries the shipped pill's\n * SEPARATOR colour rather than its label colour; the pill is a flex row whose\n * `gap` already spaces the appended item, so the separator is what makes the\n * result read as one continuous run (`1.2M tokens · Cache hit 87% · $0.0123`)\n * rather than as a value parked at the end of it.\n */\nexport interface SessionCostPillRun {\n /** The shipped pill's own separator glyph. */\n separator: string\n /** The amount, `≈` marker and free word included. */\n value: string\n}\n\n/** Split the appended run into the two nodes the display creates. */\nexport function sessionCostPillRun(view: SessionCostView): SessionCostPillRun {\n return { separator: SESSION_COST_COPY.separator, value: view.value }\n}\n\n/**\n * How the harness's own usage dialog is decorated: one entry per row the\n * shipped component renders, IN ITS OWN ORDER.\n *\n * The price goes on the right of the row it belongs to (`3,206,544 tok $0.07`)\n * rather than in a block of our own rows beneath them, so the dialog keeps the\n * harness's layout and gains nothing to read past.\n *\n * Two rows are special. `cacheHit` carries a percentage, not a count, so it is\n * never priced. `cacheWrite` is HIDDEN and never priced: the pricing page\n * publishes a cache-write rate for a minority of models, so its cell read\n * `unpriced` far more often than a number; its tokens still count toward the\n * total the pill shows.\n */\nexport type SessionCostShippedRow = 'cacheHit' | 'uncachedInput' | 'cacheRead' | 'cacheWrite' | 'output'\n\n/** One shipped dialog row and what to do with it. */\nexport interface SessionCostRowDecoration {\n /** Which shipped row this is. */\n row: SessionCostShippedRow\n /**\n * The exact token count that row must be showing, or undefined for a row that\n * carries no count. The display layer verifies it before decorating anything:\n * the shipped labels are the `chat` locale's own strings (never English), so\n * rows are matched POSITIONALLY and this is what proves the position is right.\n */\n tokens: number | undefined\n /** The price to append to the row's value, or undefined to leave it alone. */\n amount: string | undefined\n /** Whether the row is dropped from the dialog entirely. */\n hidden: boolean\n}\n\n/**\n * Decorate the harness's usage dialog, row by row.\n *\n * The row sequence mirrors the shipped component's conditions exactly — the\n * cache-hit row exists while there is billed prompt input, the cache-write row\n * while those tokens are non-zero — because the display layer matches what it\n * finds positionally. A shape it cannot confirm is a shape it does not touch.\n *\n * A free model decorates nothing: every row's cost is zero by definition, the\n * pill already says `Free`, and a column of `$0.00` would be noise. A bucket\n * whose rate the page does not publish is likewise left unfilled rather than\n * filled with an invented number.\n */\nexport function sessionCostRowDecorations(view: SessionCostView): SessionCostRowDecoration[] {\n const bucket = (key: SessionCostBucketRow['key']): number =>\n view.rows.find((row) => row.key === key)?.tokens ?? 0\n const price = (key: SessionCostBucketRow['key']): string | undefined => {\n if (view.free) return undefined\n return view.rows.find((row) => row.key === key)?.costText\n }\n const uncachedInput = bucket('uncachedInput')\n const cacheRead = bucket('cacheRead')\n const cacheWrite = bucket('cacheWrite')\n const output = bucket('output')\n const plan: SessionCostRowDecoration[] = []\n if (uncachedInput + cacheRead + cacheWrite > 0) {\n plan.push({ row: 'cacheHit', tokens: undefined, amount: undefined, hidden: false })\n }\n plan.push({ row: 'uncachedInput', tokens: uncachedInput, amount: price('uncachedInput'), hidden: false })\n plan.push({ row: 'cacheRead', tokens: cacheRead, amount: price('cacheRead'), hidden: false })\n if (cacheWrite !== 0) {\n // Hidden only when the page publishes NO cache-write rate: those tokens are\n // genuinely unpriced, the note says so, and the row would otherwise show a\n // blank cell. When the rate IS known its price is part of the total, so the\n // row must stay — hiding a row whose cost the pill already counts leaves the\n // visible rows unable to explain the figure above them.\n const amount = price('cacheWrite')\n plan.push({ row: 'cacheWrite', tokens: cacheWrite, amount, hidden: amount === undefined })\n }\n plan.push({ row: 'output', tokens: output, amount: price('output'), hidden: false })\n return plan\n}\n","/**\n * The DOM half of the composer's session-cost figure (browser only).\n *\n * The cost is not a surface of its own any more: it is injected INTO the two\n * surfaces the harness already draws under the composer — the token-usage pill\n * (`1.2M tokens · Cache hit 87%`) and the usage dialog that pill opens. This\n * module owns that injection; `./session-cost.ts` owns every number and every\n * string, and `./session-cost-view.tsx` owns the two seats the figures come\n * from.\n *\n * Why inject rather than take the pill's cell over (registering a `stats` entry\n * REPLACES the shipped readout, it does not extend it): the shipped row is one\n * component owning its tokens / cache-hit / duration figures through the `chat`\n * locale namespace, and its cache-hit percentage obeys an exact-integer rule\n * this plugin must not re-derive. Owning that cell would mean reproducing all of\n * it in English, and every upstream change to it would stop reaching users. So\n * the shipped markup stays the harness's, and this module adds exactly two\n * things to it.\n *\n * Four properties make that safe, all verified against the shipped build:\n *\n * 1. **The dialog's rows are styled by ELEMENT.** `dsh-client-ui-chat`'s\n * `stat-dialog` module styles its `dl` as a two-column grid and then\n * `.details dt` / `.details dd` — not by class. A price node appended INSIDE a\n * shipped value cell therefore inherits that cell's tabular numerals and right\n * alignment for free, and this plugin ships no CSS at all.\n * 2. **The dialog's rows are matched by POSITION and confirmed by value.** Their\n * labels are the `chat` locale's own strings (`Uncached input` in English,\n * `未缓存输入` in Chinese), so no label is ever read. Instead the shape is\n * predicted from the session's buckets — the cache-hit row exists while there\n * is billed prompt input, the cache-write row while those tokens are non-zero\n * — and each value cell must then carry exactly the token count predicted for\n * it. A dialog that does not confirm is left alone.\n * 3. **The pill keeps the cost visible when space runs out.** The button is an\n * inline flex row with `gap`, and its label carries `min-width:0` plus\n * ellipsis; our appended span keeps the default `min-width:auto`, so the\n * LABEL is what truncates. The cost also inherits the button's `font:inherit`\n * and `tabular-nums` typography and its hover/expanded tint.\n * 4. **React owns those value cells' text, so a price is re-attached, never\n * assumed.** The shipped component renders each count as a single string, and\n * React rewrites such a cell through `textContent` when the count changes —\n * which drops every child with it, our price included. Every sync therefore\n * re-checks that the node is still where it was put; the cost of that is a\n * read, and the alternative is a price that silently disappears mid-session.\n *\n * A `MutationObserver` on `document.body` with `childList` (deliberately NOT\n * `subtree`, so streaming text never wakes it) is the only way to learn that the\n * dialog — which is portaled straight onto `body`, with no slot of ours inside\n * it — has opened or closed. That observer is also what decorates a newly opened\n * dialog from the last view this module was handed.\n *\n * @module dsh-commandcode-provider/client/session-cost-display\n */\n\nimport type { SessionCostPillRun, SessionCostRowDecoration, SessionCostShippedRow, SessionCostView } from './session-cost.ts'\nimport {\n SESSION_COST_COPY,\n sessionCostPillRun,\n sessionCostRowDecorations,\n} from './session-cost.ts'\n\n/**\n * The shipped composer stats row (dsh-client-ui-chat `StatsPills`).\n *\n * A PREFERENCE, not a requirement: the attribute has already been dropped once\n * upstream (0.1.6-alpha.2) while the rest of the row's markup stayed identical,\n * so a lookup that insisted on it would silently stop finding the row. When it\n * is absent the search falls back to the dock OUTLET — deliberately the outlet\n * and never the outlet's parent, because the parent is the composer footer,\n * which holds the `ContextMeter` as well, and that meter's trigger is itself a\n * `button[aria-haspopup=\"dialog\"]` rendered AFTER the dock. A parent-scoped\n * \"last trigger wins\" would therefore append the cost to the context ring\n * instead of the token pill.\n */\nconst STATS_ROOT = '[data-composer-stats]'\n\n/**\n * The shipped token-usage dialog's `<dl>`. Unique WITHIN one `StatsPills`\n * render: the per-message turn-usage panel has its own dialog with different\n * markup, so a single composer's usage dialog is unambiguous. It is not unique\n * across the document once two composers are live — see {@link resolveDialog}.\n */\nconst USAGE_DIALOG = '[data-session-stats-usage]'\n\n/**\n * The usage dialog's trigger. Both pills announce a dialog, but the token one is\n * rendered LAST — and when no step carries timing the time pill is not a button\n * at all, so \"last\" still selects the token pill in both cases.\n */\nconst DIALOG_TRIGGER = 'button[aria-haspopup=\"dialog\"]'\n\n/**\n * Stable id for the hidden node the appended cost is described by. The pill's\n * own `aria-label` is computed by the harness on every render and cannot be\n * extended, so a description is how the cost reaches assistive technology.\n */\nconst A11Y_ID = 'dsh-commandcode-session-cost'\n\n/** How many consecutive misses before the missing anchor is worth a console line. */\nconst MISSES_BEFORE_WARNING = 3\n\n/**\n * How the display learns that the shipped usage dialog opened or closed.\n *\n * `target` is `document.body`, and the returned function detaches. The default\n * is a `MutationObserver`; the seam exists so tests can announce the dialog\n * without a global observer (the repository's usual injected-seam shape).\n */\nexport type SessionCostObserverFactory = (target: Node, listener: () => void) => (() => void) | undefined\n\n/**\n * The default observer: `childList` on `body`, and deliberately NOT `subtree`, so\n * streaming text inside the page never wakes it while the panel the harness\n * portals straight onto `body` does.\n */\nconst observeBodyChildren: SessionCostObserverFactory = (target, listener) => {\n if (typeof MutationObserver === 'undefined') return undefined\n const observer = new MutationObserver(listener)\n observer.observe(target, { childList: true })\n return () => observer.disconnect()\n}\n\n/** What the display layer reads: the injected document and where to look in it. */\nexport interface SessionCostDisplayOptions {\n /** The document to inject into (injected so node tests can drive a double). */\n doc: Document\n /**\n * The composer that owns this entry — our own outlet wrapper's parent, so a\n * session-scoped composer looks in its OWN card rather than at whichever\n * `[data-composer-stats]` happens to come first in the document.\n */\n scope: () => ParentNode | null\n /** Observer seam; defaults to a `childList` `MutationObserver` on `body`. */\n observe?: SessionCostObserverFactory\n}\n\n/**\n * Owns the nodes injected into the shipped token-usage UI.\n *\n * One instance per mounted entry. `sync()` is cheap and idempotent: it re-reads\n * both targets on every call, which is what lets it self-heal when React\n * remounts the row or replaces the dialog, and it rewrites a node only when its\n * text actually changed.\n */\nexport class SessionCostDisplay {\n private readonly doc: Document\n private readonly scope: () => ParentNode | null\n private readonly observe: SessionCostObserverFactory\n private view: SessionCostView | undefined = undefined\n /** Detaches the observer installed by `start()`. */\n private detach: (() => void) | undefined = undefined\n /** The button we appended into, while it is still connected. */\n private pillHost: Element | undefined = undefined\n /** Our appended root, and the two nodes whose text changes. */\n private pillRoot: HTMLElement | undefined = undefined\n private pillValue: HTMLElement | undefined = undefined\n private pillA11y: HTMLElement | undefined = undefined\n /** Whether WE set `aria-describedby` on the button (so only we take it back). */\n private described = false\n /** The dialog we decorated, the price nodes we own, and the cells we hid. */\n private dialogHost: Element | undefined = undefined\n private dialogPrices = new Map<HTMLElement, HTMLElement>()\n private dialogHidden = new Set<HTMLElement>()\n private pillMisses = 0\n\n constructor(options: SessionCostDisplayOptions) {\n this.doc = options.doc\n this.scope = options.scope\n this.observe = options.observe ?? observeBodyChildren\n }\n\n /** Begin watching for the shipped usage dialog opening and closing. */\n start(): void {\n if (this.detach !== undefined) return\n const body = this.doc.body\n if (body === null || body === undefined) return\n this.detach = this.observe(body, () => this.apply())\n }\n\n /**\n * Hand the display the current figure.\n *\n * Undefined — nothing priceable about this session — removes everything this\n * module injected, leaving both shipped surfaces exactly as they ship.\n */\n sync(view: SessionCostView | undefined): void {\n this.view = view\n this.apply()\n }\n\n /** Remove every injected node and stop observing. Safe to call twice. */\n dispose(): void {\n this.detach?.()\n this.detach = undefined\n this.removePill()\n this.clearDialog()\n this.view = undefined\n }\n\n /** Re-apply the last known view to whatever both targets are right now. */\n private apply(): void {\n this.applyPill()\n this.applyDialog()\n }\n\n // -------------------------------------------------------------------------\n // The pill: the cost as the last item of the shipped token pill's text run\n // -------------------------------------------------------------------------\n\n private applyPill(): void {\n const view = this.view\n if (view === undefined) {\n this.removePill()\n return\n }\n if (this.pillHost?.isConnected !== true) {\n const button = this.resolvePillButton()\n if (button === null) {\n this.pillMisses += 1\n if (this.pillMisses === MISSES_BEFORE_WARNING) {\n console.warn(\n '[dsh-commandcode-provider] no shipped token pill in this composer\\'s dock outlet to append the session cost to; the figure stays in the usage dialog only',\n )\n }\n return\n }\n this.pillMisses = 0\n this.removePill()\n this.buildPill(button, sessionCostPillRun(view))\n }\n if (this.pillValue !== undefined) {\n const amount = sessionCostPillRun(view).value\n if (this.pillValue.textContent !== amount) this.pillValue.textContent = amount\n }\n if (this.pillRoot !== undefined) {\n if (this.pillRoot.title !== view.title) this.pillRoot.title = view.title\n const approximate = view.approximate ? 'true' : null\n if (this.pillRoot.getAttribute('data-approximate') !== approximate) {\n if (approximate === null) this.pillRoot.removeAttribute('data-approximate')\n else this.pillRoot.setAttribute('data-approximate', approximate)\n }\n }\n if (this.pillA11y !== undefined) {\n const described = `${SESSION_COST_COPY.panelTitle} ${view.value}`\n if (this.pillA11y.textContent !== described) this.pillA11y.textContent = described\n }\n }\n\n /**\n * The shipped token pill, scoped to this entry's own composer.\n *\n * The scope is the dock OUTLET (`display: contents`, one per slot), which holds\n * exactly that slot's entries — the shipped `stats` cell and ours, in their\n * registration order. {@link STATS_ROOT} narrows that to the stats row where\n * the markup marks it; where it does not, the outlet is already the narrowest\n * correct container, because the composer footer's `ContextMeter` sits BESIDE\n * the outlet rather than inside it.\n *\n * A missing scope is \"no pill\", never a document-wide search: the outlet is\n * what makes this lookup per-composer, and a second composer can be live at\n * once (the sidebar can mount an embedded Conversation).\n */\n private resolvePillButton(): Element | null {\n const scope = this.scope()\n if (scope === null) return null\n const root = scope.querySelector(STATS_ROOT) ?? scope\n const triggers = root.querySelectorAll(DIALOG_TRIGGER)\n return triggers.length === 0 ? null : (triggers[triggers.length - 1] ?? null)\n }\n\n /**\n * Create and append the cost run. The button's child list is static\n * (`[svg, label]`), so appending once is enough for it to stay last.\n */\n private buildPill(button: Element, run: SessionCostPillRun): void {\n const doc = this.doc\n const root = doc.createElement('span')\n root.setAttribute('data-composer-session-cost', '')\n // The separator is its own node so it can carry the shipped pill's separator\n // colour. Its LEFT spacing comes from the button's flex gap; the right margin\n // reproduces the shipped separator's `margin:0 6px` rhythm, so the run reads\n // `tokens · Cache hit 87% · $0.0123` at one consistent rhythm.\n const separator = doc.createElement('span')\n separator.textContent = run.separator\n separator.setAttribute('aria-hidden', 'true')\n separator.style.color = 'var(--dsw-alias-separator-primary)'\n separator.style.margin = '0 6px 0 0'\n const value = doc.createElement('span')\n value.textContent = run.value\n value.style.fontWeight = '500'\n // Referenced by the button's `aria-describedby`: a hidden node named by id is\n // still read out, which is how the cost survives the aria-label override.\n const a11y = doc.createElement('span')\n a11y.id = A11Y_ID\n a11y.style.display = 'none'\n root.appendChild(separator)\n root.appendChild(value)\n root.appendChild(a11y)\n button.appendChild(root)\n // Only ever claim the attribute when the button has none of its own: a\n // shipped `aria-describedby` is the harness's, and overwriting it would\n // delete a description we cannot restore.\n if (!button.hasAttribute('aria-describedby')) {\n button.setAttribute('aria-describedby', A11Y_ID)\n this.described = true\n }\n this.pillHost = button\n this.pillRoot = root\n this.pillValue = value\n this.pillA11y = a11y\n }\n\n private removePill(): void {\n if (this.pillRoot !== undefined && this.pillRoot.parentNode !== null) {\n this.pillRoot.parentNode.removeChild(this.pillRoot)\n }\n if (this.described) {\n this.pillHost?.removeAttribute('aria-describedby')\n this.described = false\n }\n this.pillHost = undefined\n this.pillRoot = undefined\n this.pillValue = undefined\n this.pillA11y = undefined\n }\n\n // -------------------------------------------------------------------------\n // The dialog: a price on the right of each token row the harness already draws\n // -------------------------------------------------------------------------\n\n private applyDialog(): void {\n const view = this.view\n const host = view === undefined ? null : this.resolveDialog()\n if (host === null || view === undefined) {\n this.clearDialog()\n return\n }\n this.pruneDialog(host)\n const plan = sessionCostRowDecorations(view)\n const pairs = dialogPairs(host)\n if (!dialogShapeMatches(pairs, plan, this.dialogPrices)) {\n // The dialog is not the shape this session's buckets predict — a different\n // build, or a projection carrying values the counts cannot explain. Leave\n // it exactly as the harness drew it rather than pricing the wrong row.\n this.clearDialog()\n return\n }\n const hidden = new Set<HTMLElement>()\n for (const [index, row] of plan.entries()) {\n const pair = pairs[index]\n if (pair === undefined) continue\n const span = this.dialogPrices.get(pair.dd)\n if (row.hidden) {\n // The row is dropped: both cells, or the grid leaves an empty label\n // behind. An inline `display` survives the harness's own re-renders\n // (React pins no style on these nodes) and is given back on disposal.\n if (pair.dt.style.display !== 'none') pair.dt.style.display = 'none'\n if (pair.dd.style.display !== 'none') pair.dd.style.display = 'none'\n hidden.add(pair.dt)\n hidden.add(pair.dd)\n this.removeDialogPrice(pair.dd, span)\n continue\n }\n if (pair.dt.style.display === 'none') pair.dt.style.display = ''\n if (pair.dd.style.display === 'none') pair.dd.style.display = ''\n if (row.amount === undefined) {\n this.removeDialogPrice(pair.dd, span)\n continue\n }\n const price = span ?? this.createDialogPrice(pair.dd, row.row)\n // React owns this cell's text and rewrites it through `textContent` when\n // the count changes, which drops every child with it — so the price is\n // re-attached on a miss rather than assumed to still be there.\n if (price.parentNode !== pair.dd) pair.dd.appendChild(price)\n if (price.textContent !== row.amount) price.textContent = row.amount\n }\n // Cells hidden by an earlier shape (a cache-write row React then rewrote) go\n // back to the harness.\n for (const cell of [...this.dialogHidden]) {\n if (hidden.has(cell)) continue\n if (cell.style.display === 'none') cell.style.display = ''\n this.dialogHidden.delete(cell)\n }\n for (const cell of hidden) this.dialogHidden.add(cell)\n this.dialogHost = host\n }\n\n /** Forget the cells and prices a re-rendered dialog took with it. */\n private pruneDialog(host: Element): void {\n for (const [dd, price] of [...this.dialogPrices]) {\n if (dd.parentNode === host) continue\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n this.dialogPrices.delete(dd)\n }\n for (const cell of [...this.dialogHidden]) {\n if (cell.parentNode === host) continue\n // The dialog was re-rendered and this cell went with the old tree. Give\n // the style back BEFORE dropping the reference: a detached node can be\n // recycled by the next render (React reuses DOM nodes across a remount of\n // the same shape), and a surviving `display: none` would hide a row of a\n // dialog we are no longer decorating — with nothing left tracking it to\n // restore it later.\n if (cell.style.display === 'none') cell.style.display = ''\n this.dialogHidden.delete(cell)\n }\n }\n\n /** The price node for one shipped value cell, appended as its last child. */\n private createDialogPrice(dd: HTMLElement, row: SessionCostShippedRow): HTMLElement {\n const price = this.doc.createElement('span')\n price.setAttribute('data-session-cost-price', row)\n // The cell is right-aligned over tabular numerals, so a fixed-width\n // inline-block lines the prices up as a column of their own to the right of\n // the counts instead of trailing each count raggedly.\n price.style.marginLeft = '6px'\n price.style.display = 'inline-block'\n price.style.minWidth = '56px'\n price.style.textAlign = 'right'\n price.style.fontWeight = '500'\n dd.appendChild(price)\n this.dialogPrices.set(dd, price)\n return price\n }\n\n private removeDialogPrice(dd: HTMLElement, price: HTMLElement | undefined): void {\n if (price === undefined) return\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n this.dialogPrices.delete(dd)\n }\n\n /**\n * The shipped usage dialog, or null while it is closed (or ambiguous).\n *\n * The dialog is portaled onto `body`, so unlike the pill it cannot be scoped\n * from this entry, and the attribute is unique per DIALOG rather than per\n * document. While one composer was guaranteed, a document-level lookup was\n * exact. 0.1.6-alpha.2 ends that guarantee: it mounts an embedded Conversation\n * in the sidebar, so a second composer — with its own session, its own dock\n * and its own dialog — can be live and open at the same time.\n *\n * There is no DOM link from a dialog back to its trigger (the portaled panel\n * carries no id and no `aria-controls`), so with two dialogs open document\n * order says nothing about ownership. The shape confirmation in\n * {@link dialogShapeMatches} would usually reject the stranger, but it compares\n * against THIS entry's counts, so a coincidentally matching dialog would be\n * priced with another session's figures. Ambiguity is therefore answered by\n * declining to decorate at all — the same rule the shape check already\n * follows, applied one level up: a dialog we cannot prove is ours is left\n * alone.\n */\n private resolveDialog(): Element | null {\n if (this.dialogHost?.isConnected === true) return this.dialogHost\n // The dialog we injected into is gone: our nodes went with it, so only the\n // bookkeeping is left to drop.\n this.clearDialog()\n const dialogs = this.doc.querySelectorAll(USAGE_DIALOG)\n return dialogs.length === 1 ? (dialogs[0] ?? null) : null\n }\n\n /** Give the dialog back: every price removed, every hidden row restored. */\n private clearDialog(): void {\n for (const price of this.dialogPrices.values()) {\n if (price.parentNode !== null) price.parentNode.removeChild(price)\n }\n this.dialogPrices.clear()\n for (const cell of this.dialogHidden) {\n if (cell.style.display === 'none') cell.style.display = ''\n }\n this.dialogHidden.clear()\n this.dialogHost = undefined\n }\n}\n\n/** The shipped dialog's `dt`/`dd` pairs, in document order. */\nfunction dialogPairs(host: Element): Array<{ dt: HTMLElement; dd: HTMLElement }> {\n const pairs: Array<{ dt: HTMLElement; dd: HTMLElement }> = []\n let label: HTMLElement | null = null\n for (const node of Array.from(host.childNodes)) {\n const tag = tagNameOf(node)\n if (tag === 'DT') label = node as HTMLElement\n else if (tag === 'DD' && label !== null) {\n pairs.push({ dt: label, dd: node as HTMLElement })\n label = null\n }\n }\n return pairs\n}\n\n/** `tagName` upper-cased, or an empty string for a non-element node. */\nfunction tagNameOf(node: Node): string {\n const tag = (node as Element).tagName\n return typeof tag === 'string' ? tag.toUpperCase() : ''\n}\n\n/**\n * Whether the dialog really holds the rows this session's buckets predict.\n *\n * The shipped labels belong to the `chat` locale — they are `Uncached input` in\n * English and something else entirely in Chinese — so rows are matched by\n * POSITION, and this is what makes that safe: the row count must agree, the\n * cache-hit row must be the percentage it is, and every other value must carry\n * exactly the token count of the bucket predicted for it. A mismatch means the\n * dialog is not what this view describes, and nothing is decorated.\n */\nfunction dialogShapeMatches(\n pairs: ReadonlyArray<{ dt: HTMLElement; dd: HTMLElement }>,\n plan: readonly SessionCostRowDecoration[],\n prices: ReadonlyMap<HTMLElement, HTMLElement>,\n): boolean {\n if (pairs.length !== plan.length) return false\n return plan.every((row, index) => {\n const pair = pairs[index]\n if (pair === undefined) return false\n const text = hostValueText(pair.dd, prices.get(pair.dd))\n if (row.tokens === undefined) return text.includes('%')\n return digitsOf(text) === String(row.tokens)\n })\n}\n\n/**\n * A value cell's own text, without the price this module appended to it — the\n * digits of `3,206,544 tok` are the host's, the digits of `$0.07` are ours.\n */\nfunction hostValueText(dd: HTMLElement, price: HTMLElement | undefined): string {\n let text = ''\n for (const node of Array.from(dd.childNodes)) {\n if (node === price) continue\n text += node.textContent ?? ''\n }\n return text\n}\n\n/** Every digit of a display string, so locale grouping cannot break the match. */\nfunction digitsOf(text: string): string {\n return text.replace(/\\D/g, '')\n}\n","/**\n * The composer's live session-cost figure (browser half).\n *\n * This component renders NO surface of its own. The cost lives inside the\n * harness's own token-usage UI: the amount becomes the last item of the shipped\n * pill's text run (`1.2M tokens · Cache hit 87% · $0.0123`) and the per-bucket\n * breakdown becomes extra rows in the usage dialog that pill opens.\n * `./session-cost-display.ts` owns that injection and `./session-cost.ts` owns\n * every number and every string; this file owns nothing but the two seats the\n * figures come from and the lifetime of the injection.\n *\n * It is still registered as an entry in `conversation.composer.dock`, because\n * that registration is what delivers the seats: `useProjection` is a standard\n * prop the composer hands every dock occupant, so there is no other way to read\n * the session's token accounting. Registering under the shipped `stats` cell's\n * id instead would REPLACE the harness's readout rather than extend it;\n * `./session-cost-display.ts` records why that trade is refused.\n *\n * The rendered node is a hidden marker — `display:none`, so it can add neither a\n * box nor a flex gap to the composer card. It exists to locate THIS composer\n * from the entry (`closest()` on the dock's outlet anchor), so a session-scoped\n * composer reads its own card rather than whichever row comes first in the\n * document. It is rendered only while there is something to show, so a session\n * with nothing priceable contributes no markup at all.\n *\n * Two seats are read, from two different owners: `useProjection` comes from the\n * composer (a standard prop of the dock, not part of this registration), and\n * `useCommandCodePrices` comes from our own registration's `inject` face, which\n * `bindInjectSources` re-exposes from the `hooks` compartment. Reading\n * `props.hooks.*` instead finds `undefined` at runtime and crashes the render,\n * which the slot renderer contains by ABDICATING the entry — a surface that\n * vanishes with no visible error.\n *\n * Both effects are `useEffect`, never `useLayoutEffect`: there is nothing on\n * screen to align with (the injection is a text run and a hidden marker), and a\n * layout effect would log a warning from the server render the tests use.\n *\n * @module dsh-commandcode-provider/client/session-cost-view\n */\n\nimport type { SessionCostFacts } from '../cost-facts.ts'\nimport { useEffect, useRef } from 'react'\nimport type { SnapshotStore } from './snapshot-store.ts'\nimport type { SessionCostPricesState } from './prices.ts'\nimport { SessionCostDisplay } from './session-cost-display.ts'\nimport {\n buildSessionCostView,\n type SessionModelSelectionProjection,\n type SessionUsageBuckets,\n} from './session-cost.ts'\n\n/**\n * The dock outlet this entry renders inside, i.e. what it scopes itself from.\n *\n * The OUTLET itself, not its parent. The outlet is one `display:contents` div\n * holding exactly this slot's entries (the shipped `stats` cell and ours), so it\n * is the narrowest container that is still per-composer. Its parent is NOT:\n * from 0.1.6-alpha.2 the composer stacks the dock inside a footer that also\n * holds the `ContextMeter`, whose trigger is another\n * `button[aria-haspopup=\"dialog\"]` rendered after the dock — scoping to the\n * parent would let the cost land on the context ring.\n */\nconst DOCK_ANCHOR = '[data-slot=\"conversation.composer.dock\"]'\n\n/** Module-level constant so the marker's `style` prop never diffs. */\nconst HIDDEN_STYLE = { display: 'none' } as const\n\n/**\n * The injected face this registration carries. Bound by the client entry so the\n * component stays unaware of the Remote, the controller, and its caching.\n *\n * NOTE the split from {@link SessionCostComponentProps}: the renderer\n * destructures this face's `hooks` compartment and re-exposes each member as a\n * `use<Name>` prop (`commandCodePrices` → `useCommandCodePrices`); it does not\n * hand the component this object verbatim.\n */\nexport interface SessionCostInjected {\n hooks: {\n commandCodePrices: SnapshotStore<SessionCostPricesState>\n }\n}\n\n/**\n * The projection keys this readout reads, declared structurally because the\n * plugin bundle does not depend on the session-controller package (whose\n * `UseProjection` this mirrors).\n */\ninterface ProjectionSeats {\n commandCodeCost: SessionCostFacts\n tokenUsage: SessionUsageBuckets\n modelSelection: SessionModelSelectionProjection\n}\n\n/** The projection reader the composer supplies to every dock occupant. */\nexport interface UseProjectionLike {\n <K extends keyof ProjectionSeats>(key: K): ProjectionSeats[K] | undefined\n <K extends keyof ProjectionSeats, S>(\n key: K,\n selector: (value: ProjectionSeats[K] | undefined) => S,\n eq?: (a: S, b: S) => boolean,\n ): S\n}\n\n/** The props this component actually receives. */\nexport interface SessionCostComponentProps {\n useCommandCodePrices<T>(selector: (state: SessionCostPricesState) => T): T\n useProjection: UseProjectionLike\n}\n\n/** Log a missing seat once per page, so a silent no-op stays diagnosable. */\nlet warnedMissingSeat = false\n\n/**\n * The composer's session-cost entry. Guards the two seats before rendering the\n * mount: a dsh that does not supply the projection seat to dock occupants gets\n * an absent cost and one console line, never a render crash — which the renderer\n * would answer by abdicating the entry with no visible trace.\n */\nexport function CommandCodeSessionCost(props: SessionCostComponentProps) {\n if (typeof props.useProjection !== 'function' || typeof props.useCommandCodePrices !== 'function') {\n if (!warnedMissingSeat) {\n warnedMissingSeat = true\n console.error(\n '[dsh-commandcode-provider] the composer does not supply the projection/hook seats the session-cost readout needs; the readout stays hidden',\n )\n }\n return null\n }\n return <SessionCostEntry {...props} />\n}\n\n/** The mount: one injection lifetime, one hidden marker. Every hook lives here. */\nfunction SessionCostEntry(props: SessionCostComponentProps) {\n const markerRef = useRef<HTMLSpanElement | null>(null)\n const displayRef = useRef<SessionCostDisplay | null>(null)\n const prices = props.useCommandCodePrices((state) => state)\n const usage = props.useProjection('tokenUsage')\n const selection = props.useProjection('modelSelection')\n const facts = props.useProjection('commandCodeCost')\n const view = buildSessionCostView({ usage, selection, facts, table: prices.table, now: Date.now() })\n\n useEffect(() => {\n // No DOM outside a browser: the server render used by the tests, and a\n // node-hosted assembly, must both stay no-ops.\n if (typeof document === 'undefined') return\n const display = new SessionCostDisplay({\n doc: document,\n scope: () => markerRef.current?.closest(DOCK_ANCHOR) ?? null,\n })\n displayRef.current = display\n display.start()\n return () => {\n displayRef.current = null\n display.dispose()\n }\n }, [])\n\n // Every render: the projection is a fresh fold, so there is nothing cheaper to\n // compare than the plan the display derives from it — and the display rewrites\n // a node only when that node's own text actually moved.\n useEffect(() => {\n displayRef.current?.sync(view)\n })\n\n if (view === undefined) return null\n return <span ref={markerRef} style={HIDDEN_STYLE} data-ccp-session-cost-anchor=\"\" />\n}\n","/**\n * Stylesheet for the Command Code settings page — and the Models-page provider\n * card, which shares its `cc-` classes.\n *\n * Returned as a string rather than injected here so the modules stay free of\n * DOM side effects at import time: `./index.ts` installs it once, keyed by\n * `PAGE_CSS_ID`. It is a module of its own rather than a literal inside the\n * client entry so `tests/styles.test.ts` can audit every rule without importing\n * the React tree (which pulls `*.module.css` through the primitives package and\n * needs a loader registered first).\n *\n * Every colour comes from a harness theme alias with a neutral fallback, so the\n * page follows the active theme (light/dark and any brand pack) without\n * hardcoded values. Classes are `cc-` prefixed to stay clear of the panel's\n * `ccp-` set.\n *\n * @module dsh-commandcode-provider/client/page-styles\n */\n\n/**\n * Stylesheet id (the `data-plugin-css` value that makes injection idempotent).\n *\n * The package prefix must match the one the panel stylesheet uses\n * (`PANEL_CSS_ID` in `./panel-styles.ts`) and this package's real name: an id is\n * the injection's identity, so a stale fork prefix would let a second copy of\n * the plugin inject the same rules twice and would misreport the owner in the\n * DOM. The two ids must also stay distinct from each other — they key two\n * separate style tags, and a shared id would make the second injection a no-op\n * that silently drops one stylesheet.\n */\nexport const PAGE_CSS_ID = '@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css'\n\n/**\n * The settings-page stylesheet.\n *\n * The metrics are the harness's own settings pages', read out of the 0.1.7\n * bundles so the page sits beside General and Models without looking foreign:\n * a row is 16px of padding over a 0.5px border-l2 hairline, its title 14/22\n * label-primary and its description 12/18 label-tertiary, the control on the\n * right. Selectors and buttons are capsules (36px / 28px compact), inputs are\n * 32px with an 8px radius and a 0.5px border-l4 edge, a card is a 0.5px\n * border-l4 outline with a 16px radius, and a nested panel is a\n * bg-module-platform fill with a 12px radius. Errors use state-error-primary,\n * the platform's error colour (label-error is its text-only sibling).\n */\nexport const PAGE_CSS = `\n.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex}\n.cc-title{margin:0;color:var(--dsw-alias-label-primary);font-size:16px;font-weight:500;line-height:24px}\n.cc-intro{margin:4px 0 0;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}\n.cc-readOnly{margin:8px 0 0;color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-tertiary));font-size:12px;line-height:18px}\n.cc-spacer{flex:1}\n/* Groups: a heading over hairline-separated rows, no card surface. */\n.cc-group{flex-direction:column;display:flex;margin-top:28px}\n.cc-groupHead{align-items:center;gap:8px;display:flex;min-height:28px;padding-bottom:4px}\n.cc-groupTitle{margin:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}\n.cc-groupDesc{margin:0 0 12px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n.cc-rows>.cc-groupDesc{margin:0;padding:4px 0 0}\n.cc-disclosure{width:100%;padding:0 0 4px;border:0;background:0 0;font:inherit;text-align:left;cursor:pointer;border-radius:6px}\n.cc-disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}\n.cc-rows{flex-direction:column;display:flex}\n.cc-row{align-items:center;gap:8px;display:flex;padding:16px 0;border-bottom:.5px solid var(--dsw-alias-border-l2)}\n.cc-rows>.cc-row:last-child{border-bottom:0}\n.cc-rowNested{padding-left:16px}\n.cc-rowFlush{padding:0;border-bottom:0}\n.cc-rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:32px;display:flex}\n.cc-rowTitleLine{align-items:center;gap:8px;display:flex;min-width:0}\n.cc-rowTitle{min-width:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}\n.cc-rowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n.cc-rowDesc p{margin:0}\n.cc-rowDesc p+p{margin-top:4px}\n.cc-rowError{margin:0;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}\n.cc-rowControl{flex:none;align-items:center;justify-content:flex-end;gap:8px;display:inline-flex;max-width:60%}\n.cc-rowInput{width:200px}\n.cc-rowInputWide{width:280px}\n/* The platform's link button: a compact capsule with no fill until hovered. */\n.cc-linkButton{box-sizing:border-box;flex:none;align-items:center;display:inline-flex;height:28px;padding:0 10px;border:0;border-radius:14px;background:0 0;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px;line-height:18px;white-space:nowrap;cursor:pointer}\n.cc-linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}\n.cc-linkButton:disabled{cursor:default;opacity:.4}\n.cc-linkButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n/* Tags: the platform Tag's capsule (11/17, weight 500). */\n.cc-badges{align-items:center;gap:8px;display:inline-flex}\n.cc-badge,.cc-badgeMuted{flex:none;align-items:center;display:inline-flex;white-space:nowrap;border-radius:999px;corner-shape:round;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}\n.cc-badge{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}\n.cc-badgeMuted{border:.5px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}\n.cc-badgeWarn{background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary))}\n/* The stacked field (the Models-page provider card and the account forms):\n * the platform SettingsForm field's metrics. */\n.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}\n.cc-field+.cc-field{border-top:.5px solid var(--dsw-alias-border-l2)}\n.cc-fieldHead{align-items:center;gap:8px;display:flex}\n.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}\n.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:18px}\n.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}\n.cc-reset:disabled{cursor:default;opacity:.4}\n.cc-input{box-sizing:border-box;height:32px;min-width:0;padding:0 10px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-1);font:inherit;color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}\n.cc-input::placeholder{color:var(--dsw-alias-label-dimmed)}\n.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}\n.cc-input:disabled{opacity:.6;cursor:default}\n.cc-inputInvalid{border-color:var(--dsw-alias-state-error-primary)}\n.cc-invalid{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}\n.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}\n/* The model multi-select trigger: the platform's selector capsule (the\n * language / permission pickers on General). */\n.cc-modelSelectAnchor{flex-direction:column;align-items:stretch;gap:6px;display:inline-flex;min-width:160px}\n.cc-selector{box-sizing:border-box;align-items:center;gap:12px;display:inline-flex;height:36px;padding:0 14px;border:0;border-radius:18px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}\n.cc-selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}\n.cc-selector:disabled{cursor:default;opacity:.4}\n.cc-selector:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n.cc-selectorText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.cc-selectorCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-bottom:3px;transform:rotate(45deg)}\n/* The search box sits inside the Menu anchor, so typing in it never trips\n * the Menu's outside-click close. */\n.cc-modelSearch{width:100%}\n.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}\n.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}\n.cc-checkRow:hover{cursor:pointer}\n/* A hand-drawn box rather than the platform's accent-color checkbox: the\n * native control's colours come from color-scheme, which the theme sets once\n * at BOOT (it is not re-applied when the theme is switched in-session), so a\n * native box can paint light-chrome white on a dark page. Drawn from tokens it\n * cannot. The mark rides a brand-primary fill, so it takes the theme's brand\n * foreground — the platform's pairing for anything painted on that fill, and\n * the only one that survives the dark mode's near-white brand. The box\n * outline is a border-l3 hairline: border-l2 (#ffffff1f in dark) leaves an\n * unchecked box all but invisible against the menu surface. */\n.cc-check{box-sizing:border-box;appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid var(--dsw-alias-border-l3);border-radius:4px;background:0 0;position:relative}\n.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}\n.cc-check:checked::after{content:'';position:absolute;top:3px;left:5px;width:3px;height:7px;border:solid var(--dsw-alias-label-primary-foreground,#fff);border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}\n.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n/* The platform SegmentedControl: a translucent track and one raised pill that\n * slides under the picked segment. Segments are equal grid tracks, so the\n * indicator's width and offset follow from the count and the index alone. */\n.cc-segmented{position:relative;display:inline-grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:2px;padding:3px;border-radius:9px;background:var(--dsw-alias-interactive-bg-hover)}\n.cc-segmentIndicator{position:absolute;top:3px;left:3px;width:calc((100% - 6px - 2px * (var(--cc-segment-count) - 1)) / var(--cc-segment-count));height:calc(100% - 6px);border-radius:7px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-soft,0 1px 2px rgba(0,0,0,.12));transform:translateX(calc(var(--cc-segment-index) * (100% + 2px)));transition:transform .16s ease;pointer-events:none}\n.cc-segment{box-sizing:border-box;position:relative;z-index:1;height:28px;padding:0 16px;border:0;border-radius:7px;background:0 0;color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;font-weight:500;line-height:20px;white-space:nowrap;cursor:pointer;transition:color .12s ease}\n.cc-segment:hover:not(:disabled),.cc-segment[aria-checked=true]{color:var(--dsw-alias-label-primary)}\n.cc-segment:disabled{cursor:default;opacity:.4}\n.cc-segment:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}\n/* Modelled on the platform's own Switch primitive (ui-primitives\n * Switch.module.css): a 36x20 capsule that pads its track by 2px and slides a\n * 16px thumb across the 32px content box.\n *\n * Three things are load-bearing. (1) corner-shape:round on BOTH the track and\n * the thumb: the theme sets a global superellipse corner shape on every\n * element, and a superellipse capsule squares its ends off around a round\n * thumb. (2) No literal colours. --dsw-alias-brand-primary INVERTS between the\n * two modes (near-black in light, near-white in dark), so a hardcoded white\n * thumb vanishes on the checked track in dark mode; the brand foreground is the\n * token the platform paints on that fill. (3) --dsw-alias-border-l3 as the off\n * track: border-l2 (#ffffff1f in dark) leaves it indistinguishable from the\n * page. */\n.cc-toggle{box-sizing:border-box;appearance:none;flex-shrink:0;width:36px;height:20px;margin:0;padding:2px;border:0;border-radius:10px;corner-shape:round;background:var(--dsw-alias-border-l3);cursor:pointer;position:relative}\n.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}\n.cc-toggle::after{content:'';display:block;width:16px;height:16px;border-radius:50%;corner-shape:round;background:var(--dsw-alias-label-primary-foreground);transition:transform .12s ease}\n/* 32px content box minus the 16px thumb. */\n.cc-toggle:checked::after{transform:translateX(16px)}\n.cc-toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}\n.cc-toggle:disabled{cursor:default;opacity:.5}\n.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:7px;height:7px;margin-right:6px;margin-bottom:3px;transform:rotate(45deg);transition:transform .15s ease}\n.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}\n/* Accounts: one outlined card per account, the Models page's provider card. */\n.cc-accountMode{align-items:center;gap:4px;display:flex;margin:-4px 0 12px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}\n.cc-accountList{flex-direction:column;gap:8px;display:flex}\n.cc-accountList+.cc-addButton,.cc-accountList+.cc-addPanel{margin-top:8px}\n.cc-accountItem{flex-direction:column;gap:10px;display:flex;padding:12px 14px;border:.5px solid var(--dsw-alias-border-l4);border-radius:16px}\n.cc-accountItemActive{border-color:var(--dsw-static-neutral-bluish-400,var(--dsw-alias-border-l3))}\n.cc-accountHead{align-items:center;gap:4px;display:flex;min-height:28px}\n.cc-accountToggle{align-items:center;gap:8px;display:flex;flex:1;min-width:0;padding:0;background:0 0;border:0;color:inherit;cursor:pointer;font:inherit;text-align:left}\n.cc-accountToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:4px}\n.cc-accountName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}\n.cc-iconButton{flex-shrink:0;align-items:center;justify-content:center;display:inline-flex;width:28px;height:28px;padding:0;background:0 0;border:0;border-radius:6px;color:var(--dsw-alias-label-tertiary);cursor:pointer}\n.cc-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.cc-iconButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n/* Three dots from one element: the dot itself plus two box-shadow copies. */\n.cc-kebab{width:3px;height:3px;border-radius:50%;corner-shape:round;background:currentColor;box-shadow:0 -5px 0 currentColor,0 5px 0 currentColor}\n.cc-tabDot{flex-shrink:0;width:8px;height:8px;border-radius:50%;corner-shape:round}\n.cc-tabDotOk{background:var(--dsw-alias-state-success-primary)}\n.cc-tabDotWarn{background:var(--dsw-alias-state-warn-primary,#d97706)}\n.cc-tabDotError{background:var(--dsw-alias-state-error-primary)}\n.cc-accountMeters{flex-wrap:wrap;gap:6px 20px;display:flex;padding-left:16px}\n.cc-miniMeter{align-items:center;gap:8px;display:inline-flex;font-size:12px;line-height:18px}\n.cc-miniMeterLabel{color:var(--dsw-alias-label-tertiary)}\n.cc-miniMeterTrack{overflow:hidden;background:var(--dsw-alias-bg-module-platform);border-radius:999px;width:64px;height:4px}\n.cc-miniMeterFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%}\n.cc-miniMeterValue{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}\n.cc-accountSetup,.cc-loginStatus{flex-direction:column;gap:8px;display:flex;padding-left:16px}\n.cc-loginStatus{flex-direction:row;flex-wrap:wrap;align-items:center;gap:4px 12px}\n.cc-loginStatus>p{margin:0;font-size:12px;line-height:18px}\n.cc-accountDetails{container-type:inline-size;border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;display:flex;padding-top:12px}\n.cc-inlineForm,.cc-confirmBar{flex-direction:column;gap:8px;display:flex}\n.cc-inlineActions{align-items:center;gap:8px;display:flex}\n.cc-confirmBar{border:.5px solid var(--dsw-alias-state-error-primary);border-radius:12px;padding:12px 14px}\n.cc-confirmText{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;line-height:22px}\n.cc-dangerButton{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}\n.cc-dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}\n/* Adding an account: the Models page's dashed add button, opening a filled\n * panel in its place. */\n.cc-addButton{box-sizing:border-box;align-items:center;justify-content:center;gap:6px;display:flex;width:100%;height:44px;border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;cursor:pointer}\n.cc-addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}\n.cc-addButton:disabled{cursor:default;opacity:.4}\n.cc-addButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n/* A plus from two crossed bars. */\n.cc-addGlyph{position:relative;width:12px;height:12px}\n.cc-addGlyph::before,.cc-addGlyph::after{content:'';position:absolute;background:currentColor;border-radius:1px}\n.cc-addGlyph::before{left:0;right:0;top:5.25px;height:1.5px}\n.cc-addGlyph::after{top:0;bottom:0;left:5.25px;width:1.5px}\n.cc-addPanel{flex-direction:column;gap:12px;display:flex;padding:14px 16px;border-radius:12px;background:var(--dsw-alias-bg-module-platform)}\n.cc-panelTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}\n/* Account report: stat tiles are filled panels, like the platform's editors. */\n.cc-accountReport{flex-direction:column;gap:14px;display:flex}\n.cc-usageHead{align-items:center;gap:8px;display:flex}\n.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:14px;font-weight:500;line-height:22px}\n.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n.cc-usagePlan{flex:none;white-space:nowrap;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:999px;corner-shape:round;padding:0 7px;font-size:11px;font-weight:500;line-height:17px}\n.cc-usagePlanStatus{flex:none;margin:0;white-space:nowrap;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}\n.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}\n/* Two fixed grids instead of one auto-fit track: auto-fit wrapped the four\n * activity tiles 3 + 1 at the details' width. Each group fills its own row\n * (four activity tiles, three balances) and the activity row folds to 2 × 2\n * in a narrow details panel. */\n.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}\n.cc-usageStatsActivity{grid-template-columns:repeat(4,minmax(0,1fr))}\n.cc-usageStatsBalance{grid-template-columns:repeat(3,minmax(0,1fr))}\n@container (max-width:460px){.cc-usageStatsActivity{grid-template-columns:repeat(2,minmax(0,1fr))}}\n.cc-usageStat{min-width:0;flex-direction:column;gap:2px;display:flex;padding:10px 12px;border-radius:12px;background:var(--dsw-alias-bg-module-platform)}\n.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:500;line-height:24px;font-variant-numeric:tabular-nums}\n.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.cc-usageWindows{flex-direction:column;gap:14px;display:flex}\n.cc-usageWindow{flex-direction:column;gap:6px;display:flex}\n.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}\n.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;line-height:18px}\n.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;font-variant-numeric:tabular-nums}\n.cc-usageExceeded{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}\n.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-module-platform);border-radius:999px;height:4px}\n.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.cc-usageBarFillWarn{background:var(--dsw-alias-state-error-primary)}\n.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}\n.cc-usageMeta{align-items:center;gap:8px;display:flex}\n.cc-usageMetaSpacer{flex:1}\n.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}\n.cc-usagePartial{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}\n.cc-usageBlocked{border:.5px solid var(--dsw-alias-state-error-primary);border-radius:12px;padding:12px 14px;display:flex;flex-direction:column;gap:4px}\n.cc-usageBlockedTitle{color:var(--dsw-alias-state-error-primary);margin:0;font-size:14px;font-weight:500;line-height:22px}\n.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}\n.cc-usageBlockedDetail{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px;word-break:break-word}\n.cc-version{margin:32px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}\n/* The update hint rides the footer version line, quiet until hovered. */\n.cc-versionLink{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary));text-decoration:none}\n.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}\n/* The Models-page provider panel root: unstyled by design — the row card the\n * Models page owns supplies the surface, the panel only stacks its controls. */\n.cc-providerCard{flex-direction:column;display:flex}\n.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}\n.cc-failed{display:inline-block;max-width:260px;min-width:0;color:var(--dsw-alias-state-error-primary);margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px}\n/* The authorization link is the only link-coloured element on a login row. */\n.cc-loginLink{color:var(--dsw-alias-link,var(--dsw-alias-brand-primary));text-decoration:none;font-size:12px;line-height:18px}\n.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}\n.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}\n.cc-loginError{color:var(--dsw-alias-state-error-primary)}\n/* The floating save bar: a centered capsule pinned to the bottom of the\n * settings scrollport. The dock is a zero-height sticky strip at the end of\n * the page, so the bar overlays the scrolling content instead of taking a row\n * of its own; while it is shown the section reserves room at its end so the\n * last line can still scroll clear of it. Hidden, it sinks and fades, and\n * visibility (switched after the transition) takes its buttons out of the tab\n * order.\n *\n * Its surface is an elevated layer (bg-layer-1 over the settings panel's\n * layer-2) with the platform's prominent elevation and no stroke. The corners\n * are concentric: a 44px capsule around 36px capsule buttons inset by 4px, so\n * the gap around each button is even. */\n.cc-sectionWithBar{padding-bottom:80px}\n.cc-saveBarDock{position:sticky;bottom:0;z-index:2;height:0;pointer-events:none}\n.cc-saveBar{--cc-saveBar-tone:var(--dsw-alias-state-warn-primary,#d97706);position:absolute;left:50%;bottom:20px;box-sizing:border-box;width:max-content;max-width:calc(100% - 24px);align-items:center;gap:10px;display:flex;height:44px;padding:4px 4px 4px 16px;border:0;border-radius:22px;corner-shape:round;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-prominent,0 12px 32px -8px rgba(0,0,0,.24),0 2px 8px rgba(0,0,0,.08));opacity:0;visibility:hidden;transform:translate(-50%,12px);transition:opacity .16s ease,transform .16s ease,visibility 0s linear .16s}\n.cc-saveBarShown{opacity:1;visibility:visible;transform:translate(-50%,0);pointer-events:auto;transition:opacity .2s ease,transform .24s cubic-bezier(.2,.9,.3,1.1),visibility 0s}\n.cc-saveBar-error{--cc-saveBar-tone:var(--dsw-alias-state-error-primary)}\n.cc-saveBar-success{--cc-saveBar-tone:var(--dsw-alias-state-success-primary,#16a34a);padding-right:18px}\n.cc-saveBarIcon{flex-shrink:0;align-items:center;justify-content:center;display:inline-flex;width:16px;height:16px;color:var(--cc-saveBar-tone)}\n.cc-saveBarPulse{width:8px;height:8px;border-radius:50%;corner-shape:round;background:var(--cc-saveBar-tone)}\n.cc-saveBarText{min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}\n.cc-saveBar-error .cc-saveBarText{color:var(--dsw-alias-state-error-primary)}\n.cc-saveBarActions{flex-shrink:0;align-items:center;gap:4px;display:flex;margin-left:8px}\n.cc-saveBarButton{box-sizing:border-box;height:36px;padding:0 16px;border:0;border-radius:18px;corner-shape:round;font:inherit;font-size:14px;line-height:22px;white-space:nowrap;cursor:pointer}\n.cc-saveBarButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}\n.cc-saveBarButton:disabled{cursor:default;opacity:.4}\n.cc-saveBarGhost{background:0 0;color:var(--dsw-alias-label-primary)}\n.cc-saveBarGhost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}\n.cc-saveBarPrimary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}\n.cc-saveBarPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary)))}\n@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle::after,.cc-usageBarFill,.cc-saveBar,.cc-saveBarShown,.cc-segmentIndicator,.cc-segment{transition:none}}\n`\n","/**\n * Stylesheet for the Command Code plans & quota panel (the sidebar footer card\n * and the dashboard it opens).\n *\n * Returned as a string rather than injected here so the modules stay free of\n * DOM side effects at import time — the client entry installs it once, keyed\n * by the same `data-plugin-css` attribute the settings-page stylesheet\n * (`./page-styles.ts`) uses, and removes it again when the plugin's fiber\n * unwinds.\n *\n * These rules are GLOBAL CSS: every selector in here can match markup this\n * plugin did not render. So each one is either qualified by a `ccp-` class of\n * our own, or anchored to the sidebar region it has to lay out — and the one\n * foreign anchor carries its justification in place (see the footer card\n * block; issue #48). `tests/styles.test.ts` audits that containment for both\n * stylesheets and simulates it against the real foreign class stems.\n *\n * Every colour comes from a harness theme alias with a neutral fallback, so\n * the panel follows the active theme (light/dark and any brand pack) without\n * hardcoded values. Classes are `ccp-` prefixed to stay clear of the settings\n * page's `cc-` set.\n *\n * @module dsh-commandcode-provider/client/panel-styles\n */\n\n/**\n * Stylesheet id (the `data-plugin-css` value that makes injection idempotent).\n *\n * The package prefix must match the one the settings-page stylesheet uses\n * (`PAGE_CSS_ID` in `./page-styles.ts`) and this package's real name: an id is\n * the injection's identity, so a stale fork prefix would let a second copy of\n * the plugin inject the same rules twice and would misreport the owner in the\n * DOM. The two ids must also stay distinct from each other — they key two\n * separate style tags, and a shared id would make the second injection a no-op\n * that silently drops one stylesheet.\n */\nexport const PANEL_CSS_ID = '@mars-sea/dsh-commandcode-provider/CommandCodePanel.module.css'\n\n/** The panel stylesheet. */\nexport const PANEL_CSS = `\n/* ------------------------------------------------- sidebar footer card */\n/* The shell's foot area renders this list ABOVE the Settings seat, so the card\n is the sidebar's bottom-most content. The shell supplies no chrome: the entry\n is the button. It is deliberately quiet — a surface that sits beside Settings\n should read as part of the column, not as a call to action — with one hover\n step and a hairline border.\n\n The shell's container is a flex ROW whose occupants (this card and ui-cordis's\n footer chip) each declare a full-width line and shrink-proof flex, so as a row\n it would overflow the column: this card's flex:0 0 auto cannot shrink, and the\n chip's width:100% basis would absorb the whole overflow and collapse to\n nothing. Both were written for a full-width line, which is exactly what a\n column gives them. Matched by the CSS-module class STEM — never a hashed name\n — so a dsh that renames it degrades to the shell's own row rather than\n breaking.\n\n THE ANCHOR IS LOAD-BEARING, and it is the whole reason this selector is not\n just [class*=\"_footerActions\"] (issue #48). \"footerActions\" is NOT a stem this\n shell owns alone: @deepseek-ai/dsh-client-ui-user-questions renders the\n ask-user-question dialog's button row as Mbwy4a_footerActions, so the\n unanchored rule forced THAT row into a column too and stacked the dialog's\n side-by-side buttons on every page. \"footArea\" is declared by\n dsh-client-ui-sidebar alone — verified against every client bundle of the\n 0.1.6-alpha.1 engine, and against our own cc-/ccp- class names, which collide\n with no engine class — so anchoring under it keeps the sidebar layout fix and\n cannot reach another component's markup. The descendant combinator (rather\n than a child one) deliberately survives a wrapper element appearing between\n the two: a renamed or restructured shell should degrade to its own row, not\n lose the fix. tests/styles.test.ts pins both halves of this — the dialog row\n is no longer matched, the sidebar row still is. */\n[class*=\"_footArea\"] [class*=\"_footerActions\"]{flex-direction:column}\n.ccp-foot{box-sizing:border-box;flex:0 0 auto;width:100%;min-width:0;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:1px solid transparent;border-radius:10px;flex-direction:column;gap:6px;margin:0 0 4px;padding:8px;display:flex}\n.ccp-foot:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}\n.ccp-foot:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n.ccp-footTop{align-items:center;gap:8px;min-width:0;display:flex}\n.ccp-footName{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);min-width:0;overflow:hidden;font-size:13px;font-weight:500;line-height:20px}\n/* One block per quota window: a head line carrying the window's own spend and\n limit, then the FULL-WIDTH bar under it. Stacking the two lets the card show\n the dollar figures — the reason this surface exists — without squeezing the\n bar into what is left beside them. Mirrors the dashboard's own window block. */\n.ccp-footRow{flex-direction:column;gap:4px;min-width:0;display:flex}\n.ccp-footHead{align-items:baseline;gap:8px;min-width:0;display:flex}\n.ccp-footLabel{flex:1;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}\n.ccp-footAmount{flex:none;color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px;font-variant-numeric:tabular-nums;white-space:nowrap}\n/* The card's markup must stay PHRASING content — it renders inside the shell's\n own button — so these bars are spans, not divs. That makes display:block\n load-bearing on BOTH: an inline box ignores width and height outright, so\n without it the 5px track still painted (a flex item is blockified by its\n container) while the fill collapsed to 0x0 and the bar showed no usage. */\n.ccp-footBar{display:block;background:var(--dsw-alias-bg-layer-2);border-radius:999px;height:5px;overflow:hidden}\n.ccp-footFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.ccp-footFillWarn{background:var(--dsw-alias-state-error-primary)}\n.ccp-footPct{flex:none;width:34px;color:var(--dsw-alias-label-secondary);text-align:right;font-size:11px;line-height:16px;font-variant-numeric:tabular-nums}\n\n/* The 56px rail: one icon button on the shell's own rail geometry (36px cell),\n so the collapsed column keeps a single 18px glyph like its siblings. */\n.ccp-railButton{box-sizing:border-box;width:36px;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:1px solid transparent;border-radius:8px;flex:none;justify-content:center;align-items:center;margin:0 0 4px;padding:0;display:inline-flex}\n.ccp-railButton:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}\n.ccp-railButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}\n\n/* The ring glyph. Sized entirely by its own width/height attribute, so the\n footer row, the rail button and the dashboard can each ask for their own. */\n.ccp-glyph{flex:none;justify-content:center;align-items:center;display:inline-flex;color:var(--dsw-alias-brand-primary)}\n\n/* ------------------------------------------------------------ dashboard */\n/* The center column in the layout frame: fill it, scroll the content column,\n and cap the reading width like the harness's own panels. */\n.ccp-main{background:var(--dsw-alias-bg-layer-1);width:100%;height:100%;overflow:auto;display:block}\n.ccp-mainInner{max-width:760px;margin:0 auto;padding:24px 20px 40px;flex-direction:column;gap:14px;display:flex;color:var(--dsw-alias-label-primary)}\n.ccp-header{align-items:center;gap:10px;display:flex;flex-wrap:wrap}\n.ccp-headerText{flex-direction:column;gap:2px;display:flex;min-width:0}\n.ccp-title{margin:0;font-size:18px;font-weight:600;line-height:1.4}\n.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}\n.ccp-spacer{flex:1}\n.ccp-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;font-variant-numeric:tabular-nums}\n/* The dashboard's exit: an icon-sized glyph button. The primitive's own\n geometry is kept (size=\"sm\"); only the glyph is enlarged and optically\n centred, so it reads as a dismiss control rather than a text button. */\n.ccp-close{min-width:28px;justify-content:center;padding-left:0;padding-right:0}\n.ccp-close span{font-size:16px;line-height:1}\n.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n\n/* Notices: the no-key guidance, a blocked report, and a stale-data error. */\n.ccp-notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:12px 14px;flex-direction:column;gap:4px;display:flex}\n.ccp-noticeError{border-color:var(--dsw-alias-state-error-primary)}\n.ccp-noticeTitle{margin:0;font-size:13px;font-weight:600;line-height:1.5}\n.ccp-noticeError .ccp-noticeTitle{color:var(--dsw-alias-state-error-primary)}\n.ccp-noticeHint{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55}\n.ccp-noticeDetail{margin:0;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;word-break:break-word}\n\n.ccp-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:14px;padding:16px 18px;flex-direction:column;gap:16px;display:flex}\n.ccp-cardHead{align-items:center;gap:10px;display:flex;flex-wrap:wrap}\n.ccp-avatar{flex:none;width:28px;height:28px;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-module-platform);border-radius:50%;justify-content:center;align-items:center;font-size:12px;font-weight:600;line-height:1;display:inline-flex}\n.ccp-cardIdentity{flex-direction:column;gap:1px;min-width:0;display:flex}\n.ccp-cardTitle{font-size:13px;font-weight:600;line-height:1.4}\n.ccp-cardOwner{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px}\n.ccp-block{flex-direction:column;gap:8px;display:flex}\n.ccp-blockTitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:600;line-height:1.5;text-transform:uppercase;letter-spacing:.04em}\n.ccp-planRow{align-items:center;gap:8px;display:flex;flex-wrap:wrap}\n.ccp-fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}\n.ccp-planName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:1.5}\n\n/* Stat tiles: the monthly credits and the usage totals share one grid. */\n.ccp-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px}\n.ccp-tile{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex;min-width:0}\n.ccp-tileLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}\n.ccp-tileValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4;font-variant-numeric:tabular-nums}\n.ccp-tileSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n\n/* Quota bars: the monthly bar and the two windows stack in one column, each a\n label row plus the track. */\n.ccp-windows{flex-direction:column;gap:14px;display:flex}\n.ccp-window{flex-direction:column;gap:6px;display:flex}\n.ccp-windowHead{align-items:baseline;gap:8px;display:flex}\n.ccp-windowLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:1.5}\n.ccp-windowValue{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5;font-variant-numeric:tabular-nums;white-space:nowrap}\n.ccp-windowPct{color:var(--dsw-alias-label-primary);min-width:38px;text-align:right;font-size:12px;font-weight:600;line-height:1.5;font-variant-numeric:tabular-nums}\n.ccp-warnTag{white-space:nowrap;background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary));border-radius:999px;padding:0 8px;font-size:11px;font-weight:600;line-height:17px}\n.ccp-bar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:8px}\n.ccp-barFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}\n.ccp-barFillWarn{background:var(--dsw-alias-state-error-primary)}\n.ccp-windowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}\n\n/* Badges. */\n.ccp-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}\n.ccp-badgeError{background:transparent;color:var(--dsw-alias-state-error-primary)}\n.ccp-badgeWarn{background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary))}\n.ccp-badgeMuted{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;max-width:220px;overflow:hidden;text-overflow:ellipsis}\n\n/* Account switch: plain buttons, like the settings page's usage carousel. */\n.ccp-tabs{flex-wrap:wrap;gap:6px;display:flex}\n.ccp-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}\n.ccp-tab:hover:not(.ccp-tabActive){color:var(--dsw-alias-label-primary)}\n.ccp-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}\n\n@media (prefers-reduced-motion:reduce){.ccp-footFill,.ccp-barFill{transition:none}}\n`\n","/**\n * Locale copy for the \"Command Code\" settings page, and the declaration that\n * merges the page's namespace into the framework's `LocaleNamespaceMap` so\n * `ctx.locale.register` / `ctx.slots.register(..., { locale })` are typed.\n *\n * zh is the source of truth for the key set (repo convention); en must carry\n * the exact same keys — a mismatch is a compile error at the register site.\n */\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Copy of the Command Code settings page. */\n 'settings.commandcode': SettingsCommandCodeKey\n }\n}\n\n/** Dictionary keys of the Command Code settings page. */\nexport type SettingsCommandCodeKey =\n | 'nav'\n | 'title'\n | 'intro'\n | 'apiKey'\n | 'apiKeyHint'\n | 'apiKeySet'\n | 'apiKeyUnset'\n | 'apiKeyLocked'\n | 'apiBase'\n | 'apiBaseHint'\n | 'requestTimeoutMs'\n | 'requestTimeoutMsHint'\n | 'streamIdleTimeoutMs'\n | 'streamIdleTimeoutMsHint'\n | 'transportMaxRetries'\n | 'transportMaxRetriesHint'\n | 'advancedSettings'\n | 'advancedSettingsHint'\n | 'advancedOverriddenOne'\n | 'advancedOverriddenMany'\n | 'advancedInvalid'\n | 'filterModelsByPlan'\n | 'filterModelsByPlanHint'\n | 'webSearch'\n | 'webSearchHint'\n | 'showSidebarQuota'\n | 'showSidebarQuotaHint'\n | 'commandGuard'\n | 'commandGuardHint'\n | 'commandGuardLevel'\n | 'commandGuardLevelHint'\n | 'commandGuardLevelHigh'\n | 'commandGuardLevelMedium'\n | 'commandGuardLevelLow'\n | 'zdr'\n | 'zdrHint'\n | 'accountsTitle'\n | 'accountsHint'\n | 'accountAdd'\n | 'accountDefault'\n | 'modelSearchPlaceholder'\n | 'modelSearchEmpty'\n | 'modelStale'\n | 'visibleModelsTitle'\n | 'visibleModelsHint'\n | 'visibleModelsPick'\n | 'visibleModelsCount'\n | 'visibleModelsShowAll'\n | 'visibleModelsStaleHint'\n | 'visibleModelsCleanStale'\n | 'overridden'\n | 'reset'\n | 'invalidNumber'\n | 'numberTooSmall'\n | 'numberTooLarge'\n | 'readOnly'\n | 'save'\n | 'saving'\n | 'saved'\n | 'saveFailed'\n | 'unsavedChanges'\n | 'saveInvalid'\n | 'discard'\n | 'cancel'\n | 'show'\n | 'hide'\n | 'usageRefresh'\n | 'usageRefreshing'\n | 'usageLoading'\n | 'usageError'\n | 'usageRequests'\n | 'usageFailed'\n | 'usageSuccessRate'\n | 'usageCost'\n | 'usageTokens'\n | 'usageTokensIn'\n | 'usageTokensOut'\n | 'usageMonthly'\n | 'usagePurchased'\n | 'usageFree'\n | 'usageFiveHour'\n | 'usageWeekly'\n | 'usageMonthlyLeft'\n | 'usageExceeded'\n | 'usageReset'\n | 'usagePartial'\n | 'usageKeyInvalid'\n | 'usageKeyInvalidHint'\n | 'usageServiceUnavailable'\n | 'usageServiceUnavailableHint'\n | 'usageNetworkError'\n | 'usageNetworkHint'\n | 'usageInvalidResponse'\n | 'usageInvalidResponseHint'\n | 'usageUpdated'\n | 'usagePeriodEnd'\n | 'usageActive'\n | 'usageCooldown'\n | 'usageInvalidKey'\n | 'usageUnconfigured'\n | 'updateAvailable'\n | 'updateHint'\n | 'loginTitle'\n | 'loginHintIdle'\n | 'loginButton'\n | 'loginStarting'\n | 'loginWaiting'\n | 'loginOpenLink'\n | 'loginCancel'\n | 'loginSuccess'\n | 'loginUnavailable'\n | 'loginDenied'\n | 'loginTimeout'\n | 'loginInvalidKey'\n | 'loginNetwork'\n | 'loginStoreFailed'\n | 'loginCancelled'\n | 'loginFailedGeneric'\n | 'cardTitle'\n | 'cardRouteActive'\n | 'cardLoadingHint'\n | 'cardRegistrationHint'\n | 'accountsRotationHint'\n | 'accountModeAuto'\n | 'accountModePinned'\n | 'accountStatusPinned'\n | 'accountActions'\n | 'accountActionPin'\n | 'accountActionUnpin'\n | 'accountActionLogin'\n | 'accountActionKey'\n | 'accountActionRename'\n | 'accountActionClearKey'\n | 'accountActionRemove'\n | 'accountRemoveConfirm'\n | 'accountClearKeyConfirm'\n | 'accountConfirmRemove'\n | 'accountConfirmClear'\n | 'accountApply'\n | 'accountNoKeyHint'\n | 'accountAddHint'\n | 'accountAddLogin'\n | 'accountAddPaste'\n | 'accountAddConfirm'\n | 'accountNamePlaceholder'\n | 'accountNameN'\n | 'accountKeyPlaceholder'\n | 'accountOpFailed'\n | 'accountModels'\n | 'accountModelsHint'\n | 'accountModelOwner'\n | 'modelPick'\n | 'modelCount'\n | 'modelCatalogFailed'\n | 'modelsTitle'\n | 'privacyTitle'\n | 'integrationsTitle'\n\nexport const zh: Record<SettingsCommandCodeKey, string> = {\n nav: 'Command Code',\n title: 'Command Code',\n intro: '账户操作立即生效;其余设置修改后点击底部「保存」。API 密钥仅保存在本机凭据服务中,不会回显。',\n apiKey: 'API 密钥',\n apiKeyHint: '在 commandcode.ai 控制台创建。留空保存不会覆盖已存储的密钥。',\n apiKeySet: '已配置',\n apiKeyUnset: '未配置',\n apiKeyLocked: '密钥由只读来源提供',\n apiBase: 'API 地址',\n apiBaseHint: '默认 https://api.commandcode.ai,一般无需修改。',\n requestTimeoutMs: '请求超时(毫秒)',\n requestTimeoutMsHint: '等待响应首个字节的超时;默认 60000。',\n streamIdleTimeoutMs: '流空闲超时(毫秒)',\n streamIdleTimeoutMsHint: '生成流停滞多久视为断连;默认 300000(长思考模型可静默数分钟,默认值刻意放宽)。',\n transportMaxRetries: '网络失败重试次数',\n transportMaxRetriesHint: '连接失败时自动重试几次,默认 5(各次等待 0.5+1+2+4+8 秒,合计约 15 秒)。'\n + '超过后直接报错,不再按指数退避长时间等待;填 0 表示不重试。限流、5xx 等由服务端要求重试的失败不受此项影响。',\n advancedSettings: '高级设置',\n advancedSettingsHint: 'API 地址和网络参数,一般无需修改。',\n advancedOverriddenOne: '已自定义 1 项',\n advancedOverriddenMany: '已自定义 {count} 项',\n advancedInvalid: '高级设置中有未填好的数字,请展开修正后再保存。',\n filterModelsByPlan: '隐藏套餐外模型',\n filterModelsByPlanHint: '只显示套餐内模型;按需余额账户仍显示全部。',\n webSearch: '用 Command Code 承载联网搜索',\n webSearchHint: '使用同一密钥承载 dsh 的 web_search;关闭后恢复原搜索后端。',\n showSidebarQuota: '在侧边栏显示额度卡片',\n showSidebarQuotaHint: '在侧边栏底部显示套餐与额度卡片,点击可打开完整仪表盘。默认关闭,关闭时不会为它后台刷新用量。',\n commandGuard: 'AI 命令安全预判',\n commandGuardHint: '命令确认弹窗前,先由 typesafe/jev 判断它是否安全;沙箱提权还会额外判断范围与必要性。三项都足够确定才自动放行,其余照常弹窗。默认关闭。',\n commandGuardLevel: '自动放行阈值',\n commandGuardLevelHint: '阈值越高,需要越确定才放行,弹窗越多。高 = 0.95,中 = 0.9(默认),低 = 0.8。判定超过 3 秒未返回会照常弹窗。',\n commandGuardLevelHigh: '高',\n commandGuardLevelMedium: '中',\n commandGuardLevelLow: '低',\n zdr: '零数据保留(ZDR)',\n zdrHint: '仅使用不留存、不训练的上游;可用模型可能更少且价格通常更高。',\n accountsTitle: '账户',\n accountsHint: '账户操作立即生效,无需保存。可以添加多个账户:当前账户达到用量限额或密钥失效时,请求会自动切换到下一个。',\n accountAdd: '添加账户',\n accountDefault: '默认账户',\n modelSearchPlaceholder: '搜索模型…',\n modelSearchEmpty: '没有匹配的模型。',\n modelStale: '已下架',\n visibleModelsTitle: '模型白名单',\n visibleModelsHint:\n '勾选要保留的模型,模型选择器就只列出这些;一个都不勾选时则显示全部模型。'\n + '保存后,下次打开模型选择器生效。',\n visibleModelsPick: '选择要保留的模型…',\n visibleModelsCount: '已选 {count} 个模型',\n visibleModelsShowAll: '显示全部',\n visibleModelsStaleHint: '有 {count} 个已选模型在目录中找不到了(可能已下架),不影响其他模型;可清理或保留。',\n visibleModelsCleanStale: '清理失效({count})',\n overridden: '已覆盖',\n reset: '重置',\n invalidNumber: '无效数字',\n numberTooSmall: '不能小于 1(毫秒)',\n numberTooLarge: '超出允许上限(2147483647 毫秒)',\n readOnly: '当前配置为只读。',\n save: '保存',\n saving: '保存中',\n saved: '设置已保存',\n saveFailed: '保存失败,请重试。',\n unsavedChanges: '有未保存的更改',\n saveInvalid: '有字段填写不正确,修正后才能保存',\n discard: '放弃',\n cancel: '取消',\n show: '显示',\n hide: '隐藏',\n usageRefresh: '刷新',\n usageRefreshing: '刷新中…',\n usageLoading: '正在获取账户用量…',\n usageError: '用量获取失败',\n usageRequests: '请求',\n usageFailed: '失败',\n usageSuccessRate: '成功率',\n usageCost: '花费',\n usageTokens: 'Token',\n usageTokensIn: '入',\n usageTokensOut: '出',\n usageMonthly: '月额度',\n usagePurchased: '已购',\n usageFree: '赠送',\n usageFiveHour: '5 小时窗口',\n usageWeekly: '每周窗口',\n usageMonthlyLeft: '月额度剩余',\n usageExceeded: '已超限',\n usageReset: '重置于',\n usagePartial: '部分端点数据不可用',\n usageKeyInvalid: 'API 密钥无效或已过期',\n usageKeyInvalidHint: '服务端拒绝了全部请求(401)。请检查该账户配置的密钥,或到 commandcode.ai 控制台重新生成。',\n usageServiceUnavailable: 'Command Code 服务暂时不可用',\n usageServiceUnavailableHint: '服务端返回了错误(5xx),稍后点击刷新重试。',\n usageNetworkError: '无法连接 Command Code 服务',\n usageNetworkHint: '所有请求都没有到达服务端。请检查网络连接或 API 地址设置。',\n usageInvalidResponse: 'Command Code 响应无法读取',\n usageInvalidResponseHint: '请求已收到响应,但内容无法解析。请检查宿主的 HTTP 代理或响应解压配置。',\n usageUpdated: '更新于',\n usagePeriodEnd: '账期截止',\n usageActive: '当前使用',\n usageCooldown: '限额冷却中',\n usageInvalidKey: '密钥无效',\n usageUnconfigured: '该账户尚未配置 API 密钥。',\n updateAvailable: '可更新',\n updateHint: '已发布新版本,点击查看发布说明;更新插件后刷新本页,提示会自动消失。',\n loginTitle: '通过官方登录获取密钥',\n loginHintIdle: '也可通过网页授权自动获取并保存密钥。',\n loginButton: '登录 Command Code',\n loginStarting: '正在启动本地回调服务…',\n loginWaiting: '等待在浏览器中完成授权…',\n loginOpenLink: '打开授权页面 ↗',\n loginCancel: '取消登录',\n loginSuccess: '已登录为',\n loginUnavailable: '此环境暂不支持登录流程,请手动粘贴密钥。',\n loginDenied: '授权被拒绝。可重试,或手动粘贴密钥。',\n loginTimeout: '等待超时:未在窗口期内收到授权回调,请重试。',\n loginInvalidKey: '获取到的密钥未通过校验(401),请重试或手动粘贴。',\n loginNetwork: '无法连接 Command Code 服务校验密钥,请检查网络后重试。',\n loginStoreFailed: '密钥无法写入本机凭据服务,请手动粘贴。',\n loginCancelled: '登录已取消。',\n loginFailedGeneric: '登录失败,请重试或手动粘贴密钥。',\n cardTitle: 'Command Code',\n cardRouteActive: '已启用',\n cardLoadingHint: '正在读取 Command Code 配置…',\n cardRegistrationHint: '此卡片由 Command Code 插件提供,正在等待设置页装配,稍后即可显示完整内容。',\n accountsRotationHint: '账户操作立即生效。当前账户达到用量限额或密钥失效时,请求会按列表顺序自动切换到下一个可用账户。',\n accountModeAuto: '使用方式:自动切换(按列表顺序)',\n accountModePinned: '使用方式:固定使用「{name}」,不可用时仍会自动切换',\n accountStatusPinned: '已固定',\n accountActions: '账户操作',\n accountActionPin: '固定使用此账户',\n accountActionUnpin: '恢复自动切换',\n accountActionLogin: '网页登录获取新密钥',\n accountActionKey: '粘贴新密钥',\n accountActionRename: '重命名',\n accountActionClearKey: '删除密钥',\n accountActionRemove: '移除账户',\n accountRemoveConfirm: '移除「{name}」?它保存的密钥和专用模型设置会一起删除。',\n accountClearKeyConfirm: '删除默认账户保存的密钥?之后会回退到环境变量或官方 CLI 的登录信息。',\n accountConfirmRemove: '移除',\n accountConfirmClear: '删除',\n accountApply: '确定',\n accountNoKeyHint: '还没有密钥:通过网页登录自动获取,或粘贴在 commandcode.ai 控制台创建的 API 密钥。',\n accountAddHint: '网页登录会打开 Command Code 授权页,授权完成后账户自动添加;也可以直接粘贴 API 密钥。',\n accountAddLogin: '网页登录',\n accountAddPaste: '粘贴密钥',\n accountAddConfirm: '添加',\n accountNamePlaceholder: '备注名(可选,网页登录时默认使用账户名)',\n accountNameN: '账户 {n}',\n accountKeyPlaceholder: '粘贴 API 密钥',\n accountOpFailed: '账户操作未能完成,请重试。',\n accountModels: '专用模型',\n accountModelsHint: '选中的模型优先由此账户处理,此账户不可用时仍会自动切换。一个模型只属于一个账户,选中会把它从其他账户移过来。',\n accountModelOwner: '属于 {name}',\n modelPick: '选择模型…',\n modelCount: '已选 {count} 个模型',\n modelCatalogFailed: '模型目录获取失败,暂时无法选择模型;已保存的设置仍会生效。',\n modelsTitle: '模型',\n privacyTitle: '隐私与安全',\n integrationsTitle: '集成与显示',\n}\n\nexport const en: Record<SettingsCommandCodeKey, string> = {\n nav: 'Command Code',\n title: 'Command Code',\n intro: 'Account actions apply immediately; other settings are written by Save at the bottom. The API key stays in the local credential service and is never echoed.',\n apiKey: 'API key',\n apiKeyHint: 'Create one in the commandcode.ai console. Saving with this field'\n + ' blank keeps the stored key.',\n apiKeySet: 'Configured',\n apiKeyUnset: 'Not configured',\n apiKeyLocked: 'Key provided by a read-only source',\n apiBase: 'API base URL',\n apiBaseHint: 'Defaults to https://api.commandcode.ai; usually leave as-is.',\n requestTimeoutMs: 'Request timeout (ms)',\n requestTimeoutMsHint: 'Time to wait for the first response byte; default 60000.',\n streamIdleTimeoutMs: 'Stream idle timeout (ms)',\n streamIdleTimeoutMsHint: 'How long a stalled stream is treated as dead; default 300000'\n + ' (deliberately generous — long-thinking models can stay silent for minutes).',\n transportMaxRetries: 'Transport retries',\n transportMaxRetriesHint: 'How many times a failed connection is retried automatically; default 5'\n + ' (waits of 0.5+1+2+4+8s, ~15s in total). After that the failure is reported instead of waiting'\n + ' on the exponential backoff. 0 disables the retries. Rate limits and 5xx answers keep their'\n + ' own, longer retry window.',\n advancedSettings: 'Advanced',\n advancedSettingsHint: 'API base URL and network limits; usually leave as-is.',\n advancedOverriddenOne: '1 customized',\n advancedOverriddenMany: '{count} customized',\n advancedInvalid: 'A number in Advanced settings is not ready to save; expand to fix it.',\n filterModelsByPlan: 'Hide out-of-plan models',\n filterModelsByPlanHint: 'Show only models in your plan; on-demand credit accounts still see the full catalog.',\n webSearch: 'Serve dsh web search with Command Code',\n webSearchHint: 'Use the same key for dsh web search; turning it off restores the previous backend.',\n showSidebarQuota: 'Show the quota card in the sidebar',\n showSidebarQuotaHint: 'Show a plan and quota card at the bottom of the sidebar that opens the full dashboard. Off by default; while off, no background usage refresh runs for it.',\n commandGuard: 'AI command guard',\n commandGuardHint: 'Before a shell command asks for approval, typesafe/jev judges whether'\n + ' it is safe. A sandbox escalation also needs separate scope and necessity'\n + ' verdicts; all three must be confident enough to skip the prompt.'\n + ' Off by default.',\n commandGuardLevel: 'Auto-approve threshold',\n commandGuardLevelHint: 'A higher threshold needs more confidence to skip the prompt, so you'\n + ' see more prompts. High = 0.95, Medium = 0.9 (default), Low = 0.8. A judgement'\n + ' that takes longer than 3 seconds shows the normal prompt.',\n commandGuardLevelHigh: 'High',\n commandGuardLevelMedium: 'Medium',\n commandGuardLevelLow: 'Low',\n zdr: 'Zero data retention (ZDR)',\n zdrHint: 'Use only upstreams that retain no data and do not train on requests; availability and pricing may differ.',\n accountsTitle: 'Accounts',\n accountsHint: 'Account actions apply immediately, no save needed. Add more accounts and requests switch to the next one when the current account hits its usage limit or its key stops working.',\n accountAdd: 'Add account',\n accountDefault: 'Default account',\n modelSearchPlaceholder: 'Search models…',\n modelSearchEmpty: 'No matching models.',\n modelStale: 'Retired',\n visibleModelsTitle: 'Model allowlist',\n visibleModelsHint:\n 'Check the models you want to keep, and model pickers will list only those. '\n + 'If nothing is checked, every model is shown. After saving, the change '\n + 'applies the next time you open a model picker.',\n visibleModelsPick: 'Select models to keep…',\n visibleModelsCount: '{count} model(s) selected',\n visibleModelsShowAll: 'Show all',\n visibleModelsStaleHint: '{count} selected model(s) are no longer in the catalog (possibly retired);'\n + ' other models are unaffected. Clean them up or keep them.',\n visibleModelsCleanStale: 'Clean stale ({count})',\n overridden: 'Overridden',\n reset: 'Reset',\n invalidNumber: 'Invalid number',\n numberTooSmall: 'Must be at least 1 (ms)',\n numberTooLarge: 'Above the allowed maximum (2147483647 ms)',\n readOnly: 'Settings are read-only.',\n save: 'Save',\n saving: 'Saving',\n saved: 'Settings saved',\n saveFailed: 'Save failed, please retry.',\n unsavedChanges: 'You have unsaved changes',\n saveInvalid: 'Fix the highlighted field before saving',\n discard: 'Discard',\n cancel: 'Cancel',\n show: 'Show',\n hide: 'Hide',\n usageRefresh: 'Refresh',\n usageRefreshing: 'Refreshing…',\n usageLoading: 'Fetching account usage…',\n usageError: 'Could not fetch usage',\n usageRequests: 'Requests',\n usageFailed: 'failed',\n usageSuccessRate: 'Success rate',\n usageCost: 'Spend',\n usageTokens: 'Tokens',\n usageTokensIn: 'in',\n usageTokensOut: 'out',\n usageMonthly: 'Monthly',\n usagePurchased: 'Purchased',\n usageFree: 'Free',\n usageFiveHour: '5-hour window',\n usageWeekly: 'Weekly window',\n usageMonthlyLeft: 'Monthly left',\n usageExceeded: 'Exceeded',\n usageReset: 'Resets',\n usagePartial: 'Some endpoint data unavailable',\n usageKeyInvalid: 'API key invalid or expired',\n usageKeyInvalidHint: 'The server rejects every request (401). Check the key configured for this account, or generate a new one in the commandcode.ai console.',\n usageServiceUnavailable: 'The Command Code service is temporarily unavailable',\n usageServiceUnavailableHint: 'The server returned errors (5xx); try Refresh again later.',\n usageNetworkError: 'Could not reach the Command Code service',\n usageNetworkHint: 'No request reached the server. Check your network connection or the API base setting.',\n usageInvalidResponse: 'Could not read the Command Code response',\n usageInvalidResponseHint: 'The requests received responses, but their bodies could not be parsed. Check the host HTTP proxy or response decoding.',\n usageUpdated: 'Updated',\n usagePeriodEnd: 'Period ends',\n usageActive: 'Active',\n usageCooldown: 'Cooling down',\n usageInvalidKey: 'Invalid key',\n usageUnconfigured: 'No API key configured for this account yet.',\n updateAvailable: 'update available',\n updateHint: 'A newer version has been published; click for release notes. The notice disappears once the plugin is updated.',\n loginTitle: 'Sign in to fetch a key',\n loginHintIdle: 'Alternatively, sign in to fetch and store a key automatically.',\n loginButton: 'Sign in to Command Code',\n loginStarting: 'Starting the local callback server…',\n loginWaiting: 'Waiting for authorization in your browser…',\n loginOpenLink: 'Open the authorization page ↗',\n loginCancel: 'Cancel sign-in',\n loginSuccess: 'Signed in as',\n loginUnavailable: 'Sign-in is unavailable in this environment; paste the API key instead.',\n loginDenied: 'Authorization was denied. Try again or paste the key manually.',\n loginTimeout: 'Timed out waiting for the authorization callback; try again.',\n loginInvalidKey: 'The delivered key failed validation (401). Try again or paste it manually.',\n loginNetwork: 'Could not reach the Command Code service to validate the key; check your network and retry.',\n loginStoreFailed: 'The key could not be stored in the local credential service; paste it manually.',\n loginCancelled: 'Sign-in cancelled.',\n loginFailedGeneric: 'Sign-in failed; try again or paste the key manually.',\n cardTitle: 'Command Code',\n cardRouteActive: 'Active',\n cardLoadingHint: 'Loading the Command Code configuration…',\n cardRegistrationHint: 'This card is contributed by the Command Code plugin and is waiting for the settings page to finish assembling.',\n accountsRotationHint: 'Account actions apply immediately. When the current account hits its usage limit or its key stops working, requests switch to the next usable account in list order.',\n accountModeAuto: 'Mode: switch automatically (list order)',\n accountModePinned: 'Mode: pinned to \"{name}\", still switching when it is unavailable',\n accountStatusPinned: 'Pinned',\n accountActions: 'Account actions',\n accountActionPin: 'Pin this account',\n accountActionUnpin: 'Switch automatically',\n accountActionLogin: 'Sign in for a new key',\n accountActionKey: 'Paste a new key',\n accountActionRename: 'Rename',\n accountActionClearKey: 'Delete key',\n accountActionRemove: 'Remove account',\n accountRemoveConfirm: 'Remove \"{name}\"? Its stored key and dedicated models are deleted with it.',\n accountClearKeyConfirm: 'Delete the default account\\'s stored key? The provider then falls back to the environment or the official CLI sign-in.',\n accountConfirmRemove: 'Remove',\n accountConfirmClear: 'Delete',\n accountApply: 'Apply',\n accountNoKeyHint: 'No key yet: sign in through the browser, or paste an API key created in the commandcode.ai console.',\n accountAddHint: 'Sign-in opens the Command Code authorization page and adds the account once you approve; you can also paste an API key.',\n accountAddLogin: 'Sign in',\n accountAddPaste: 'Paste key',\n accountAddConfirm: 'Add',\n accountNamePlaceholder: 'Name (optional; sign-in uses the account name)',\n accountNameN: 'Account {n}',\n accountKeyPlaceholder: 'Paste an API key',\n accountOpFailed: 'The account change did not complete. Try again.',\n accountModels: 'Dedicated models',\n accountModelsHint: 'These models prefer this account and still switch when it is unavailable. A model belongs to one account; selecting it here moves it from any other.',\n accountModelOwner: 'on {name}',\n modelPick: 'Choose models…',\n modelCount: '{count} models selected',\n modelCatalogFailed: 'The model catalog could not be loaded; saved settings still apply.',\n modelsTitle: 'Models',\n privacyTitle: 'Privacy & security',\n integrationsTitle: 'Integrations & display',\n}\n","/**\n * Browser half of the dsh-commandcode-provider bundle.\n *\n * Two responsibilities:\n *\n * 1. A \"Command Code\" settings page (a `settings.section` entry at the same\n * nav level as General / Models / Plugins). The Models page renders an\n * unknown-adapter-family card for the `commandcode` provider and disables\n * its submit, so the API key cannot be configured there; this page is the\n * dedicated surface. It writes the API key through the credentials domain\n * (the `COMMANDCODE_API_KEY` reference the plugin resolves via\n * `ctx.remote.credentials`) and the connection facts through the\n * `llm-commandcode` settings namespace, so a saved key or endpoint reaches\n * the very next request.\n *\n * 2. The Models-page provider card (settings.models.provider-card) — see\n * `./card.tsx`.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { createSnapshotStore } from './snapshot-store.ts'\n// Type-only imports that pull in the client-service augmentations\n// (`slots`/`remote`/`locale` on Context) and the `settings.section` SlotMap\n// entry (declared through dsh-client-ui-settings).\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { createSettingsScope, type SettingsRemoteNamespace, type SettingsScopeContext } from './settings-scope.ts'\nimport { CommandCodeSettingsController, COMMANDCODE_NS, type SettingsPageState } from './settings.ts'\nimport type { SettingsPageApi } from './settings.ts'\nimport { CommandCodeUsageController, type UsagePageState, type UsageRemote } from './usage.ts'\nimport { CommandCodePricesController, type SessionCostPricesState } from './prices.ts'\nimport { CommandCodeLoginController, type LoginPageState, type LoginRemote } from './login.ts'\nimport { USAGE_REMOTE_CONTRIBUTION, MODELS_REMOTE_CONTRIBUTION, PRICES_REMOTE_CONTRIBUTION } from '../usage-wire.ts'\nimport { LOGIN_REMOTE_CONTRIBUTION } from '../login-wire.ts'\nimport type { TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'\nimport { CommandCodeSettingsPage } from './section.tsx'\nimport { CommandCodeProviderCard } from './card.tsx'\nimport { CommandCodePanel, CommandCodeFooterEntry } from './panel-view.tsx'\nimport type { PanelInjected } from './panel-view.tsx'\nimport { CommandCodeSessionCost } from './session-cost-view.tsx'\nimport type { SessionCostInjected } from './session-cost-view.tsx'\nimport { startPanelAutoRefresh } from './panel.ts'\nimport { PAGE_CSS, PAGE_CSS_ID } from './page-styles.ts'\nimport { PANEL_CSS, PANEL_CSS_ID } from './panel-styles.ts'\n// Type-only: pulls in the SlotMap merge for the composer dock\n// (`./session-cost-slots.ts`). The sidebar-foot / center-column merge rides the\n// `./panel-view.tsx` value import above, which imports `./panel-slots.ts`.\nimport type {} from './session-cost-slots.ts'\nimport { zh, en } from './locales.ts'\nimport { PANEL_COPY_EN, PANEL_COPY_ZH, PANEL_LOCALE_NS } from './panel-copy.ts'\n\n\n\n/** Inject the page stylesheet once (idempotent per tag). */\nfunction injectPageCss(): void {\n if (typeof document === 'undefined') return\n if (document.querySelector(`style[data-plugin-css=\"${PAGE_CSS_ID}\"]`) !== null) return\n const tag = document.createElement('style')\n tag.dataset.plugin = '@mars-sea/dsh-commandcode-provider'\n tag.dataset.pluginCss = PAGE_CSS_ID\n tag.textContent = PAGE_CSS\n document.head.appendChild(tag)\n}\n\n/**\n * Install the plans & quota panel's stylesheet and return its disposer, for\n * `ctx.effect` to own. Keyed by its own `data-plugin-css` id, so the injection\n * is idempotent even if a second surface asks for it later.\n */\nfunction injectPanelCss(): () => void {\n if (typeof document === 'undefined') return () => {}\n if (document.querySelector(`style[data-plugin-css=\"${PANEL_CSS_ID}\"]`) !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.plugin = '@mars-sea/dsh-commandcode-provider'\n tag.dataset.pluginCss = PANEL_CSS_ID\n tag.textContent = PANEL_CSS\n document.head.appendChild(tag)\n return () => {\n tag.remove()\n }\n}\n\n/**\n * Plans & quota panel id. It is the layout's `MainPanelId`: one string shared\n * by the `sidebar.footer.action` card and the `main` slot cell, so the card\n * selects this panel and nothing else. `dsh-client-ui-layout` is not a\n * dependency of this bundle (its type is only a brand over `string`), so the\n * brand is applied at the call site instead of importing the package.\n */\nconst PANEL_ID = 'commandcode-panel'\n\n/**\n * The composer figure's entry id in `conversation.composer.dock`. Its own id,\n * not the shipped `stats` cell's: reusing `stats` would REPLACE the tokens /\n * cache-hit / throughput readout rather than inject into it, and that readout\n * is the harness's to format (see `./session-cost-display.ts`).\n */\nconst SESSION_COST_ID = 'commandcode-session-cost'\n\n/**\n * The one shot of the `layout` service this plugin needs, declared\n * structurally for the same reason as {@link PANEL_ID}: importing the package\n * would make the browser resolve a client module this bundle never calls.\n * Reached through the reflective `ctx.get('layout')`, never a bare `ctx.layout`\n * property — cordis throws `cannot get property … without inject` for an\n * undeclared service, and declaring `layout` statically would park the whole\n * client fiber (settings page included) on a service some profiles never mount.\n */\ninterface LayoutSelectionSeam {\n /** `null` shows the Conversation again; a string selects that registered `main` key. */\n selectPanel(id: string | null): void\n}\n\n/**\n * Client plugin body. Gates on `slots`, `locale` and `remote` — never on\n * `settingsScope`, whose wrapper service the 0.1.7 settings rewrite removed\n * (the settings scope here speaks the `remote.settings` wire directly). The\n * page mounts once `remote.credentials` appears.\n */\nexport function apply(ctx: Context): void {\n injectPageCss()\n\n // The \"Command Code\" settings page: register the section once the\n // `settings.section` declaration is on the ledger (ui-settings-general\n // owns the shell; registration order relative to it is not constrained —\n // `slots.inject` waits for the declaration).\n ctx.effect(() => ctx.locale.register('settings.commandcode', { zh, en }), 'dsh-commandcode-provider: page copy')\n\n // The plans & quota panel's copy is a namespace of its own: the panel is not\n // part of the settings page, but it follows the SAME active language (both\n // panel registrations declare it below, which is what binds their `t` seat).\n ctx.effect(\n () => ctx.locale.register(PANEL_LOCALE_NS, { zh: PANEL_COPY_ZH, en: PANEL_COPY_EN }),\n 'dsh-commandcode-provider: panel copy',\n )\n\n // Credentials reach the browser as a Typert Remote namespace. The inject is\n // the activation gate for every surface below, so a profile whose Host serves\n // no credentials namespace simply never mounts the page.\n ctx.inject(['remote.credentials'], (remoteCtx) => {\n const credentials = (remoteCtx.remote as unknown as {\n credentials: SettingsPageApi['credentials']\n }).credentials\n applyClientSurfaces(remoteCtx, { credentials })\n })\n}\n\n/** Mount the one shared UI implementation. */\nfunction applyClientSurfaces(\n ctx: Context,\n api: SettingsPageApi,\n): void {\n // The settings scope: this plugin's own binding of the `llm-commandcode`\n // namespace over `remote.settings` (see `./settings-scope.ts`). The harness\n // used to provide a `settingsScope` service to bind here, but that wrapper\n // existed only through 0.1.6 and was removed with the 0.1.7 settings\n // rewrite — while the describe/mutate wire underneath spans every\n // supported release, so one implementation now serves all of them.\n //\n // The namespace object is captured from an INJECT-SCOPED context, never read\n // off `ctx.remote`: `remote.settings` is a Cordis service nested under\n // `remote`, and cordis answers a read through a context that does not declare\n // it with `Error: cannot get property \"remote.settings\" without inject`. That\n // throw lands inside the scope's own `try`/`catch` (so nothing is logged),\n // leaving the mirror unanswered, the scope on its initial `writable: false`\n // snapshot, and the page read-only with every control disabled — the 0.1.7\n // settings-page report. The resolver below hands the scope the very object\n // the inject resolved; `refresh()` re-reads once it lands, and a profile whose\n // Host serves no settings namespace simply never resolves it, where the page\n // keeps rendering its degraded state instead of crashing.\n let settingsNamespace: SettingsRemoteNamespace | undefined\n const scope = createSettingsScope<Record<string, unknown>>(\n ctx as unknown as SettingsScopeContext,\n COMMANDCODE_NS,\n () => settingsNamespace,\n )\n ctx.effect(() => () => { void scope.dispose() }, 'dsh-commandcode-provider: settings scope')\n ctx.inject(['remote.settings'], (settingsCtx) => {\n settingsNamespace = (settingsCtx.remote as unknown as {\n settings: SettingsRemoteNamespace\n }).settings\n // The first read raced this inject and answered \"not mounted\"; re-read now\n // that the namespace is here (and again whenever it re-mounts).\n scope.refresh()\n settingsCtx.effect(() => () => {\n settingsNamespace = undefined\n }, 'dsh-commandcode-provider: settings namespace')\n })\n // The model catalog for the settings page's model editors (the\n // routing-rule editor and the visible-models filter) is served by the\n // `commandcode/models` Remote below; the controller reads it through this\n // mutable seam so the Remote mount (which happens after the controller is\n // constructed) still reaches the catalog fetch. Unset until the mount\n // lands — the controller degrades to the empty-catalog state meanwhile.\n let modelsRemote: NonNullable<SettingsPageApi['models']> | undefined\n const controller = new CommandCodeSettingsController(\n scope,\n { ...api, models: () => modelsRemote?.() ?? Promise.resolve({ ok: false, error: { message: 'commandcode/models remote is not mounted' } }) },\n )\n ctx.effect(() => () => controller.dispose(), 'dsh-commandcode-provider: settings controller')\n const store = createSnapshotStore<SettingsPageState>(controller.state())\n controller.subscribe(() => store.set(controller.state()))\n ctx.effect(\n () => (ctx.remote as unknown as {\n $on(event: 'credentials/reference-updated', listener: (ref: string) => void): () => void\n }).$on('credentials/reference-updated', () => { controller.refreshCredentials() }),\n 'dsh-commandcode-provider: credential invalidations',\n )\n\n // The account-usage card + login panel: mount the shared Remote contribution\n // (one mount carries every endpoint this plugin serves — report, catalog,\n // price table, and login — so the Client's bookkeeping stays 1:1 with the\n // Host's single registry registration), then resolve the\n // `remote.commandcode` namespace through a scoped inject. Cordis only serves\n // services a fiber declares in `inject`, and the namespace service exists\n // only after the mount — a static inject would deadlock the plugin (the\n // mounter would wait for its own mount), so the inject is registered\n // dynamically once the mount lands. A Host half that predates the Remote\n // fails the calls instead, and the surfaces render their error branches.\n let usageNamespace: (typeof ctx.remote)['commandcode'] | undefined\n let usageMountError: string | undefined\n // Declared here, constructed below once the Remote seam exists: the mount\n // effect underneath calls `ensure()` from its inject callback, which cordis\n // runs synchronously while the mount promise settles — before the\n // controller's own `const` below would have been initialized.\n let pricesController: CommandCodePricesController | undefined\n // The same hazard for the usage controller, whose `const` is just as far\n // below: the inject callback needs a way to ask for a report without\n // touching that binding before it is initialized (a `const` read in its\n // temporal dead zone THROWS, so `?.` would not save it).\n let refreshUsage: (() => void) | undefined\n const contribution: TypertRemoteContribution = {\n package: USAGE_REMOTE_CONTRIBUTION.package,\n descriptors: [\n ...USAGE_REMOTE_CONTRIBUTION.descriptors,\n ...MODELS_REMOTE_CONTRIBUTION.descriptors,\n ...PRICES_REMOTE_CONTRIBUTION.descriptors,\n ...LOGIN_REMOTE_CONTRIBUTION.descriptors,\n ],\n }\n ctx.effect(() => {\n let cancelled = false\n let unmount: (() => Promise<void>) | undefined\n void ctx.remote.$mount(contribution).then((dispose: () => Promise<void>) => {\n if (cancelled) {\n void dispose()\n return\n }\n unmount = dispose\n ctx.inject(['remote.commandcode'], (namespaceCtx) => {\n usageNamespace = namespaceCtx.remote.commandcode\n // The catalog Remote is live now; (re)fetch it for the model editors.\n controller.refreshCatalog()\n // ...and the price table, which the composer's cost readout needs. This\n // is its only trigger: `ensure()` is idempotent, so a readout already on\n // screen simply starts pricing when the table lands, and asking earlier\n // could only fail (the namespace did not exist yet).\n pricesController?.reload()\n // ...and the usage report. A surface can (and on a boot with the quota\n // card on, always does) ask for it BEFORE this mount lands: the answer\n // then is the synthetic \"remote is not mounted\" failure, which the\n // controller stores as `status: 'error'` — and its `shouldRefresh` only\n // fires from `idle`, so nothing would ever retry it (`usage.ts`). The\n // namespace is live here, so re-read now and replace that stale answer.\n refreshUsage?.()\n namespaceCtx.effect(() => () => {\n usageNamespace = undefined\n }, 'dsh-commandcode-provider: usage namespace')\n })\n }, (error: unknown) => {\n // A mount failure (e.g. a harness without the Remote mount) leaves the\n // namespace unset; keep the reason so the card can surface it.\n usageMountError = error instanceof Error ? error.message : String(error)\n })\n return () => {\n cancelled = true\n usageNamespace = undefined\n if (unmount !== undefined) void unmount()\n }\n }, 'dsh-commandcode-provider: usage remote')\n const usageRemote: UsageRemote = {\n report: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/report remote is not mounted' } }\n }\n return namespace.report()\n },\n models: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/models remote is not mounted' } }\n }\n return namespace.models()\n },\n prices: async () => {\n const namespace = usageNamespace\n if (namespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode/prices remote is not mounted' } }\n }\n const call = namespace.prices\n // A Host half older than the price table mounts no such descriptor, so\n // the namespace member is genuinely missing. Report it as a failure the\n // readout treats as permanent rather than throwing.\n if (typeof call !== 'function') {\n return { ok: false, error: { message: 'the Host serves no commandcode/prices endpoint', permanent: true } }\n }\n return call.call(namespace)\n },\n }\n // Wire the catalog Remote into the settings controller's models seam so the\n // model editors can fetch the catalog once the mount lands.\n modelsRemote = () => usageRemote.models()\n const usageController = new CommandCodeUsageController(usageRemote)\n refreshUsage = () => void usageController.refresh()\n ctx.effect(() => () => usageController.dispose(), 'dsh-commandcode-provider: usage controller')\n const usageStore = createSnapshotStore<UsagePageState>(usageController.state())\n usageController.subscribe(() => usageStore.set(usageController.state()))\n\n // The composer's session-cost readout prices a session from a static table,\n // so its controller is a one-shot cache rather than a poll: it fetches once\n // the namespace is live and never again.\n pricesController = new CommandCodePricesController(usageRemote)\n ctx.effect(() => () => pricesController?.dispose(), 'dsh-commandcode-provider: price table')\n const pricesStore = createSnapshotStore<SessionCostPricesState>(pricesController.state())\n pricesController.subscribe(() => pricesStore.set(pricesController.state()))\n\n // The login panel: same namespace, three endpoints; the key never crosses\n // to the browser — the Host validates and stores it through the credentials\n // seam, and a landed login re-reads the credential badges + usage card.\n const loginRemote: LoginRemote = {\n loginBegin: async (targetRef?: string) => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginBegin(targetRef)\n },\n loginStatus: async () => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginStatus()\n },\n loginCancel: async () => {\n if (usageNamespace === undefined) {\n return { ok: false, error: { message: usageMountError ?? 'commandcode remote is not mounted' } }\n }\n return usageNamespace.loginCancel()\n },\n }\n const loginController = new CommandCodeLoginController(() => loginRemote)\n ctx.effect(() => () => loginController.dispose(), 'dsh-commandcode-provider: login controller')\n const loginStore = createSnapshotStore<LoginPageState>(loginController.state())\n let lastLoginPhase = loginController.state().phase\n loginController.subscribe(() => {\n const phase = loginController.state().phase\n // A landed login stored the key Host-side behind the page's back; the\n // badges must follow and the account card can finally fetch.\n if (phase === 'success' && lastLoginPhase !== 'success') {\n controller.refreshCredentials()\n void usageController.refresh()\n }\n lastLoginPhase = phase\n loginStore.set(loginController.state())\n })\n\n const refreshUsageOn = (ok: boolean): boolean => {\n if (ok) void usageController.refresh()\n return ok\n }\n const injected = () => ({\n hooks: { commandCodeSettings: store, commandCodeUsage: usageStore, commandCodeLogin: loginStore },\n edit: (field: string, text: string) => controller.edit(field, text),\n resetField: (field: string) => controller.resetField(field),\n // A landed save can change the key or endpoint the usage endpoints read,\n // so the account card refetches; a failed save keeps the old data.\n save: () => void controller.save().then(() => {\n const settled = controller.state()\n if (!settled.failed && settled.anyAccountConfigured) void usageController.refresh()\n }),\n discard: () => controller.discard(),\n refreshUsage: () => void usageController.refresh(),\n beginLogin: (targetRef?: string) => void loginController.begin(targetRef),\n cancelLogin: () => void loginController.cancel(),\n // Account operations commit immediately. The ones that change which keys\n // exist refetch the usage report so the account rows follow.\n createAccount: (input: { label: string; key?: string }) => controller.createAccount(input).then((ref) => {\n if (ref !== undefined && input.key) void usageController.refresh()\n return ref\n }),\n renameAccount: (ref: string, label: string) => controller.renameAccount(ref, label),\n removeAccount: (ref: string) => controller.removeAccount(ref).then(refreshUsageOn),\n setAccountKey: (target: string, key: string) => controller.setAccountKey(target, key).then(refreshUsageOn),\n clearAccountKey: (target: string) => controller.clearAccountKey(target).then(refreshUsageOn),\n setActiveAccount: (id: string) => controller.setActiveAccount(id).then(refreshUsageOn),\n setAccountModels: (target: string, ids: string[]) => controller.setAccountModels(target, ids),\n editVisibleModels: (ids: string[]) => controller.editVisibleModels(ids),\n clearVisibleModels: () => controller.clearVisibleModels(),\n })\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'commandcode',\n order: 12,\n label: () => ctx.locale.bind('settings.commandcode')('nav'),\n locale: 'settings.commandcode',\n inject: injected,\n }, CommandCodeSettingsPage))\n\n // The Models-page provider panel (dsh 0.1.2, rc.1): a keyed slot the\n // Models section dispatches with `entryKey = settingsNs` on every provider\n // card of an adapter family. Registering under `llm-commandcode` mounts the\n // panel beside the official editor on every Command Code row — including\n // the first-run setup posture, exactly where a user without a key lands.\n // While the official 编辑 toggle is open, the panel hides the official\n // editor shell (for this namespace it holds only the settings.yaml hint\n // over a disabled apply) and shows the real controls; see card.tsx.\n // The registration carries its own inject face (store hooks + actions)\n // because the declaring entry is ui-settings-models', not ours; the `t`\n // seat comes from the registration's own `locale` namespace.\n //\n // On dsh builds without this slot the declaration never exists and\n // `slots.inject` never fires its callback — the registration silently\n // does not happen, and nothing else about the plugin changes.\n ctx.slots.inject('settings.models.provider-card', () => ctx.slots.register({\n name: 'settings.models.provider-card',\n key: 'llm-commandcode',\n locale: 'settings.commandcode',\n inject: () => ({\n hooks: { commandCodeSettings: store, commandCodeLogin: loginStore },\n edit: (field: string, text: string) => controller.edit(field, text),\n save: () => void controller.save().then(() => {\n const settled = controller.state()\n if (!settled.failed && settled.anyAccountConfigured) void usageController.refresh()\n }),\n discard: () => controller.discard(),\n beginLogin: () => void loginController.begin(),\n cancelLogin: () => void loginController.cancel(),\n }),\n }, CommandCodeProviderCard))\n\n // The plans & quota panel: a footer card pinned at the bottom of the\n // sidebar, on top of the Settings seat, that opens a dashboard in the\n // center column.\n //\n // Two registrations, one navigation entry. `sidebar.footer.action` is the\n // list the sidebar shell renders in its foot area directly above the\n // Settings seat (`footArea` = `footerActions` then `settingsArea`), which is\n // what puts this card at the bottom of the column rather than at the top\n // with the global panel icons of `sidebar.panellist`. The layout's keyed\n // `main` slot holds the panel the card opens — `ctx.layout.selectPanel(id)`\n // resolves the id against that registry and throws when no cell occupies it,\n // so BOTH are required, and BOTH need the `inject` face below (an entry\n // without one receives none of the panel's data; see the `hooks` → `useX`\n // rule in panel-view.tsx).\n //\n // Unlike a `sidebar.panellist` row, the shell renders NO chrome around a\n // footer action: our component is the button, it owns the label (so a title\n // carrying live quota needs no re-registration — that dance exists only\n // because the shell caches a panellist entry's label), and it selects the\n // panel itself through the `open` action below.\n //\n // Both registrations declare the panel's own `locale` namespace\n // (`panel.commandcode`, registered in `apply` above), which is what binds the\n // `t` seat the components feed into `buildPanelView` — so the panel follows\n // the harness's active language and a switch re-renders it (the renderer\n // mints a fresh `t` per revision, and its identity is the invalidation).\n //\n // The footer card opens the panel through `layout.selectPanel`, so it is\n // gated on the `layout` SERVICE rather than only on its slot: a profile whose\n // `main` declaration exists but whose layout never mounted (a headless client)\n // would otherwise register a card that renders and does nothing when clicked\n // — a dead button.\n //\n // The dashboard cell itself needs no such gate: registering a cell for a\n // declaration that never arrives is a no-op by construction (the callback only\n // runs while the declaration is live). Only the always-declared footer seat\n // needed an explicit guard.\n //\n // Shape notes:\n // * The stylesheet gets its own `ctx.effect` rather than riding an `inject`\n // callback's return value, so the tag's lifetime is the plugin fiber's and\n // is unaffected by a slot declaration collapsing and re-declaring.\n // * Each registration is guarded so a failure in one surface cannot abort\n // `applyClientSurfaces` and take the OTHER surfaces down with it —\n // `slots.inject` rethrows a callback failure synchronously once the\n // declaration exists. The renderer contains a *render* crash by abdicating\n // the entry with no visible error, so a failure that leaves nothing on\n // screen must at least be loud in the console.\n const panelFace = (): PanelInjected => ({\n hooks: { commandCodeUsage: usageStore, commandCodeSettings: store },\n refresh: () => { pricesController?.ensure(); void usageController.refresh() },\n // The Host resolves every credential source, including CLI auth and literals.\n // A browser credential-reference lookup cannot determine availability.\n startAutoRefresh: () => startPanelAutoRefresh(usageController, () => true),\n // `layout` is read reflectively AT CLICK TIME, never captured at setup:\n // ui-layout is not a dependency of this bundle (its types are not imported\n // and its client module is never resolved), so a static `inject` would park\n // the whole client fiber — settings page included — on a service another\n // profile may never mount. The footer registration is gated on that same\n // seam, so by the time this runs the method exists; the guard stays as the\n // last line of defence against a layout that renames it.\n open: () => {\n const layout = ctx.get('layout') as LayoutSelectionSeam | undefined\n layout?.selectPanel(PANEL_ID)\n },\n // The dashboard's way out (issue #41). It occupies the center column in\n // place of the Conversation, and `open()` above is the ONLY other panel\n // selection this plugin makes — so without an exit the panel is a one-way\n // door: clicking the sidebar card just re-selects it. `selectPanel(null)`\n // is layout's \"show the Conversation\" selection and leaves the current\n // Session untouched.\n close: () => {\n const layout = ctx.get('layout') as LayoutSelectionSeam | undefined\n layout?.selectPanel(null)\n },\n })\n\n ctx.effect(() => injectPanelCss(), 'dsh-commandcode-provider: panel styles')\n\n try {\n ctx.slots.inject('main', () => ctx.slots.register(\n { name: 'main', key: PANEL_ID, locale: PANEL_LOCALE_NS, inject: panelFace },\n CommandCodePanel,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the plans & quota panel:', error)\n }\n\n // The footer card is registered only where the layout can actually open the\n // panel behind it. `ctx.inject(['layout'], …)` runs its body when that service\n // is live and re-runs it if the service is replaced, mirroring how the Remote\n // namespace is mounted — so a profile without ui-layout (the TUI, a headless\n // client) never registers the card. Without this gate the card would render\n // and silently do nothing on click, which is worse than not being there.\n ctx.inject(['layout'], (layoutCtx) => {\n try {\n layoutCtx.slots.inject('sidebar.footer.action', () => layoutCtx.slots.register(\n // `order` is the only control over position inside a list slot, and the\n // renderer sorts ascending. ui-cordis's footer chip registers at the\n // default 0, so 1 sorts after it — but any sibling passing an order ≥ 1\n // lands between this card and Settings, so \"directly above Settings\" is\n // a preference, not a guarantee.\n { name: 'sidebar.footer.action', id: PANEL_ID, order: 1, locale: PANEL_LOCALE_NS, inject: panelFace },\n CommandCodeFooterEntry,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the sidebar footer card:', error)\n }\n })\n\n // The composer's session-cost figure: an entry in the dock below the input\n // that renders NO surface of its own. The cost is injected into the harness's\n // own token-usage UI — the amount as the last item of the shipped pill's text\n // run, the breakdown as rows inside the usage dialog that pill opens (see\n // `./session-cost-display.ts`).\n //\n // The entry exists for its SEATS, not for a surface: `useProjection` is a\n // standard prop the composer hands every dock occupant, so this registration\n // is the only way to read the session's token accounting. Its id must stay\n // distinct from the shipped `stats` cell's, because registering under an\n // existing id REPLACES that cell rather than extending it.\n //\n // It carries only the price-table hook: the token buckets and the model\n // selection arrive from the composer itself as standard dock props\n // (`useProjection`), which the owner supplies to every occupant.\n //\n // No `locale` namespace and no `t` seat: the figure is English by\n // construction, from `./session-cost.ts`.\n const sessionCostFace = (): SessionCostInjected => ({\n hooks: { commandCodePrices: pricesStore },\n })\n\n try {\n ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register(\n // No `order`: the entry renders nothing, so its position among the dock's\n // rows cannot matter — the sort only ever decides what a reader sees.\n { name: 'conversation.composer.dock', id: SESSION_COST_ID, inject: sessionCostFace },\n CommandCodeSessionCost,\n ))\n } catch (error: unknown) {\n console.error('[dsh-commandcode-provider] could not register the composer session-cost readout:', error)\n }\n}\n\nexport const inject: readonly string[] = [\n 'slots',\n 'locale',\n 'remote',\n]\n"],"mappings":"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"}
|