@mars-sea/dsh-commandcode-provider 0.2.0 → 0.2.2
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 +19 -0
- package/README.md +11 -8
- package/README.zh-CN.md +11 -8
- package/lib/client.js +666 -10
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +10 -11
- package/lib/index.js +18 -68
- package/lib/index.js.map +1 -1
- package/package.json +23 -3
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/client/index.ts"],"sourcesContent":["/**\n * Browser half of the dsh-commandcode-provider bundle.\n *\n * The host rejects switching to a text-only model while the session already\n * contains images with a harness-level `model-unavailable` error\n * (`dsh-host-apiproxy`'s `session.selectModel` handler). That rejection is\n * intentional and cannot be relaxed from the plugin side — the adapter's\n * `inputModalities` is exactly what makes the guard work. What we CAN do is\n * make the error message friendlier: this client plugin wraps the shared\n * `connection.api.sessions.selectModel` face so a `model-unavailable`\n * rejection shows a clear, actionable hint (with the requested model name)\n * instead of the raw English harness message.\n *\n * The wrapper is deliberately narrow: only the `model-unavailable` code is\n * rewritten, only when the message matches the image-session gate, and only\n * the message text changes — the error code and details pass through\n * untouched so any caller that switches on `error.code` keeps working.\n *\n * The wire types are spelled structurally here (not imported from\n * `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag an\n * extra peer dependency into the package; the shapes are stable and the\n * client build inlines them anyway.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n\n/** The `model-unavailable` error details: provider + model id. */\ninterface ModelUnavailableDetails {\n provider: string\n model: string\n}\n\n/** The narrow slice of the RPC error we need to inspect and rewrite. */\ninterface RpcErrorLike {\n code: string\n message: string\n details?: ModelUnavailableDetails\n}\n\n/**\n * The narrow slice of a unary RPC result we need to inspect and rewrite.\n * The wire shape from `sessions.selectModel` (via `AbstractApiClient.callUnary`)\n * is the full envelope `{ rpcId, result: { ok, error? } }` — the error lives\n * under `result.result`, not at the top level. `RpcResultLike` models that.\n */\ninterface RpcResultLike {\n rpcId: string\n result:\n | { ok: true; value?: unknown }\n | { ok: false; error: RpcErrorLike }\n}\n\n/** One selectModel call: payload in, envelope out. */\ntype SelectModelCall = (\n payload: { sessionId: string; provider: string; model: string; reasoningEffort?: string },\n signal?: AbortSignal,\n) => Promise<RpcResultLike>\n\n/** The shared sessions wire face we wrap. */\ninterface SessionsLike {\n selectModel: SelectModelCall\n}\n\n/** The connection handle shape we read `api.sessions` from. */\ninterface ConnectionLike {\n api: { sessions: SessionsLike }\n}\n\n/** Whether a selectModel rejection is the harness's image-session gate. */\nexport function isImageSessionRejection(\n result: RpcResultLike,\n): result is RpcResultLike & { result: { ok: false; error: RpcErrorLike } } {\n return (\n !result.result.ok &&\n result.result.error.code === 'model-unavailable' &&\n result.result.error.message.includes('does not accept image input')\n )\n}\n\n/** Wrap the shared sessions API so selectModel failures read friendlier. */\nexport function withFriendlyImageError(sessions: SessionsLike): SessionsLike {\n const selectModel = sessions.selectModel.bind(sessions)\n return {\n ...sessions,\n selectModel: async (payload, signal) => {\n const result = await selectModel(payload, signal)\n if (!isImageSessionRejection(result)) return result\n const model = result.result.error.details?.model ?? payload.model\n return {\n ...result,\n result: {\n ...result.result,\n error: {\n ...result.result.error,\n message:\n `当前会话已包含图片,而模型 ${model} 不支持图片输入;`\n + '请选择支持图片的模型,或先移除会话中的图片。',\n },\n },\n }\n },\n }\n}\n\n/**\n * Client plugin body: install the selectModel wrapper on the connection's\n * shared api. `inject: ['connection']` gates activation until the connection\n * service is provided (the same pattern the harness's own client plugins\n * use), and `connection.api.sessions` is a stable object the model-selection\n * UI reads fresh on every call — so wrapping it once covers both the /model\n * popup and the composer seat, across reconnects.\n */\nexport function apply(ctx: Context): void {\n const connection = ctx.get('connection') as ConnectionLike | undefined\n if (connection === undefined) return\n connection.api.sessions = withFriendlyImageError(connection.api.sessions)\n}\n\nexport const inject: readonly string[] = ['connection']\n"],"mappings":";;;;;;;;EAqEA,SAAgB,wBACd,QAC0E;GAC1E,OACE,CAAC,OAAO,OAAO,MACf,OAAO,OAAO,MAAM,SAAS,uBAC7B,OAAO,OAAO,MAAM,QAAQ,SAAS,6BAA6B;EAEtE;;EAGA,SAAgB,uBAAuB,UAAsC;GAC3E,MAAM,cAAc,SAAS,YAAY,KAAK,QAAQ;GACtD,OAAO;IACL,GAAG;IACH,aAAa,OAAO,SAAS,WAAW;KACtC,MAAM,SAAS,MAAM,YAAY,SAAS,MAAM;KAChD,IAAI,CAAC,wBAAwB,MAAM,GAAG,OAAO;KAC7C,MAAM,QAAQ,OAAO,OAAO,MAAM,SAAS,SAAS,QAAQ;KAC5D,OAAO;MACL,GAAG;MACH,QAAQ;OACN,GAAG,OAAO;OACV,OAAO;QACL,GAAG,OAAO,OAAO;QACjB,SACE,iBAAiB,MAAM;OAE3B;MACF;KACF;IACF;GACF;EACF;;;;;;;;;EAUA,SAAgB,MAAM,KAAoB;GACxC,MAAM,aAAa,IAAI,IAAI,YAAY;GACvC,IAAI,eAAe,KAAA,GAAW;GAC9B,WAAW,IAAI,WAAW,uBAAuB,WAAW,IAAI,QAAQ;EAC1E;EAEA,MAAa,SAA4B,CAAC,YAAY"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["Button","createSnapshotStore"],"sources":["../src/client/sessions.ts","../src/client/settings.ts","../src/client/section.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * Friendly-error wrapper for the harness's image-session gate.\n *\n * The host rejects switching to a text-only model while the session already\n * contains images with a `model-unavailable` error\n * (`dsh-host-apiproxy`'s `session.selectModel` handler). That rejection is\n * intentional and cannot be relaxed from the plugin side — the adapter's\n * `inputModalities` is exactly what makes the guard work. What we CAN do is\n * make the error message friendlier: wrap the shared\n * `connection.api.sessions.selectModel` face so a `model-unavailable`\n * rejection shows a clear, actionable hint (with the requested model name)\n * instead of the raw English harness message.\n *\n * The wrapper is deliberately narrow: only the `model-unavailable` code is\n * rewritten, only when the message matches the image-session gate, and only\n * the message text changes — the error code and details pass through\n * untouched so any caller that switches on `error.code` keeps working.\n *\n * The wire types are spelled structurally here (not imported from\n * `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag an\n * extra peer dependency into the package; the shapes are stable and the\n * client build inlines them anyway.\n *\n * This module is deliberately free of React and other client-platform\n * imports so the node test runner can exercise it directly.\n */\n\n/** The `model-unavailable` error details: provider + model id. */\ninterface ModelUnavailableDetails {\n provider: string\n model: string\n}\n\n/** The narrow slice of the RPC error we need to inspect and rewrite. */\ninterface RpcErrorLike {\n code: string\n message: string\n details?: ModelUnavailableDetails\n}\n\n/**\n * The narrow slice of a unary RPC result we need to inspect and rewrite.\n * The wire shape from `sessions.selectModel` (via `AbstractApiClient.callUnary`)\n * is the full envelope `{ rpcId, result: { ok, error? } }` — the error lives\n * under `result.result`, not at the top level. `RpcResultLike` models that.\n */\ninterface RpcResultLike {\n rpcId: string\n result:\n | { ok: true; value?: unknown }\n | { ok: false; error: RpcErrorLike }\n}\n\n/** One selectModel call: payload in, envelope out. */\ntype SelectModelCall = (\n payload: { sessionId: string; provider: string; model: string; reasoningEffort?: string },\n signal?: AbortSignal,\n) => Promise<RpcResultLike>\n\n/** The shared sessions wire face we wrap. */\ninterface SessionsLike {\n selectModel: SelectModelCall\n}\n\n/** Whether a selectModel rejection is the harness's image-session gate. */\nexport function isImageSessionRejection(\n result: RpcResultLike,\n): result is RpcResultLike & { result: { ok: false; error: RpcErrorLike } } {\n return (\n !result.result.ok &&\n result.result.error.code === 'model-unavailable' &&\n result.result.error.message.includes('does not accept image input')\n )\n}\n\n/** Wrap the shared sessions API so selectModel failures read friendlier. */\nexport function withFriendlyImageError(sessions: SessionsLike): SessionsLike {\n const selectModel = sessions.selectModel.bind(sessions)\n return {\n ...sessions,\n selectModel: async (payload, signal) => {\n const result = await selectModel(payload, signal)\n if (!isImageSessionRejection(result)) return result\n const model = result.result.error.details?.model ?? payload.model\n return {\n ...result,\n result: {\n ...result.result,\n error: {\n ...result.result.error,\n message:\n `当前会话已包含图片,而模型 ${model} 不支持图片输入;`\n + '请选择支持图片的模型,或先移除会话中的图片。',\n },\n },\n }\n },\n }\n}\n\n/** The connection handle shape we read `api.sessions` from. */\nexport interface ConnectionLike {\n api: { sessions: SessionsLike }\n}\n\n/** Install the wrapper on a connection's shared sessions face. */\nexport function installFriendlyImageError(connection: ConnectionLike): void {\n connection.api.sessions = withFriendlyImageError(connection.api.sessions)\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 the\n * `settingsScope` service, keeps a staged draft of edits, and writes them on\n * save through `scope.set` / the credentials domain. The Host stays the\n * single fact source; the snapshot is republished 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\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-runtime/client'\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 narrow slice of the wire face this controller needs. */\nexport interface SettingsPageApi {\n credentials: {\n describe(request: { refs: string[] }): Promise<{\n result: { ok: true; value: { credentials: Record<string, { configured: boolean; writable: boolean }> } } | { ok: false; error: { message: string } }\n }>\n set(request: { ref: string; value: string }): Promise<{ result: { ok: true; value?: unknown } | { ok: false; error: { message: string } } }>\n }\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\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 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 /** 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 /** 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\n/** Parsed outcome of one field's draft. */\ntype Parsed = { kind: 'set'; value: string | number } | { kind: 'clear' } | { kind: 'invalid' }\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/** A whole-number field; an empty draft clears it, anything non-numeric blocks save. */\nfunction numberField(field: string): 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 return Number.isFinite(parsed) ? { kind: 'set', value: parsed } : { kind: 'invalid' }\n },\n }\n}\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'),\n numberField('streamIdleTimeoutMs'),\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 private credential = { ref: DEFAULT_API_KEY_REF, configured: false, writable: true }\n private saving = false\n private failed = false\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 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.readCredential()\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.credential.ref) return\n this.credential = { ref: named, configured: false, writable: true }\n void this.readCredential()\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 return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n apiKeyConfigured: this.credential.configured,\n apiKeyWritable: this.credential.writable,\n apiKey: {\n text: this.staged.get('apiKey')?.text ?? '',\n clear: false,\n overridden: false,\n invalid: false,\n },\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 dirty: plan.length > 0,\n invalid: plan.some((item) => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n }\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 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.failed) return\n this.staged.clear()\n this.failed = false\n this.publish()\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 if (plan.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 for (const run of runs) landed = (await run()) && landed\n this.saving = false\n this.failed = !landed\n if (landed) this.staged.clear()\n this.publish()\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 }\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 }\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): Promise<boolean> {\n await this.scope.set(field, value)\n return this.userLayer()?.[field] === value\n }\n\n /** Write the staged key, then re-read whether the Host now holds one. */\n private async writeKey(value: string): Promise<boolean> {\n try {\n const response = await this.api.credentials.set({ ref: this.credential.ref, value })\n if (!response.result.ok) return false\n } catch {\n return false\n }\n await this.readCredential()\n return this.credential.configured\n }\n\n /** Ask the credentials domain about the reference this page writes. */\n private async readCredential(): Promise<void> {\n const ref = this.credential.ref\n let response: Awaited<ReturnType<SettingsPageApi['credentials']['describe']>>\n try {\n response = await this.api.credentials.describe({ refs: [ref] })\n } catch {\n return\n }\n if (!response.result.ok) return\n const view = response.result.value.credentials[ref]\n const next = {\n ref,\n configured: view?.configured ?? false,\n writable: view?.writable ?? true,\n }\n if (next.configured === this.credential.configured && next.writable === this.credential.writable) return\n this.credential = next\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 * 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. Styles are injected once by the client entry\n * (see src/client/index.ts) and class-prefixed `cc-` to stay local.\n */\n\nimport { Button } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { Translate } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SettingsCommandCodeKey } from './locales.ts'\nimport type { SettingsPageState, StagedField } from './settings.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 edit(field: string, text: string): void\n resetField(field: string): void\n save(): void\n discard(): void\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}>{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 ? t('invalidNumber') : hint}\n </p>\n </div>\n )\n}\n\n/** The API-key control: write-only, reports configured state, never echoes the key. */\nfunction SecretKeyField({\n label,\n hint,\n state,\n disabled,\n configured,\n configuredLabel,\n unconfiguredLabel,\n onEdit,\n}: {\n label: string\n hint: string\n state: StagedField\n disabled: boolean\n configured: boolean\n configuredLabel: string\n unconfiguredLabel: string\n onEdit(text: string): void\n}) {\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 </span>\n </div>\n <input\n id=\"cc-api-key\"\n className=\"cc-input\"\n type=\"password\"\n autoComplete=\"off\"\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/** The settings page body: connection facts for the Command Code provider. */\nexport function CommandCodeSettingsPage(props: CommandCodeSettingsProps) {\n const { t } = props\n const state = props.useCommandCodeSettings((snapshot) => snapshot)\n const disabled = !state.writable\n const keyLocked = !state.apiKeyWritable\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 <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}\n configured={state.apiKeyConfigured}\n configuredLabel={t('apiKeySet')}\n unconfiguredLabel={t('apiKeyUnset')}\n onEdit={(text) => props.edit('apiKey', text)}\n />\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) => props.edit('apiBase', text)}\n onReset={() => props.resetField('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) => props.edit('workingDir', text)}\n onReset={() => props.resetField('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) => props.edit('requestTimeoutMs', text)}\n onReset={() => props.resetField('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) => props.edit('streamIdleTimeoutMs', text)}\n onReset={() => props.resetField('streamIdleTimeoutMs')}\n t={t}\n />\n </div>\n <div className=\"cc-footer\">\n {state.failed ? <p className=\"cc-failed\" role=\"status\">{t('saveFailed')}</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 </section>\n )\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 | 'overridden'\n | 'reset'\n | 'invalidNumber'\n | 'readOnly'\n | 'unsaved'\n | 'save'\n | 'saving'\n | 'saveFailed'\n | 'discard'\n | 'cancel'\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: '生成流停滞多久视为断连;默认 120000。',\n overridden: '已覆盖',\n reset: '重置',\n invalidNumber: '无效数字',\n readOnly: '当前配置为只读。',\n unsaved: '未保存',\n save: '保存',\n saving: '保存中',\n saveFailed: '保存失败,请重试。',\n discard: '放弃',\n cancel: '取消',\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 120000.',\n overridden: 'Overridden',\n reset: 'Reset',\n invalidNumber: 'Invalid number',\n readOnly: 'Settings are read-only.',\n unsaved: 'Unsaved',\n save: 'Save',\n saving: 'Saving',\n saveFailed: 'Save failed, please retry.',\n discard: 'Discard',\n cancel: 'Cancel',\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) and the\n * connection facts through the `llm-commandcode` settings namespace, so a\n * saved key or endpoint reaches the very next request.\n *\n * 2. The friendly-error wrapper for the harness's image-session gate — see\n * `./sessions.ts`. The wrapper is deliberately narrow: only the\n * `model-unavailable` code is rewritten, only when the message matches the\n * image-session gate, and only the message text changes.\n *\n * The wire types are spelled structurally in `./sessions.ts` (not imported\n * from `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag\n * an extra peer dependency into the package; the shapes are stable and the\n * client build inlines them anyway.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport { createSnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'\n// Type-only imports that pull in the client-service augmentations\n// (`slots`/`remote`/`locale` on Context) and the `settings.section` SlotMap\n// entry (`settingsScope` arrives 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-settings/client'\nimport { installFriendlyImageError } from './sessions.ts'\nimport { CommandCodeSettingsController, COMMANDCODE_NS, type SettingsPageState } from './settings.ts'\nimport { CommandCodeSettingsPage } from './section.tsx'\nimport { zh, en } from './locales.ts'\n\nexport { isImageSessionRejection, withFriendlyImageError } from './sessions.ts'\nimport type { ConnectionLike } from './sessions.ts'\n\n/** CSS for the settings page, injected once (harness bundle convention). */\nconst 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.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.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.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}\n`\n\n/** Inject the page stylesheet once (idempotent per tag). */\nfunction injectPageCss(): void {\n if (typeof document === 'undefined') return\n const id = '@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css'\n if (document.querySelector(`style[data-plugin-css=\"${id}\"]`) !== null) return\n const tag = document.createElement('style')\n tag.dataset.plugin = '@mars-sea/dsh-commandcode-provider'\n tag.dataset.pluginCss = id\n tag.textContent = PAGE_CSS\n document.head.appendChild(tag)\n}\n\n/**\n * Client plugin body. Gates on the services the settings page needs\n * (`slots`, `locale`, `connection`, `remote`, `settingsScope`) plus the\n * `connection` used by the friendly-error wrapper — the same inject list the\n * harness's own settings-surface plugins declare.\n */\nexport function apply(ctx: Context): void {\n injectPageCss()\n\n // Friendly image-gate error wrapper (unchanged behaviour).\n const connection = ctx.get('connection') as ConnectionLike | undefined\n if (connection !== undefined) {\n installFriendlyImageError(connection)\n }\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 const api = ctx.get('connection').api\n const hostDescription = ctx.get('connection').hostDescription\n const scope = ctx.settingsScope.bind<Record<string, unknown>>({ namespace: COMMANDCODE_NS })\n const controller = new CommandCodeSettingsController(scope, { credentials: api.credentials }, hostDescription)\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 const injected = () => ({\n hooks: { commandCodeSettings: store },\n edit: (field: string, text: string) => controller.edit(field, text),\n resetField: (field: string) => controller.resetField(field),\n save: () => void controller.save(),\n discard: () => controller.discard(),\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\nexport const inject: readonly string[] = [\n 'slots',\n 'locale',\n 'connection',\n 'remote',\n 'settingsScope',\n]\n"],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -23,18 +23,17 @@ declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
|
|
|
23
23
|
*/
|
|
24
24
|
declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
|
|
25
25
|
/**
|
|
26
|
-
* Models
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* source for selectable effort levels.
|
|
26
|
+
* Models the official CLI's model table (`ZA` in command-code@1.26.0) marks
|
|
27
|
+
* `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
|
|
28
|
+
* think automatically, with Command Code driving the depth. This is the
|
|
29
|
+
* authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
|
|
30
|
+
* mirrors the CLI's effort map exactly) stays the sole source for selectable
|
|
31
|
+
* effort levels, and this snapshot is not surfaced in the picker's compact
|
|
32
|
+
* description — it exists for programmatic consumers.
|
|
34
33
|
*
|
|
35
|
-
* Source:
|
|
36
|
-
*
|
|
37
|
-
* dsh-commandcode-upstream skill.
|
|
34
|
+
* Source: the command-code@1.26.0 bundled model table (dist/cli.mjs, the `ZA`
|
|
35
|
+
* object), cross-checked with https://commandcode.ai/docs/reference/cli/models.
|
|
36
|
+
* Keep in sync via the dsh-commandcode-upstream skill.
|
|
38
37
|
*/
|
|
39
38
|
declare const KNOWN_THINKING_MODELS: ReadonlySet<string>;
|
|
40
39
|
/**
|
package/lib/index.js
CHANGED
|
@@ -35,11 +35,6 @@ const KNOWN_EFFORTS = {
|
|
|
35
35
|
"medium",
|
|
36
36
|
"xhigh"
|
|
37
37
|
],
|
|
38
|
-
"MiniMaxAI/MiniMax-M2.5": [
|
|
39
|
-
"low",
|
|
40
|
-
"medium",
|
|
41
|
-
"xhigh"
|
|
42
|
-
],
|
|
43
38
|
"claude-fable-5": [
|
|
44
39
|
"low",
|
|
45
40
|
"medium",
|
|
@@ -47,13 +42,6 @@ const KNOWN_EFFORTS = {
|
|
|
47
42
|
"xhigh",
|
|
48
43
|
"max"
|
|
49
44
|
],
|
|
50
|
-
"claude-haiku-4-5-20251001": [
|
|
51
|
-
"low",
|
|
52
|
-
"medium",
|
|
53
|
-
"high",
|
|
54
|
-
"xhigh",
|
|
55
|
-
"max"
|
|
56
|
-
],
|
|
57
45
|
"claude-opus-4-7": [
|
|
58
46
|
"low",
|
|
59
47
|
"medium",
|
|
@@ -160,37 +148,7 @@ const KNOWN_EFFORTS = {
|
|
|
160
148
|
"xhigh",
|
|
161
149
|
"max"
|
|
162
150
|
],
|
|
163
|
-
"meta/muse-spark-1.2-contributor": [
|
|
164
|
-
"low",
|
|
165
|
-
"medium",
|
|
166
|
-
"high"
|
|
167
|
-
],
|
|
168
|
-
"moonshotai/Kimi-K2.5": [
|
|
169
|
-
"low",
|
|
170
|
-
"high",
|
|
171
|
-
"max"
|
|
172
|
-
],
|
|
173
|
-
"moonshotai/Kimi-K2.6": [
|
|
174
|
-
"low",
|
|
175
|
-
"high",
|
|
176
|
-
"max"
|
|
177
|
-
],
|
|
178
|
-
"moonshotai/Kimi-K2.7-Code-Highspeed": [
|
|
179
|
-
"low",
|
|
180
|
-
"high",
|
|
181
|
-
"max"
|
|
182
|
-
],
|
|
183
151
|
"sakana/fugu-ultra": ["high", "xhigh"],
|
|
184
|
-
"tencent/Hy3": [
|
|
185
|
-
"low",
|
|
186
|
-
"medium",
|
|
187
|
-
"high"
|
|
188
|
-
],
|
|
189
|
-
"tencent/hy3-paid": [
|
|
190
|
-
"low",
|
|
191
|
-
"medium",
|
|
192
|
-
"high"
|
|
193
|
-
],
|
|
194
152
|
"xai/grok-4.5": [
|
|
195
153
|
"low",
|
|
196
154
|
"medium",
|
|
@@ -202,16 +160,6 @@ const KNOWN_EFFORTS = {
|
|
|
202
160
|
"high",
|
|
203
161
|
"xhigh"
|
|
204
162
|
],
|
|
205
|
-
"xiaomi/mimo-v2.5": [
|
|
206
|
-
"low",
|
|
207
|
-
"medium",
|
|
208
|
-
"xhigh"
|
|
209
|
-
],
|
|
210
|
-
"xiaomi/mimo-v2.5-pro": [
|
|
211
|
-
"low",
|
|
212
|
-
"medium",
|
|
213
|
-
"xhigh"
|
|
214
|
-
],
|
|
215
163
|
"zai-org/GLM-5.2": ["high", "max"],
|
|
216
164
|
"zai-org/GLM-5.3": [
|
|
217
165
|
"low",
|
|
@@ -275,18 +223,17 @@ const KNOWN_IMAGE_MODELS = /* @__PURE__ */ new Set([
|
|
|
275
223
|
"xiaomi/mimo-v2.5"
|
|
276
224
|
]);
|
|
277
225
|
/**
|
|
278
|
-
* Models
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* source for selectable effort levels.
|
|
226
|
+
* Models the official CLI's model table (`ZA` in command-code@1.26.0) marks
|
|
227
|
+
* `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
|
|
228
|
+
* think automatically, with Command Code driving the depth. This is the
|
|
229
|
+
* authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
|
|
230
|
+
* mirrors the CLI's effort map exactly) stays the sole source for selectable
|
|
231
|
+
* effort levels, and this snapshot is not surfaced in the picker's compact
|
|
232
|
+
* description — it exists for programmatic consumers.
|
|
286
233
|
*
|
|
287
|
-
* Source:
|
|
288
|
-
*
|
|
289
|
-
* dsh-commandcode-upstream skill.
|
|
234
|
+
* Source: the command-code@1.26.0 bundled model table (dist/cli.mjs, the `ZA`
|
|
235
|
+
* object), cross-checked with https://commandcode.ai/docs/reference/cli/models.
|
|
236
|
+
* Keep in sync via the dsh-commandcode-upstream skill.
|
|
290
237
|
*/
|
|
291
238
|
const KNOWN_THINKING_MODELS = /* @__PURE__ */ new Set([
|
|
292
239
|
"MiniMaxAI/MiniMax-M3",
|
|
@@ -297,17 +244,17 @@ const KNOWN_THINKING_MODELS = /* @__PURE__ */ new Set([
|
|
|
297
244
|
"Qwen/Qwen3.7-Plus",
|
|
298
245
|
"moonshotai/Kimi-K3",
|
|
299
246
|
"moonshotai/Kimi-K2.7-Code",
|
|
247
|
+
"moonshotai/Kimi-K2.7-Code-Highspeed",
|
|
300
248
|
"stepfun/Step-3.5-Flash",
|
|
301
249
|
"stepfun/Step-3.7-Flash",
|
|
302
|
-
"
|
|
303
|
-
"zai-org/GLM-5.1",
|
|
304
|
-
"zai-org/GLM-5.2-Fast",
|
|
250
|
+
"tencent/hy3-paid",
|
|
305
251
|
"nvidia/nemotron-3-ultra-550b-a55b",
|
|
306
252
|
"thinkingmachines/inkling",
|
|
307
253
|
"thinkingmachines/inkling-small",
|
|
308
254
|
"poolside/laguna-s-2.1-free",
|
|
309
255
|
"meta/muse-spark-1.1",
|
|
310
|
-
"meta/muse-spark-1.2"
|
|
256
|
+
"meta/muse-spark-1.2",
|
|
257
|
+
"meta/muse-spark-1.2-contributor"
|
|
311
258
|
]);
|
|
312
259
|
/**
|
|
313
260
|
* The minimum subscription plan a model is included in, per the official plan
|
|
@@ -413,7 +360,10 @@ function compareByPlan(a, b) {
|
|
|
413
360
|
return a.id.localeCompare(b.id);
|
|
414
361
|
}
|
|
415
362
|
const KNOWN_DEALS = {
|
|
416
|
-
"deepseek/deepseek-v4-pro": {
|
|
363
|
+
"deepseek/deepseek-v4-pro": {
|
|
364
|
+
label: "75% off",
|
|
365
|
+
expiresAt: "2026-08-16T15:59:59.999Z"
|
|
366
|
+
},
|
|
417
367
|
"google/gemini-3.7-flash": {
|
|
418
368
|
label: "50% off",
|
|
419
369
|
expiresAt: "2026-12-31T23:59:59Z"
|