@mars-sea/dsh-commandcode-provider 0.1.0 → 0.1.1
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 +12 -0
- package/README.md +2 -0
- package/README.zh-CN.md +130 -0
- package/lib/index.d.ts +13 -1
- package/lib/index.js +24 -4
- package/lib/index.js.map +1 -1
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.1.1] - 2026-08-14
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Core unit tests (`tests/adapter.test.ts`, node:test, zero extra runtime deps): message conversion, SSE/JSONL stream parsing, catalog parsing, HTTP-error mapping, reasoning-effort exposure. `npm test`; CI runs it.
|
|
12
|
+
- `fetchImpl` injection on the adapter for testability (defaults to the global `fetch`).
|
|
13
|
+
- `providerRetryPolicy()`: declares the default retry policy (retries `RATE_LIMIT`/`SERVER`/`TIMEOUT`/`TRANSPORT`/`EMPTY_RESPONSE`), so metered Command Code 429s and transient 5xx are retried at the agent-step boundary by dsh-llm-retry.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- HTTP error mapping: a 401 now throws `INVALID_CREDENTIAL` (config problem, not retryable) instead of `PROVIDER_HTTP_ERROR`; 403/429 responses are parsed for the machine-readable `error.code` and included in the message.
|
|
18
|
+
|
|
7
19
|
## [0.1.0] - 2026-08-14
|
|
8
20
|
|
|
9
21
|
### Added
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# dsh-commandcode-provider
|
|
2
2
|
|
|
3
|
+
**English** | [简体中文](./README.zh-CN.md)
|
|
4
|
+
|
|
3
5
|
[](https://github.com/Mars-Sea/dsh-commandcode-provider/actions/workflows/ci.yml)
|
|
4
6
|
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
[](https://www.npmjs.com/package/@mars-sea/dsh-commandcode-provider)
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# dsh-commandcode-provider
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/Mars-Sea/dsh-commandcode-provider/actions/workflows/ci.yml)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.npmjs.com/package/@mars-sea/dsh-commandcode-provider)
|
|
8
|
+
|
|
9
|
+
非官方 [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/) 的 LLM provider 插件,用于 **Command Code**,移植自 [pi-commandcode-provider](https://github.com/patlux/pi-commandcode-provider)(MIT 协议)。它注册了一个 `commandcode` 模型 provider,将请求转换为 Command Code 的 Provider API(`POST /alpha/generate`,由 pi 插件逆向工程,对应 `command-code@1.15.1`)。
|
|
10
|
+
|
|
11
|
+
> 这是一个社区集成。你需要自己的 Command Code 账号、API key 或订阅,并遵守 Command Code 的服务条款。本项目与 Command Code, Inc. 无关。
|
|
12
|
+
|
|
13
|
+
## 功能一览
|
|
14
|
+
|
|
15
|
+
- **插件包**:可通过 `dsh plugin add` 安装到任意 dsh 配置(npm 包,带 `dsh.bundle` 层)。
|
|
16
|
+
- **`commandcode` provider 路由**:注册在 `llm` 服务上,可在模型选择器中选择,并带 **实时模型目录**(从 `GET {apiBase}/provider/v1/models` 拉取,缓存于 `~/.commandcode/models-cache.json`)。
|
|
17
|
+
- **Models 页面卡片**("Command Code")带 API key 输入框——凭据通过 dsh 凭据服务存储,与 DeepSeek 卡片一致。
|
|
18
|
+
- **API key 解析顺序**:`config.apiKey` → 凭据引用 `apiKeyEnv`(Web Models 页面写入,默认 `COMMANDCODE_API_KEY`)→ 启动环境变量 → 官方 Command Code CLI 认证文件(`~/.commandcode/auth.json`,由 `command-code login` 写入)。故意**不**扫描 pi/OMP 的认证文件。
|
|
19
|
+
- **推理强度(reasoning-effort)支持**:针对 Command Code 目录中标为推理模型的模型(如 `claude-opus-5`、`gpt-5.5`、`deepseek/deepseek-v4-pro` 等),通过 `KNOWN_EFFORTS` 实现,与 pi 插件对 `command-code@1.15.1` 的快照一致。
|
|
20
|
+
|
|
21
|
+
## 获取 API key
|
|
22
|
+
|
|
23
|
+
Command Code 的 API key 永不过期。最简单的途径是官方 CLI(Node.js 22+):
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm i -g command-code@latest
|
|
27
|
+
cmd login # macOS/Linux;Windows 原生版:cmdc login
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`cmd login` 会打开浏览器进行认证;成功后 key 写入 `~/.commandcode/auth.json`——本插件会自动读取(最后兜底)。也可以直接在浏览器创建 API key([Command Code Studio](https://commandcode.ai/studio/auth/cli))并粘贴到 Models 页面的卡片中,或者 `export COMMANDCODE_API_KEY="user_..."`。
|
|
31
|
+
|
|
32
|
+
## 安装
|
|
33
|
+
|
|
34
|
+
### 从 GitHub 安装(推荐)
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
dsh plugin --profile web add github:Mars-Sea/dsh-commandcode-provider#<sha>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
git 安装会拉取**源码**,因此包的 `prepare` 脚本会在安装后构建 `lib/`。pnpm ≥10 默认会阻止该脚本——先运行 `add`,然后把 pnpm 打印的**确切包 key** 复制到 `~/.dsh/profiles/web/pnpm-workspace.yaml`:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
allowBuilds:
|
|
44
|
+
'dsh-commandcode-provider@github:Mars-Sea/dsh-commandcode-provider#<sha>': true
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
然后重新运行 `add`。只允许信任其源码的包(并固定 commit)。
|
|
48
|
+
|
|
49
|
+
### 从 npm 安装
|
|
50
|
+
|
|
51
|
+
发布为 **`@mars-sea/dsh-commandcode-provider`**(npm 上裸名 `dsh-commandcode-provider` 已被无关包占用):
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
dsh plugin --profile web add @mars-sea/dsh-commandcode-provider
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 从本地检出安装
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
npm install
|
|
61
|
+
npm run build # git/压缩包安装通过 `prepare` 自动执行
|
|
62
|
+
dsh plugin --profile web add /path/to/dsh-commandcode-provider
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
本地路径安装会按原样链接检出目录,因此修改 `src/` 后需重新运行 `npm run build` 并重启应用。
|
|
66
|
+
|
|
67
|
+
### 安装做了什么
|
|
68
|
+
|
|
69
|
+
`dsh plugin add` 会将包链接到配置目录,把 `dsh-commandcode-provider` 追加到配置的 `dsh.profile.bundles`,并激活 `cordis.patch.yml` 层,其中插入:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
- insert:
|
|
73
|
+
- id: llm-commandcode
|
|
74
|
+
name: dsh-commandcode-provider
|
|
75
|
+
config:
|
|
76
|
+
apiKeyEnv: COMMANDCODE_API_KEY
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
验证合成后的层,然后(重新)启动 Web 应用:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
dsh --profile web --dump-config # 会显示 "# == dsh-commandcode-provider" 层
|
|
83
|
+
dsh web # 或重启你正在运行的实例
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 验证是否生效
|
|
87
|
+
|
|
88
|
+
重启后,在 Web UI 中:**设置 → Models** 会显示 **Command Code** 卡片;模型选择器会在 **commandcode** 下列出实时目录(撰写本文时有 54 个模型)。发送一条消息,选择你套餐中包含的模型——默认的 `deepseek/deepseek-v4-flash` 适用于入门级套餐;开放权重模型(DeepSeek/Qwen/Kimi/MiniMax)通常都可用,而前沿模型(Claude/GPT/Gemini/Grok)可能需要 Pro/Max 套餐或按需计费(见 FAQ)。
|
|
89
|
+
|
|
90
|
+
## 配置
|
|
91
|
+
|
|
92
|
+
Command Code 卡片接收你的 API key(存储在 `$DSH_HOME/.credentials.yaml`;没有 key 也可以浏览模型目录)。高级选项位于 `$DSH_HOME/settings.yaml` 的 `llm-commandcode` 一节(按请求覆盖 bundle 默认值,无需重启):
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
llm-commandcode:
|
|
96
|
+
apiKeyEnv: COMMANDCODE_API_KEY # 每次请求解析的凭据引用
|
|
97
|
+
apiBase: https://api.commandcode.ai
|
|
98
|
+
workingDir: /path/to/project # 上报给 API(项目 slug、配置块)
|
|
99
|
+
modelsCachePath: ~/.commandcode/models-cache.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
组合入口配置(`cordis.patch.yml` / 你 profile 的 `cordis.patch.yml`)接受相同的键;那里的字面量 `apiKey` 优先于凭据引用。
|
|
103
|
+
|
|
104
|
+
## 故障排查
|
|
105
|
+
|
|
106
|
+
- **`MODEL_NOT_IN_PLAN` (403)** ——所选模型不在你的 Command Code 套餐内。选择一个开放权重模型(如 `deepseek/deepseek-v4-flash`)或升级套餐。错误信息会指明模型并附官方文档链接。
|
|
107
|
+
- **`MISSING_CREDENTIAL`** ——任何地方都没有 key。通过 Models 页面卡片存储一个、`export COMMANDCODE_API_KEY`、设置 `config.apiKey`,或运行 `command-code login`。没有 key 时路由保持注册、目录保持可浏览。
|
|
108
|
+
- **Models 页面卡片显示"未配置"但请求可用** ——key 来自 `~/.commandcode/auth.json`(`cmd login` 兜底),而不是 dsh 凭据存储。把它粘贴到卡片一次即可让卡片显示为已配置;两者可以共存。
|
|
109
|
+
- **推理模型在短请求下不返回可见文本** ——推理模型(如 `deepseek/deepseek-v4-*`)会先消耗输出 token 进行推理;`maxTokens` 较小时可能在出现可见文本前就用完。这属于正常现象。
|
|
110
|
+
- **git 安装时 `dsh plugin add` 报 `allowBuilds` 错误** ——把 pnpm 打印的确切包 key(含 commit hash)复制到 `pnpm-workspace.yaml` 并重新运行(见[从 GitHub 安装(推荐)](#从-github-安装推荐))。
|
|
111
|
+
|
|
112
|
+
## 注意事项与限制
|
|
113
|
+
|
|
114
|
+
- **目前仅支持文本**:图片输入会抛出 `UNSUPPORTED_CONTENT`(接入附件服务以解析图片字节是后续工作)。有意不声明 pi 插件的 `MODEL_INPUT_MODALITIES` 表。
|
|
115
|
+
- **不支持 `stop` 序列**:线上格式没有 stop 字段;携带它的请求会抛出 `UNSUPPORTED_OPTION`。
|
|
116
|
+
- 推理块**不会**重放到后续轮次(与官方 CLI 一致:先前的私有推理不得泄漏)。
|
|
117
|
+
- 只有带配对工具结果的工具调用会被重放到对话中。
|
|
118
|
+
- 模型目录端点是公开的;对 `/alpha/generate` 的请求需要上述 key。
|
|
119
|
+
|
|
120
|
+
## 开发
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
npm install
|
|
124
|
+
npm run typecheck # tsc --noEmit
|
|
125
|
+
npm run build # tsdown -> lib/
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 许可证
|
|
129
|
+
|
|
130
|
+
MIT —— 见 [LICENSE](./LICENSE)。部分内容移植自 [pi-commandcode-provider](https://github.com/patlux/pi-commandcode-provider)(MIT)。
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
|
-
import { GenerateOptions, LlmAdapter, LlmModelInfo, LlmResolvedModelInfo, StreamChunk } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
import { GenerateOptions, LlmAdapter, LlmModelInfo, LlmResolvedModelInfo, ResolvedRetryPolicy, StreamChunk } from "@deepseek-ai/dsh-llm";
|
|
3
3
|
import { CredentialRef } from "@deepseek-ai/dsh-credentials";
|
|
4
4
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
//#region src/adapter.d.ts
|
|
@@ -26,11 +26,23 @@ interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = Comman
|
|
|
26
26
|
options: () => C;
|
|
27
27
|
/** Resolve a usable API key for the given connection facts, or throw `MISSING_CREDENTIAL`. */
|
|
28
28
|
resolveApiKey: (connection: C) => Promise<string>;
|
|
29
|
+
/** HTTP transport override (tests); defaults to the global `fetch`. */
|
|
30
|
+
fetchImpl?: typeof fetch;
|
|
29
31
|
}
|
|
30
32
|
declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {
|
|
31
33
|
private readonly deps;
|
|
32
34
|
private catalog;
|
|
35
|
+
private readonly fetchImpl;
|
|
33
36
|
constructor(deps: CommandCodeAdapterDeps<C>);
|
|
37
|
+
/**
|
|
38
|
+
* Command Code is a metered subscription API: 429 (rate limit) and 5xx
|
|
39
|
+
* (transient server errors) are worth retrying at the agent-step boundary,
|
|
40
|
+
* which is where dsh-llm-retry executes the policy returned here. The
|
|
41
|
+
* default policy already retries `RATE_LIMIT` and `SERVER`; declaring it
|
|
42
|
+
* explicitly documents the intent and gives the plugin entry a stable hook
|
|
43
|
+
* to override (e.g. a stricter cap for a metered plan).
|
|
44
|
+
*/
|
|
45
|
+
providerRetryPolicy(_provider: string): ResolvedRetryPolicy;
|
|
34
46
|
/** Refresh the catalog (live fetch, cache fallback) and return it. */
|
|
35
47
|
private loadCatalog;
|
|
36
48
|
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
|
-
import { CallId, LlmAdapter, LlmError, ReasoningEffortId, assertUsableApiKey, attributionHeaders } from "@deepseek-ai/dsh-llm";
|
|
4
|
+
import { CallId, LlmAdapter, LlmError, ReasoningEffortId, assertUsableApiKey, attributionHeaders, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
5
5
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
6
6
|
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
7
7
|
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
@@ -328,15 +328,28 @@ function messagesToCC(messages) {
|
|
|
328
328
|
var CommandCodeAdapter = class extends LlmAdapter {
|
|
329
329
|
deps;
|
|
330
330
|
catalog = [];
|
|
331
|
+
fetchImpl;
|
|
331
332
|
constructor(deps) {
|
|
332
333
|
super();
|
|
333
334
|
this.deps = deps;
|
|
335
|
+
this.fetchImpl = deps.fetchImpl ?? fetch;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Command Code is a metered subscription API: 429 (rate limit) and 5xx
|
|
339
|
+
* (transient server errors) are worth retrying at the agent-step boundary,
|
|
340
|
+
* which is where dsh-llm-retry executes the policy returned here. The
|
|
341
|
+
* default policy already retries `RATE_LIMIT` and `SERVER`; declaring it
|
|
342
|
+
* explicitly documents the intent and gives the plugin entry a stable hook
|
|
343
|
+
* to override (e.g. a stricter cap for a metered plan).
|
|
344
|
+
*/
|
|
345
|
+
providerRetryPolicy(_provider) {
|
|
346
|
+
return resolveRetryPolicy(void 0, "llm-commandcode: retryPolicy");
|
|
334
347
|
}
|
|
335
348
|
/** Refresh the catalog (live fetch, cache fallback) and return it. */
|
|
336
349
|
async loadCatalog(signal) {
|
|
337
350
|
const { apiBase, modelsCachePath } = this.deps.options();
|
|
338
351
|
try {
|
|
339
|
-
const response = await
|
|
352
|
+
const response = await this.fetchImpl(`${apiBase}/provider/v1/models`, {
|
|
340
353
|
headers: {
|
|
341
354
|
accept: "application/json",
|
|
342
355
|
...attributionHeaders()
|
|
@@ -421,7 +434,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
421
434
|
},
|
|
422
435
|
threadId: randomUUID()
|
|
423
436
|
};
|
|
424
|
-
const response = await
|
|
437
|
+
const response = await this.fetchImpl(`${connection.apiBase}/alpha/generate`, {
|
|
425
438
|
method: "POST",
|
|
426
439
|
headers: {
|
|
427
440
|
"Content-Type": "application/json",
|
|
@@ -438,7 +451,14 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
438
451
|
});
|
|
439
452
|
if (!response.ok) {
|
|
440
453
|
const errText = await response.text().catch(() => "");
|
|
441
|
-
|
|
454
|
+
let providerCode;
|
|
455
|
+
try {
|
|
456
|
+
const parsed = JSON.parse(errText);
|
|
457
|
+
if (isRecord(parsed) && isRecord(parsed.error)) providerCode = stringValue(parsed.error.code);
|
|
458
|
+
} catch {}
|
|
459
|
+
const detail = providerCode ?? `HTTP ${response.status}`;
|
|
460
|
+
if (response.status === 401) throw new LlmError(`Command Code API error 401 (${detail}): the API key is missing or invalid — check the key stored for COMMANDCODE_API_KEY (Models page) or the auth file`, "INVALID_CREDENTIAL", { status: 401 });
|
|
461
|
+
throw new LlmError(`Command Code API error ${response.status}${detail === `HTTP ${response.status}` ? "" : ` (${detail})`}: ${errText.slice(0, 500)}`, response.status === 429 ? "RATE_LIMIT" : "PROVIDER_HTTP_ERROR", { status: response.status });
|
|
442
462
|
}
|
|
443
463
|
if (!response.body) throw new LlmError("Command Code API returned no response body", "PROVIDER_PROTOCOL_ERROR");
|
|
444
464
|
const reader = response.body.getReader();
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/adapter.ts","../src/index.ts"],"sourcesContent":["/**\n * DeepSeek Harness LLM adapter for the Command Code Provider API.\n *\n * Ported from pi-commandcode-provider@0.5.1 (MIT). This is an unofficial,\n * community-maintained integration; you need your own Command Code account\n * and API key or subscription, and Command Code's terms apply.\n *\n * Wire protocol (reverse-engineered by the pi plugin, command-code@1.15.1):\n * POST {apiBase}/alpha/generate\n * body: { config, memory, taste, skills, params: { model, messages, tools,\n * system, max_tokens, temperature, stream, reasoning_effort? }, threadId }\n * SSE-ish JSONL events: text-delta | reasoning-start/delta/end | tool-call\n * | tool-result | finish | error\n * Model catalog: GET {apiBase}/provider/v1/models -> { object: 'list', data: [...] }\n *\n * The adapter is deliberately free of cordis/schemastery: it receives a\n * per-request options thunk and an API-key resolver from the plugin entry\n * (src/index.ts), so a settings change reaches the very next request.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\n\nimport {\n attributionHeaders,\n CallId,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n type ContentBlock,\n type FinishReason,\n type GenerateOptions,\n type LlmModelInfo,\n type LlmResolvedModelInfo,\n type Message,\n type StreamChunk,\n type TokenUsage,\n} from '@deepseek-ai/dsh-llm'\n\n// ---------------------------------------------------------------------------\n// Static capability snapshot (from pi plugin, command-code@1.15.1 catalog).\n// The Provider API does not expose reasoning metadata; models omitted here\n// let Command Code choose their reasoning depth, matching the official CLI.\n// ---------------------------------------------------------------------------\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n 'Qwen/Qwen3.8-Max': ['low', 'medium', 'xhigh'],\n 'claude-fable-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-7': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-8': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-4-6': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'deepseek/deepseek-v4-flash': ['high', 'max'],\n 'deepseek/deepseek-v4-pro': ['high', 'max'],\n 'gpt-5.3-codex': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4-mini': ['low', 'medium', 'high'],\n 'gpt-5.5': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-sol': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-terra': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'google/gemini-3.1-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.6-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n 'xai/grok-4.5': ['low', 'medium', 'high'],\n 'zai-org/GLM-5.2': ['high', 'max'],\n}\n\nexport const COMMAND_CODE_CLI_VERSION = '1.15.1'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\nexport const DEFAULT_GENERATE_MAX_TOKENS = 64_000\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 65_536\nexport const MODELS_TIMEOUT_MS = 10_000\nconst MODEL_CACHE_VERSION = 1\n\n// ---------------------------------------------------------------------------\n// Small helpers (ported from converters.ts / models.ts)\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction recordOrEmpty(value: unknown): Record<string, unknown> {\n if (isRecord(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed: unknown = JSON.parse(value)\n if (isRecord(parsed)) return parsed\n } catch {\n // Some providers stream incomplete JSON argument fragments.\n }\n }\n return {}\n}\n\nexport function projectSlugFromPath(pathName: string): string {\n const slug = pathName\n .toLowerCase()\n .replace(/^[a-z]:/i, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug || 'project'\n}\n\nfunction parseStreamEventLine(line: string): unknown | undefined {\n let trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(':') || trimmed.startsWith('event:')) return undefined\n if (trimmed.startsWith('data:')) trimmed = trimmed.slice(5).trim()\n if (!trimmed || trimmed === '[DONE]') return undefined\n try {\n return JSON.parse(trimmed) as unknown\n } catch {\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential fallback from the official Command Code CLI auth file. Used as\n// the last fallback by the plugin entry, so a user who already logged in with\n// `command-code login` can reuse that credential. Only the official CLI's own\n// file is read — pi/OMP auth files are intentionally not scanned, so their\n// credentials and formats cannot surprise this adapter.\n// ---------------------------------------------------------------------------\n\n/** Extract the key from the CLI's nested credential records (`command-code`). */\nfunction apiKeyFromCredentialRecord(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined\n const type = stringValue(value.type)\n if (type === 'api') return stringValue(value.key)\n if (type === 'oauth') return stringValue(value.access)\n return stringValue(value.key) ?? stringValue(value.access)\n}\n\n/** Read a usable Command Code credential from the official CLI auth file. */\nexport function resolveAuthFileApiKey(): string | undefined {\n const authPath = join(homedir(), '.commandcode', 'auth.json')\n try {\n if (!existsSync(authPath)) return undefined\n const parsed: unknown = JSON.parse(readFileSync(authPath, 'utf-8'))\n if (!isRecord(parsed)) return undefined\n const direct = stringValue(parsed.apiKey) ?? stringValue(parsed.commandcode)\n if (direct) return direct\n const nested =\n apiKeyFromCredentialRecord(parsed.commandcode) ??\n apiKeyFromCredentialRecord(parsed['command-code'])\n return nested\n } catch {\n // Ignore malformed or unreadable auth file.\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog discovery with on-disk cache fallback (ported from models.ts)\n// ---------------------------------------------------------------------------\n\ninterface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n}\n\nfunction parseCatalogResponse(value: unknown): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) {\n throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n }\n const models: CommandCodeModel[] = []\n for (const entry of value.data) {\n if (!isRecord(entry)) continue\n const id = stringValue(entry.id)\n const name = stringValue(entry.name)\n const contextLength = numberValue(entry.context_length)\n if (!id || !name || !contextLength || contextLength <= 0) continue\n models.push({\n id,\n name,\n contextWindow: contextLength,\n maxTokens: Math.min(contextLength, DEFAULT_MAX_OUTPUT_TOKENS),\n })\n }\n if (models.length === 0) {\n throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n }\n return models\n}\n\nasync function readModelsCache(cachePath: string): Promise<CommandCodeModel[]> {\n const parsed: unknown = JSON.parse(await readFile(cachePath, 'utf-8'))\n if (!isRecord(parsed) || parsed.version !== MODEL_CACHE_VERSION || !Array.isArray(parsed.models)) {\n throw new Error(`Invalid model cache at ${cachePath}`)\n }\n return parsed.models as CommandCodeModel[]\n}\n\nasync function writeModelsCache(cachePath: string, models: CommandCodeModel[]): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true })\n const tmp = `${cachePath}.${process.pid}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, models }, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600,\n })\n await rename(tmp, cachePath)\n } finally {\n await rm(tmp, { force: true }).catch(() => undefined)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Message conversion: harness Message[] -> Command Code wire messages.\n// Reasoning blocks are intentionally NOT replayed (matches the pi plugin and\n// the official CLI: prior private reasoning must not leak into later turns).\n// Only tool calls with a paired tool result are replayed.\n// ---------------------------------------------------------------------------\n\nfunction pairedToolCallIds(messages: readonly Message[]): Set<string> {\n const callIds = new Set<string>()\n const resultIds = new Set<string>()\n for (const message of messages) {\n for (const block of message.content) {\n if (message.role === 'assistant' && block.type === 'tool-call') callIds.add(block.id)\n if (block.type === 'tool-result') resultIds.add(block.toolCallId)\n }\n }\n return new Set([...callIds].filter((id) => resultIds.has(id)))\n}\n\nfunction blockText(block: ContentBlock): string {\n return block.type === 'text' || block.type === 'reasoning' ? block.text : ''\n}\n\nfunction toolResultText(block: Extract<ContentBlock, { type: 'tool-result' }>): string {\n return block.content.map(blockText).filter(Boolean).join('\\n')\n}\n\nfunction hasImageContent(message: Message): boolean {\n const check = (blocks: readonly ContentBlock[]): boolean =>\n blocks.some(\n (b) => b.type === 'image' || (b.type === 'tool-result' && check(b.content)),\n )\n return check(message.content)\n}\n\nfunction messagesToCC(messages: readonly Message[]): unknown[] {\n const out: unknown[] = []\n const paired = pairedToolCallIds(messages)\n\n for (const message of messages) {\n if (message.role === 'system') continue // folded into params.system by the caller\n\n if (message.role === 'user' && message.source.kind !== 'tool') {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n // ImageBlock carries an attachment ref owned by the attachment\n // service; resolving it to bytes requires that service. Fail loudly\n // instead of silently dropping (adapter contract).\n throw new LlmError(\n 'Image input is not wired to the attachment service in this adapter yet',\n 'UNSUPPORTED_CONTENT',\n )\n }\n }\n out.push({ role: 'user', content: parts })\n continue\n }\n\n if (message.role === 'assistant') {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n } else if (block.type === 'tool-call' && paired.has(block.id)) {\n parts.push({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: recordOrEmpty(block.arguments),\n })\n }\n // reasoning blocks: skipped by design (see header comment)\n }\n if (parts.length > 0) out.push({ role: 'assistant', content: parts })\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (message.role === 'user' && message.source.kind === 'tool') {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n out.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: block.toolCallId,\n toolName: '',\n output: block.isError\n ? { type: 'error-text', value: toolResultText(block) }\n : { type: 'text', value: toolResultText(block) },\n },\n ],\n })\n }\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Adapter\n// ---------------------------------------------------------------------------\n\n/** Connection facts resolved fresh per request by the plugin entry. */\nexport interface CommandCodeConnectionOptions {\n /** API base; the Provider API lives under it (`/alpha/generate`, `/provider/v1/models`). */\n apiBase: string\n /** Working directory reported to the API (project slug, config block). */\n workingDir: string\n /** Model catalog cache path. */\n modelsCachePath: string\n}\n\n/** Everything the adapter needs beyond the request itself. */\nexport interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** Resolve the current connection facts (fresh per request, settings-aware). */\n options: () => C\n /** Resolve a usable API key for the given connection facts, or throw `MISSING_CREDENTIAL`. */\n resolveApiKey: (connection: C) => Promise<string>\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private catalog: CommandCodeModel[] = []\n\n constructor(private readonly deps: CommandCodeAdapterDeps<C>) {\n super()\n }\n\n /** Refresh the catalog (live fetch, cache fallback) and return it. */\n private async loadCatalog(signal?: AbortSignal): Promise<CommandCodeModel[]> {\n const { apiBase, modelsCachePath } = this.deps.options()\n try {\n const response = await fetch(`${apiBase}/provider/v1/models`, {\n headers: { accept: 'application/json', ...attributionHeaders() },\n signal: signal ?? AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) {\n throw new Error(`models endpoint returned ${response.status}`)\n }\n this.catalog = parseCatalogResponse(await response.json())\n await writeModelsCache(modelsCachePath, this.catalog).catch(() => undefined)\n } catch (error) {\n if (signal?.aborted) throw error\n // Fall back to the last successful catalog on disk.\n this.catalog = await readModelsCache(modelsCachePath).catch(() => this.catalog)\n }\n return this.catalog\n }\n\n override async listModels(provider: string): Promise<readonly LlmModelInfo[]> {\n const catalog = await this.loadCatalog()\n return catalog.map((model) => ({\n provider,\n id: model.id,\n name: `${model.name} (CC)`,\n inputModalities: ['text' as const],\n }))\n }\n\n override async resolveModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<LlmResolvedModelInfo> {\n const entry =\n this.catalog.find((m) => m.id === model) ??\n (await this.loadCatalog(signal)).find((m) => m.id === model)\n\n const efforts = KNOWN_EFFORTS[model]\n return {\n provider,\n id: model,\n name: entry ? `${entry.name} (CC)` : model,\n inputModalities: ['text' as const],\n ...(entry\n ? {\n context: { contextWindow: entry.contextWindow },\n defaultMaxTokens: Math.min(entry.maxTokens, DEFAULT_GENERATE_MAX_TOKENS),\n }\n : {}),\n // Omit `reasoning` entirely for models without known effort support:\n // the harness then treats the model as having no selectable efforts.\n ...(efforts\n ? {\n reasoning: {\n efforts: efforts.map((effort) => ({\n id: ReasoningEffortId(effort),\n name: effort,\n })),\n },\n }\n : {}),\n }\n }\n\n async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n if (options.stop?.length) {\n // The Command Code wire format has no documented stop field; refuse\n // loudly instead of silently dropping a request field.\n throw new LlmError('Command Code adapter does not support stop sequences', 'UNSUPPORTED_OPTION')\n }\n if (options.messages.some(hasImageContent)) {\n throw new LlmError(\n 'Image input is not wired to the attachment service in this adapter yet',\n 'UNSUPPORTED_CONTENT',\n )\n }\n\n const connection = this.deps.options()\n const apiKey = await this.deps.resolveApiKey(connection)\n const entry = this.catalog.find((m) => m.id === options.model)\n const modelMax = entry?.maxTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n const maxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n const reasoningEffort =\n effort && effort !== 'off' && supported?.includes(effort) ? effort : undefined\n\n const systemText = [\n options.system ?? '',\n ...options.messages\n .filter((m) => m.role === 'system')\n .map((m) => m.content.map(blockText).filter(Boolean).join('\\n')),\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n const body = {\n config: {\n workingDir: connection.workingDir,\n date: new Date().toISOString().split('T')[0],\n environment: `${process.platform}-${process.arch}, Node.js ${process.version}`,\n structure: [],\n isGitRepo: false,\n currentBranch: '',\n mainBranch: '',\n gitStatus: '',\n recentCommits: [],\n },\n memory: null,\n taste: null,\n skills: null,\n params: {\n model: options.model,\n messages: messagesToCC(options.messages),\n tools: (options.tools ?? []).map((tool) => ({\n type: 'function',\n name: tool.name,\n description: tool.description,\n input_schema: tool.parameters,\n })),\n system: systemText,\n max_tokens: maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n },\n threadId: randomUUID(),\n }\n\n const response = await fetch(`${connection.apiBase}/alpha/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n 'x-project-slug': projectSlugFromPath(connection.workingDir),\n 'x-taste-learning': 'true',\n 'x-co-flag': 'false',\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n ...(options.signal ? { signal: options.signal } : {}),\n })\n\n if (!response.ok) {\n const errText = await response.text().catch(() => '')\n throw new LlmError(\n `Command Code API error ${response.status}: ${errText.slice(0, 500)}`,\n response.status === 429 ? 'RATE_LIMIT' : 'PROVIDER_HTTP_ERROR',\n { status: response.status },\n )\n }\n if (!response.body) {\n throw new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR')\n }\n\n // --- SSE/JSONL event stream -> harness StreamChunk protocol ---\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n // Block assembly state: at most one text block and one reasoning block\n // are open at a time (same assumption as the pi plugin).\n let nextIndex = 0\n let textIndex = -1\n let textContent = ''\n let reasoningIndex = -1\n let reasoningContent = ''\n let sawContent = false\n\n const closeText = function* (): Generator<StreamChunk> {\n if (textIndex < 0) return\n yield {\n type: 'block-end',\n index: textIndex,\n block: { type: 'text', text: textContent },\n }\n textIndex = -1\n textContent = ''\n }\n const closeReasoning = function* (): Generator<StreamChunk> {\n if (reasoningIndex < 0) return\n yield {\n type: 'block-end',\n index: reasoningIndex,\n block: { type: 'reasoning', text: reasoningContent },\n }\n reasoningIndex = -1\n reasoningContent = ''\n }\n\n const handleEvent = (event: unknown): StreamChunk[] => {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n\n switch (event.type) {\n case 'text-delta': {\n chunks.push(...closeReasoning())\n if (textIndex < 0) {\n textIndex = nextIndex++\n chunks.push({ type: 'block-start', index: textIndex, blockType: 'text' })\n }\n const delta = stringValue(event.text) ?? ''\n textContent += delta\n sawContent = true\n chunks.push({ type: 'text-delta', index: textIndex, text: delta })\n break\n }\n case 'reasoning-delta': {\n chunks.push(...closeText())\n if (reasoningIndex < 0) {\n reasoningIndex = nextIndex++\n chunks.push({ type: 'block-start', index: reasoningIndex, blockType: 'reasoning' })\n }\n const delta = stringValue(event.text) ?? ''\n reasoningContent += delta\n chunks.push({ type: 'reasoning-delta', index: reasoningIndex, text: delta })\n break\n }\n case 'reasoning-start':\n chunks.push(...closeText())\n break\n case 'reasoning-end':\n chunks.push(...closeReasoning())\n break\n case 'tool-call': {\n chunks.push(...closeText(), ...closeReasoning())\n const id = stringValue(event.toolCallId) ?? randomUUID()\n const name = stringValue(event.toolName) ?? ''\n const args = JSON.stringify(recordOrEmpty(event.input ?? event.args ?? event.arguments))\n const index = nextIndex++\n sawContent = true\n chunks.push(\n { type: 'block-start', index, blockType: 'tool-call' },\n { type: 'tool-call-delta', index, id: CallId(id), name, argumentsDelta: args },\n {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: CallId(id), name, arguments: args },\n },\n )\n break\n }\n case 'finish': {\n chunks.push(...closeText(), ...closeReasoning())\n const usage = isRecord(event.totalUsage) ? event.totalUsage : undefined\n if (usage) {\n const details = isRecord(usage.inputTokenDetails) ? usage.inputTokenDetails : undefined\n const totalInput = numberValue(usage.inputTokens) ?? 0\n const cacheRead = numberValue(details?.cacheReadTokens) ?? 0\n const cacheWrite = numberValue(details?.cacheWriteTokens) ?? 0\n // Harness TokenUsage counts are disjoint: uncached input only.\n const tokenUsage: TokenUsage = {\n inputTokens:\n numberValue(details?.noCacheTokens) ?? Math.max(0, totalInput - cacheRead - cacheWrite),\n outputTokens: numberValue(usage.outputTokens) ?? 0,\n cacheReadTokens: cacheRead,\n cacheWriteTokens: cacheWrite,\n }\n chunks.push({ type: 'usage', usage: tokenUsage })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(event.finishReason) })\n break\n }\n case 'error': {\n const detail = isRecord(event.error)\n ? (stringValue(event.error.message) ?? JSON.stringify(event.error))\n : (stringValue(event.error) ?? stringValue(event.message) ?? 'Stream error')\n throw new LlmError(`Command Code stream error: ${detail}`, 'PROVIDER_STREAM_ERROR')\n }\n }\n return chunks\n }\n\n try {\n let finished = false\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n if (buffer.trim()) for (const chunk of handleEvent(parseStreamEventLine(buffer))) yield chunk\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n const chunks = handleEvent(parseStreamEventLine(line))\n for (const chunk of chunks) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n if (finished) break\n }\n if (!finished) {\n // Stream ended without a finish event: close open blocks and\n // terminate according to the adapter contract (usage, then finish).\n yield* closeText()\n yield* closeReasoning()\n if (!sawContent) {\n throw new LlmError('Command Code returned an empty response', 'EMPTY_RESPONSE')\n }\n yield { type: 'finish', reason: { kind: 'stop' } }\n }\n } finally {\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n}\n\nfunction mapFinishReason(reason: unknown): FinishReason {\n if (reason === 'tool-calls') return { kind: 'tool-calls' }\n if (\n reason === 'length' ||\n reason === 'max_tokens' ||\n reason === 'max-tokens' ||\n reason === 'max_output_tokens'\n ) {\n return { kind: 'max-tokens' }\n }\n return { kind: 'stop' }\n}\n","/**\n * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command\n * Code (unofficial; ported from pi-commandcode-provider@0.5.1).\n *\n * Registers the `commandcode` provider route on `ctx.llm` and declares it in\n * the configurable-provider directory, so the web Models page shows a\n * \"Command Code\" card with an API-key field and the model picker lists the\n * live Command Code model catalog. Connection facts resolve per request over\n * the optional `llm-commandcode` user-settings section and the credential\n * seam, so a changed key, endpoint, or cache path reaches the next request\n * without a restart.\n *\n * ```yaml\n * - id: llm-commandcode\n * name: dsh-commandcode-provider\n * config:\n * apiKeyEnv: COMMANDCODE_API_KEY\n * ```\n *\n * @module dsh-commandcode-provider\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport z from '@deepseek-ai/schemastery'\nimport { assertUsableApiKey, LlmError } from '@deepseek-ai/dsh-llm'\nimport { credentialRef, type CredentialRef } from '@deepseek-ai/dsh-credentials'\nimport { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'\nimport { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'\nimport { CommandCodeAdapter, DEFAULT_API_BASE, resolveAuthFileApiKey } from './adapter.ts'\nimport type { CommandCodeConnectionOptions } from './adapter.ts'\n\nexport {\n COMMAND_CODE_CLI_VERSION,\n DEFAULT_API_BASE,\n DEFAULT_GENERATE_MAX_TOKENS,\n DEFAULT_MAX_OUTPUT_TOKENS,\n CommandCodeAdapter,\n KNOWN_EFFORTS,\n projectSlugFromPath,\n resolveAuthFileApiKey,\n} from './adapter.ts'\nexport type { CommandCodeAdapterDeps, CommandCodeConnectionOptions } from './adapter.ts'\n\nexport const name = 'llm-commandcode'\nexport const inject = ['llm']\n\nconst NS = settingsNamespace('llm-commandcode')\nconst DEFAULT_API_KEY_ENV = 'COMMANDCODE_API_KEY'\n\n/** The single provider route this plugin owns. */\nexport const PROVIDER = 'commandcode'\n/** Default models cache path (mirrors the pi plugin's on-disk cache). */\nexport const DEFAULT_MODELS_CACHE_PATH = join(homedir(), '.commandcode', 'models-cache.json')\n\n/**\n * Plugin config, validated by the same-named schemastery schema and doubling\n * as the `llm-commandcode` settings-section shape. Every field is optional:\n * a missing API key resolves through {@link Config.apiKeyEnv} at each request\n * (the web Models page writes it), with the official Command Code CLI auth\n * file (`~/.commandcode/auth.json`) as the last fallback.\n */\nexport interface Config {\n /** Credential reference (environment-variable name) resolved per request; defaults to `COMMANDCODE_API_KEY`. */\n apiKeyEnv?: string\n /** Literal API key override (composition config only); takes precedence over `apiKeyEnv`. */\n apiKey?: string\n /** API base; defaults to the public Command Code Provider API. */\n apiBase?: string\n /** Working directory reported to the API; defaults to the process cwd. */\n workingDir?: string\n /** Model catalog cache path; defaults to `~/.commandcode/models-cache.json`. */\n modelsCachePath?: string\n}\n\nexport const Config: z<Config> = z.object({\n apiKeyEnv: z.string().role('credential-ref').default(DEFAULT_API_KEY_ENV),\n apiKey: z.string(),\n apiBase: z.string(),\n workingDir: z.string(),\n modelsCachePath: z.string(),\n})\n\n/** One resolution's complete request facts: connection plus credential reference. */\nexport interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {\n apiKeyEnv: CredentialRef\n}\n\n/**\n * The one explicit resolve step from raw config to validated connection\n * facts. Programmatic construction may bypass Schemastery normalization, so\n * every default is re-judged here — for the composition entry at load and for\n * each settings snapshot at its first use.\n */\nexport function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions {\n return {\n apiKeyEnv: credentialRef(config.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n apiBase: config.apiBase ?? DEFAULT_API_BASE,\n workingDir: config.workingDir ?? process.cwd(),\n modelsCachePath: config.modelsCachePath ?? DEFAULT_MODELS_CACHE_PATH,\n }\n}\n\nexport function apply(ctx: Context, config: Config): void {\n let current: () => Config = () => config\n let lastRaw: Config | undefined\n let lastGood: ResolvedCommandCodeOptions | undefined\n const options = (): ResolvedCommandCodeOptions => {\n const raw = current()\n if (raw === lastRaw && lastGood !== undefined) return lastGood\n const next = resolveAdapterOptions(raw)\n lastRaw = raw\n lastGood = next\n return next\n }\n options()\n\n const resolveApiKey = async (connection: ResolvedCommandCodeOptions): Promise<string> => {\n // 1. A literal key in composition config wins outright.\n const literal = current().apiKey\n if (literal) return assertUsableApiKey(literal, 'llm-commandcode', 'config.apiKey')\n // 2. The credential seam (web Models page) or the trusted environment.\n const ref = connection.apiKeyEnv\n const credentials = ctx.get('credentials')\n if (credentials !== undefined) {\n const hit = await credentials.resolve(ref)\n if (hit !== undefined) return assertUsableApiKey(hit.value, 'llm-commandcode', ref)\n } else {\n const ambient = launchEnvironmentOf(ctx).get(ref)\n if (ambient !== undefined && ambient.value.length > 0) {\n return assertUsableApiKey(ambient.value, 'llm-commandcode', ref)\n }\n }\n // 3. Last resort: reuse the official Command Code CLI login (~/.commandcode/auth.json).\n const authFileKey = resolveAuthFileApiKey()\n if (authFileKey) return assertUsableApiKey(authFileKey, 'llm-commandcode', '~/.commandcode/auth.json')\n throw new LlmError(\n `llm-commandcode: no API key for provider route \"${PROVIDER}\"; store ${ref} through the`\n + ' credentials service (the web Models page writes it), export it in the launching'\n + ' environment, set config.apiKey, or run `command-code login` to write'\n + ' ~/.commandcode/auth.json',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter = new CommandCodeAdapter({ options, resolveApiKey })\n // The Models page card: a configurable provider with a settings address.\n // settingsPath [] means the whole `llm-commandcode` section configures it.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n // The live route: this is what makes models requestable under `commandcode`.\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n installSettingsSection(ctx, NS, Config, config, {\n setSource: (source) => {\n current = source\n },\n // Everything the adapter reads is resolved per request, so a settings\n // change needs no registration-level action.\n onChange: () => {},\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/adapter.ts","../src/index.ts"],"sourcesContent":["/**\n * DeepSeek Harness LLM adapter for the Command Code Provider API.\n *\n * Ported from pi-commandcode-provider@0.5.1 (MIT). This is an unofficial,\n * community-maintained integration; you need your own Command Code account\n * and API key or subscription, and Command Code's terms apply.\n *\n * Wire protocol (reverse-engineered by the pi plugin, command-code@1.15.1):\n * POST {apiBase}/alpha/generate\n * body: { config, memory, taste, skills, params: { model, messages, tools,\n * system, max_tokens, temperature, stream, reasoning_effort? }, threadId }\n * SSE-ish JSONL events: text-delta | reasoning-start/delta/end | tool-call\n * | tool-result | finish | error\n * Model catalog: GET {apiBase}/provider/v1/models -> { object: 'list', data: [...] }\n *\n * The adapter is deliberately free of cordis/schemastery: it receives a\n * per-request options thunk and an API-key resolver from the plugin entry\n * (src/index.ts), so a settings change reaches the very next request.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\n\nimport {\n attributionHeaders,\n CallId,\n LlmAdapter,\n LlmError,\n ReasoningEffortId,\n resolveRetryPolicy,\n type ResolvedRetryPolicy,\n type ContentBlock,\n type FinishReason,\n type GenerateOptions,\n type LlmModelInfo,\n type LlmResolvedModelInfo,\n type Message,\n type StreamChunk,\n type TokenUsage,\n} from '@deepseek-ai/dsh-llm'\n\n// ---------------------------------------------------------------------------\n// Static capability snapshot (from pi plugin, command-code@1.15.1 catalog).\n// The Provider API does not expose reasoning metadata; models omitted here\n// let Command Code choose their reasoning depth, matching the official CLI.\n// ---------------------------------------------------------------------------\n\nexport const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>> = {\n 'Qwen/Qwen3.8-Max': ['low', 'medium', 'xhigh'],\n 'claude-fable-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-7': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-4-8': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-opus-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-4-6': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'claude-sonnet-5': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'deepseek/deepseek-v4-flash': ['high', 'max'],\n 'deepseek/deepseek-v4-pro': ['high', 'max'],\n 'gpt-5.3-codex': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.4-mini': ['low', 'medium', 'high'],\n 'gpt-5.5': ['low', 'medium', 'high', 'xhigh'],\n 'gpt-5.6-luna': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-sol': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'gpt-5.6-terra': ['low', 'medium', 'high', 'xhigh', 'max'],\n 'google/gemini-3.1-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash': ['low', 'medium', 'high'],\n 'google/gemini-3.5-flash-lite': ['low', 'medium', 'high'],\n 'google/gemini-3.6-flash': ['low', 'medium', 'high'],\n 'sakana/fugu-ultra': ['high', 'xhigh'],\n 'xai/grok-4.5': ['low', 'medium', 'high'],\n 'zai-org/GLM-5.2': ['high', 'max'],\n}\n\nexport const COMMAND_CODE_CLI_VERSION = '1.15.1'\nexport const DEFAULT_API_BASE = 'https://api.commandcode.ai'\nexport const DEFAULT_GENERATE_MAX_TOKENS = 64_000\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 65_536\nexport const MODELS_TIMEOUT_MS = 10_000\nconst MODEL_CACHE_VERSION = 1\n\n// ---------------------------------------------------------------------------\n// Small helpers (ported from converters.ts / models.ts)\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nfunction numberValue(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n\nfunction recordOrEmpty(value: unknown): Record<string, unknown> {\n if (isRecord(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed: unknown = JSON.parse(value)\n if (isRecord(parsed)) return parsed\n } catch {\n // Some providers stream incomplete JSON argument fragments.\n }\n }\n return {}\n}\n\nexport function projectSlugFromPath(pathName: string): string {\n const slug = pathName\n .toLowerCase()\n .replace(/^[a-z]:/i, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug || 'project'\n}\n\nfunction parseStreamEventLine(line: string): unknown | undefined {\n let trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(':') || trimmed.startsWith('event:')) return undefined\n if (trimmed.startsWith('data:')) trimmed = trimmed.slice(5).trim()\n if (!trimmed || trimmed === '[DONE]') return undefined\n try {\n return JSON.parse(trimmed) as unknown\n } catch {\n return undefined\n }\n}\n\n// ---------------------------------------------------------------------------\n// Credential fallback from the official Command Code CLI auth file. Used as\n// the last fallback by the plugin entry, so a user who already logged in with\n// `command-code login` can reuse that credential. Only the official CLI's own\n// file is read — pi/OMP auth files are intentionally not scanned, so their\n// credentials and formats cannot surprise this adapter.\n// ---------------------------------------------------------------------------\n\n/** Extract the key from the CLI's nested credential records (`command-code`). */\nfunction apiKeyFromCredentialRecord(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined\n const type = stringValue(value.type)\n if (type === 'api') return stringValue(value.key)\n if (type === 'oauth') return stringValue(value.access)\n return stringValue(value.key) ?? stringValue(value.access)\n}\n\n/** Read a usable Command Code credential from the official CLI auth file. */\nexport function resolveAuthFileApiKey(): string | undefined {\n const authPath = join(homedir(), '.commandcode', 'auth.json')\n try {\n if (!existsSync(authPath)) return undefined\n const parsed: unknown = JSON.parse(readFileSync(authPath, 'utf-8'))\n if (!isRecord(parsed)) return undefined\n const direct = stringValue(parsed.apiKey) ?? stringValue(parsed.commandcode)\n if (direct) return direct\n const nested =\n apiKeyFromCredentialRecord(parsed.commandcode) ??\n apiKeyFromCredentialRecord(parsed['command-code'])\n return nested\n } catch {\n // Ignore malformed or unreadable auth file.\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Model catalog discovery with on-disk cache fallback (ported from models.ts)\n// ---------------------------------------------------------------------------\n\ninterface CommandCodeModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n}\n\nfunction parseCatalogResponse(value: unknown): CommandCodeModel[] {\n if (!isRecord(value) || value.object !== 'list' || !Array.isArray(value.data)) {\n throw new LlmError('Unexpected Command Code models response shape', 'PROVIDER_PROTOCOL_ERROR')\n }\n const models: CommandCodeModel[] = []\n for (const entry of value.data) {\n if (!isRecord(entry)) continue\n const id = stringValue(entry.id)\n const name = stringValue(entry.name)\n const contextLength = numberValue(entry.context_length)\n if (!id || !name || !contextLength || contextLength <= 0) continue\n models.push({\n id,\n name,\n contextWindow: contextLength,\n maxTokens: Math.min(contextLength, DEFAULT_MAX_OUTPUT_TOKENS),\n })\n }\n if (models.length === 0) {\n throw new LlmError('Command Code returned an empty model catalog', 'PROVIDER_PROTOCOL_ERROR')\n }\n return models\n}\n\nasync function readModelsCache(cachePath: string): Promise<CommandCodeModel[]> {\n const parsed: unknown = JSON.parse(await readFile(cachePath, 'utf-8'))\n if (!isRecord(parsed) || parsed.version !== MODEL_CACHE_VERSION || !Array.isArray(parsed.models)) {\n throw new Error(`Invalid model cache at ${cachePath}`)\n }\n return parsed.models as CommandCodeModel[]\n}\n\nasync function writeModelsCache(cachePath: string, models: CommandCodeModel[]): Promise<void> {\n await mkdir(dirname(cachePath), { recursive: true })\n const tmp = `${cachePath}.${process.pid}.tmp`\n try {\n await writeFile(tmp, `${JSON.stringify({ version: MODEL_CACHE_VERSION, models }, null, 2)}\\n`, {\n encoding: 'utf-8',\n mode: 0o600,\n })\n await rename(tmp, cachePath)\n } finally {\n await rm(tmp, { force: true }).catch(() => undefined)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Message conversion: harness Message[] -> Command Code wire messages.\n// Reasoning blocks are intentionally NOT replayed (matches the pi plugin and\n// the official CLI: prior private reasoning must not leak into later turns).\n// Only tool calls with a paired tool result are replayed.\n// ---------------------------------------------------------------------------\n\nfunction pairedToolCallIds(messages: readonly Message[]): Set<string> {\n const callIds = new Set<string>()\n const resultIds = new Set<string>()\n for (const message of messages) {\n for (const block of message.content) {\n if (message.role === 'assistant' && block.type === 'tool-call') callIds.add(block.id)\n if (block.type === 'tool-result') resultIds.add(block.toolCallId)\n }\n }\n return new Set([...callIds].filter((id) => resultIds.has(id)))\n}\n\nfunction blockText(block: ContentBlock): string {\n return block.type === 'text' || block.type === 'reasoning' ? block.text : ''\n}\n\nfunction toolResultText(block: Extract<ContentBlock, { type: 'tool-result' }>): string {\n return block.content.map(blockText).filter(Boolean).join('\\n')\n}\n\nfunction hasImageContent(message: Message): boolean {\n const check = (blocks: readonly ContentBlock[]): boolean =>\n blocks.some(\n (b) => b.type === 'image' || (b.type === 'tool-result' && check(b.content)),\n )\n return check(message.content)\n}\n\nfunction messagesToCC(messages: readonly Message[]): unknown[] {\n const out: unknown[] = []\n const paired = pairedToolCallIds(messages)\n\n for (const message of messages) {\n if (message.role === 'system') continue // folded into params.system by the caller\n\n if (message.role === 'user' && message.source.kind !== 'tool') {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') parts.push({ type: 'text', text: block.text })\n if (block.type === 'image') {\n // ImageBlock carries an attachment ref owned by the attachment\n // service; resolving it to bytes requires that service. Fail loudly\n // instead of silently dropping (adapter contract).\n throw new LlmError(\n 'Image input is not wired to the attachment service in this adapter yet',\n 'UNSUPPORTED_CONTENT',\n )\n }\n }\n out.push({ role: 'user', content: parts })\n continue\n }\n\n if (message.role === 'assistant') {\n const parts: unknown[] = []\n for (const block of message.content) {\n if (block.type === 'text') {\n parts.push({ type: 'text', text: block.text })\n } else if (block.type === 'tool-call' && paired.has(block.id)) {\n parts.push({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: recordOrEmpty(block.arguments),\n })\n }\n // reasoning blocks: skipped by design (see header comment)\n }\n if (parts.length > 0) out.push({ role: 'assistant', content: parts })\n continue\n }\n\n // tool-result message (user role, single tool-result block)\n if (message.role === 'user' && message.source.kind === 'tool') {\n const block = message.content[0]\n if (!block || block.type !== 'tool-result' || !paired.has(block.toolCallId)) continue\n out.push({\n role: 'tool',\n content: [\n {\n type: 'tool-result',\n toolCallId: block.toolCallId,\n toolName: '',\n output: block.isError\n ? { type: 'error-text', value: toolResultText(block) }\n : { type: 'text', value: toolResultText(block) },\n },\n ],\n })\n }\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Adapter\n// ---------------------------------------------------------------------------\n\n/** Connection facts resolved fresh per request by the plugin entry. */\nexport interface CommandCodeConnectionOptions {\n /** API base; the Provider API lives under it (`/alpha/generate`, `/provider/v1/models`). */\n apiBase: string\n /** Working directory reported to the API (project slug, config block). */\n workingDir: string\n /** Model catalog cache path. */\n modelsCachePath: string\n}\n\n/** Everything the adapter needs beyond the request itself. */\nexport interface CommandCodeAdapterDeps<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> {\n /** Resolve the current connection facts (fresh per request, settings-aware). */\n options: () => C\n /** Resolve a usable API key for the given connection facts, or throw `MISSING_CREDENTIAL`. */\n resolveApiKey: (connection: C) => Promise<string>\n /** HTTP transport override (tests); defaults to the global `fetch`. */\n fetchImpl?: typeof fetch\n}\n\nexport class CommandCodeAdapter<C extends CommandCodeConnectionOptions = CommandCodeConnectionOptions> extends LlmAdapter {\n private catalog: CommandCodeModel[] = []\n private readonly fetchImpl: typeof fetch\n\n constructor(private readonly deps: CommandCodeAdapterDeps<C>) {\n super()\n this.fetchImpl = deps.fetchImpl ?? fetch\n }\n\n /**\n * Command Code is a metered subscription API: 429 (rate limit) and 5xx\n * (transient server errors) are worth retrying at the agent-step boundary,\n * which is where dsh-llm-retry executes the policy returned here. The\n * default policy already retries `RATE_LIMIT` and `SERVER`; declaring it\n * explicitly documents the intent and gives the plugin entry a stable hook\n * to override (e.g. a stricter cap for a metered plan).\n */\n override providerRetryPolicy(_provider: string): ResolvedRetryPolicy {\n return resolveRetryPolicy(undefined, 'llm-commandcode: retryPolicy')\n }\n\n /** Refresh the catalog (live fetch, cache fallback) and return it. */\n private async loadCatalog(signal?: AbortSignal): Promise<CommandCodeModel[]> {\n const { apiBase, modelsCachePath } = this.deps.options()\n try {\n const response = await this.fetchImpl(`${apiBase}/provider/v1/models`, {\n headers: { accept: 'application/json', ...attributionHeaders() },\n signal: signal ?? AbortSignal.timeout(MODELS_TIMEOUT_MS),\n })\n if (!response.ok) {\n throw new Error(`models endpoint returned ${response.status}`)\n }\n this.catalog = parseCatalogResponse(await response.json())\n await writeModelsCache(modelsCachePath, this.catalog).catch(() => undefined)\n } catch (error) {\n if (signal?.aborted) throw error\n // Fall back to the last successful catalog on disk.\n this.catalog = await readModelsCache(modelsCachePath).catch(() => this.catalog)\n }\n return this.catalog\n }\n\n override async listModels(provider: string): Promise<readonly LlmModelInfo[]> {\n const catalog = await this.loadCatalog()\n return catalog.map((model) => ({\n provider,\n id: model.id,\n name: `${model.name} (CC)`,\n inputModalities: ['text' as const],\n }))\n }\n\n override async resolveModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<LlmResolvedModelInfo> {\n const entry =\n this.catalog.find((m) => m.id === model) ??\n (await this.loadCatalog(signal)).find((m) => m.id === model)\n\n const efforts = KNOWN_EFFORTS[model]\n return {\n provider,\n id: model,\n name: entry ? `${entry.name} (CC)` : model,\n inputModalities: ['text' as const],\n ...(entry\n ? {\n context: { contextWindow: entry.contextWindow },\n defaultMaxTokens: Math.min(entry.maxTokens, DEFAULT_GENERATE_MAX_TOKENS),\n }\n : {}),\n // Omit `reasoning` entirely for models without known effort support:\n // the harness then treats the model as having no selectable efforts.\n ...(efforts\n ? {\n reasoning: {\n efforts: efforts.map((effort) => ({\n id: ReasoningEffortId(effort),\n name: effort,\n })),\n },\n }\n : {}),\n }\n }\n\n async *stream(options: GenerateOptions): AsyncIterable<StreamChunk> {\n if (options.stop?.length) {\n // The Command Code wire format has no documented stop field; refuse\n // loudly instead of silently dropping a request field.\n throw new LlmError('Command Code adapter does not support stop sequences', 'UNSUPPORTED_OPTION')\n }\n if (options.messages.some(hasImageContent)) {\n throw new LlmError(\n 'Image input is not wired to the attachment service in this adapter yet',\n 'UNSUPPORTED_CONTENT',\n )\n }\n\n const connection = this.deps.options()\n const apiKey = await this.deps.resolveApiKey(connection)\n const entry = this.catalog.find((m) => m.id === options.model)\n const modelMax = entry?.maxTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n const maxTokens = Math.min(\n options.maxTokens ?? modelMax,\n modelMax,\n DEFAULT_GENERATE_MAX_TOKENS,\n )\n\n const effort = options.reasoningEffort as string | undefined\n const supported = KNOWN_EFFORTS[options.model]\n const reasoningEffort =\n effort && effort !== 'off' && supported?.includes(effort) ? effort : undefined\n\n const systemText = [\n options.system ?? '',\n ...options.messages\n .filter((m) => m.role === 'system')\n .map((m) => m.content.map(blockText).filter(Boolean).join('\\n')),\n ]\n .filter(Boolean)\n .join('\\n\\n')\n\n const body = {\n config: {\n workingDir: connection.workingDir,\n date: new Date().toISOString().split('T')[0],\n environment: `${process.platform}-${process.arch}, Node.js ${process.version}`,\n structure: [],\n isGitRepo: false,\n currentBranch: '',\n mainBranch: '',\n gitStatus: '',\n recentCommits: [],\n },\n memory: null,\n taste: null,\n skills: null,\n params: {\n model: options.model,\n messages: messagesToCC(options.messages),\n tools: (options.tools ?? []).map((tool) => ({\n type: 'function',\n name: tool.name,\n description: tool.description,\n input_schema: tool.parameters,\n })),\n system: systemText,\n max_tokens: maxTokens,\n temperature: options.temperature ?? 0.3,\n stream: true,\n ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),\n },\n threadId: randomUUID(),\n }\n\n const response = await this.fetchImpl(`${connection.apiBase}/alpha/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n 'x-command-code-version': COMMAND_CODE_CLI_VERSION,\n 'x-cli-environment': 'production',\n 'x-project-slug': projectSlugFromPath(connection.workingDir),\n 'x-taste-learning': 'true',\n 'x-co-flag': 'false',\n ...attributionHeaders(),\n },\n body: JSON.stringify(body),\n ...(options.signal ? { signal: options.signal } : {}),\n })\n\n if (!response.ok) {\n const errText = await response.text().catch(() => '')\n // Command Code folds several business rejections into 403 (plan limits,\n // CLI version, model access). Prefer the machine-readable `error.code`\n // when present; the status alone cannot distinguish them.\n let providerCode: string | undefined\n try {\n const parsed: unknown = JSON.parse(errText)\n if (isRecord(parsed) && isRecord(parsed.error)) {\n providerCode = stringValue(parsed.error.code)\n }\n } catch {\n // Plain-text bodies: rely on the status mapping below.\n }\n const detail = providerCode ?? `HTTP ${response.status}`\n if (response.status === 401) {\n // An invalid or missing credential is a config problem, not a\n // transport failure: retrying it identically cannot succeed.\n throw new LlmError(\n `Command Code API error 401 (${detail}): the API key is missing or invalid — check the`\n + ' key stored for COMMANDCODE_API_KEY (Models page) or the auth file',\n 'INVALID_CREDENTIAL',\n { status: 401 },\n )\n }\n throw new LlmError(\n `Command Code API error ${response.status}${detail === `HTTP ${response.status}` ? '' : ` (${detail})`}: ${errText.slice(0, 500)}`,\n response.status === 429 ? 'RATE_LIMIT' : 'PROVIDER_HTTP_ERROR',\n { status: response.status },\n )\n }\n if (!response.body) {\n throw new LlmError('Command Code API returned no response body', 'PROVIDER_PROTOCOL_ERROR')\n }\n\n // --- SSE/JSONL event stream -> harness StreamChunk protocol ---\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n // Block assembly state: at most one text block and one reasoning block\n // are open at a time (same assumption as the pi plugin).\n let nextIndex = 0\n let textIndex = -1\n let textContent = ''\n let reasoningIndex = -1\n let reasoningContent = ''\n let sawContent = false\n\n const closeText = function* (): Generator<StreamChunk> {\n if (textIndex < 0) return\n yield {\n type: 'block-end',\n index: textIndex,\n block: { type: 'text', text: textContent },\n }\n textIndex = -1\n textContent = ''\n }\n const closeReasoning = function* (): Generator<StreamChunk> {\n if (reasoningIndex < 0) return\n yield {\n type: 'block-end',\n index: reasoningIndex,\n block: { type: 'reasoning', text: reasoningContent },\n }\n reasoningIndex = -1\n reasoningContent = ''\n }\n\n const handleEvent = (event: unknown): StreamChunk[] => {\n const chunks: StreamChunk[] = []\n if (!isRecord(event)) return chunks\n\n switch (event.type) {\n case 'text-delta': {\n chunks.push(...closeReasoning())\n if (textIndex < 0) {\n textIndex = nextIndex++\n chunks.push({ type: 'block-start', index: textIndex, blockType: 'text' })\n }\n const delta = stringValue(event.text) ?? ''\n textContent += delta\n sawContent = true\n chunks.push({ type: 'text-delta', index: textIndex, text: delta })\n break\n }\n case 'reasoning-delta': {\n chunks.push(...closeText())\n if (reasoningIndex < 0) {\n reasoningIndex = nextIndex++\n chunks.push({ type: 'block-start', index: reasoningIndex, blockType: 'reasoning' })\n }\n const delta = stringValue(event.text) ?? ''\n reasoningContent += delta\n chunks.push({ type: 'reasoning-delta', index: reasoningIndex, text: delta })\n break\n }\n case 'reasoning-start':\n chunks.push(...closeText())\n break\n case 'reasoning-end':\n chunks.push(...closeReasoning())\n break\n case 'tool-call': {\n chunks.push(...closeText(), ...closeReasoning())\n const id = stringValue(event.toolCallId) ?? randomUUID()\n const name = stringValue(event.toolName) ?? ''\n const args = JSON.stringify(recordOrEmpty(event.input ?? event.args ?? event.arguments))\n const index = nextIndex++\n sawContent = true\n chunks.push(\n { type: 'block-start', index, blockType: 'tool-call' },\n { type: 'tool-call-delta', index, id: CallId(id), name, argumentsDelta: args },\n {\n type: 'block-end',\n index,\n block: { type: 'tool-call', id: CallId(id), name, arguments: args },\n },\n )\n break\n }\n case 'finish': {\n chunks.push(...closeText(), ...closeReasoning())\n const usage = isRecord(event.totalUsage) ? event.totalUsage : undefined\n if (usage) {\n const details = isRecord(usage.inputTokenDetails) ? usage.inputTokenDetails : undefined\n const totalInput = numberValue(usage.inputTokens) ?? 0\n const cacheRead = numberValue(details?.cacheReadTokens) ?? 0\n const cacheWrite = numberValue(details?.cacheWriteTokens) ?? 0\n // Harness TokenUsage counts are disjoint: uncached input only.\n const tokenUsage: TokenUsage = {\n inputTokens:\n numberValue(details?.noCacheTokens) ?? Math.max(0, totalInput - cacheRead - cacheWrite),\n outputTokens: numberValue(usage.outputTokens) ?? 0,\n cacheReadTokens: cacheRead,\n cacheWriteTokens: cacheWrite,\n }\n chunks.push({ type: 'usage', usage: tokenUsage })\n }\n chunks.push({ type: 'finish', reason: mapFinishReason(event.finishReason) })\n break\n }\n case 'error': {\n const detail = isRecord(event.error)\n ? (stringValue(event.error.message) ?? JSON.stringify(event.error))\n : (stringValue(event.error) ?? stringValue(event.message) ?? 'Stream error')\n throw new LlmError(`Command Code stream error: ${detail}`, 'PROVIDER_STREAM_ERROR')\n }\n }\n return chunks\n }\n\n try {\n let finished = false\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n if (buffer.trim()) for (const chunk of handleEvent(parseStreamEventLine(buffer))) yield chunk\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n const chunks = handleEvent(parseStreamEventLine(line))\n for (const chunk of chunks) {\n yield chunk\n if (chunk.type === 'finish') finished = true\n }\n }\n if (finished) break\n }\n if (!finished) {\n // Stream ended without a finish event: close open blocks and\n // terminate according to the adapter contract (usage, then finish).\n yield* closeText()\n yield* closeReasoning()\n if (!sawContent) {\n throw new LlmError('Command Code returned an empty response', 'EMPTY_RESPONSE')\n }\n yield { type: 'finish', reason: { kind: 'stop' } }\n }\n } finally {\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n }\n}\n\nfunction mapFinishReason(reason: unknown): FinishReason {\n if (reason === 'tool-calls') return { kind: 'tool-calls' }\n if (\n reason === 'length' ||\n reason === 'max_tokens' ||\n reason === 'max-tokens' ||\n reason === 'max_output_tokens'\n ) {\n return { kind: 'max-tokens' }\n }\n return { kind: 'stop' }\n}\n","/**\n * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command\n * Code (unofficial; ported from pi-commandcode-provider@0.5.1).\n *\n * Registers the `commandcode` provider route on `ctx.llm` and declares it in\n * the configurable-provider directory, so the web Models page shows a\n * \"Command Code\" card with an API-key field and the model picker lists the\n * live Command Code model catalog. Connection facts resolve per request over\n * the optional `llm-commandcode` user-settings section and the credential\n * seam, so a changed key, endpoint, or cache path reaches the next request\n * without a restart.\n *\n * ```yaml\n * - id: llm-commandcode\n * name: dsh-commandcode-provider\n * config:\n * apiKeyEnv: COMMANDCODE_API_KEY\n * ```\n *\n * @module dsh-commandcode-provider\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport z from '@deepseek-ai/schemastery'\nimport { assertUsableApiKey, LlmError } from '@deepseek-ai/dsh-llm'\nimport { credentialRef, type CredentialRef } from '@deepseek-ai/dsh-credentials'\nimport { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'\nimport { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'\nimport { CommandCodeAdapter, DEFAULT_API_BASE, resolveAuthFileApiKey } from './adapter.ts'\nimport type { CommandCodeConnectionOptions } from './adapter.ts'\n\nexport {\n COMMAND_CODE_CLI_VERSION,\n DEFAULT_API_BASE,\n DEFAULT_GENERATE_MAX_TOKENS,\n DEFAULT_MAX_OUTPUT_TOKENS,\n CommandCodeAdapter,\n KNOWN_EFFORTS,\n projectSlugFromPath,\n resolveAuthFileApiKey,\n} from './adapter.ts'\nexport type { CommandCodeAdapterDeps, CommandCodeConnectionOptions } from './adapter.ts'\n\nexport const name = 'llm-commandcode'\nexport const inject = ['llm']\n\nconst NS = settingsNamespace('llm-commandcode')\nconst DEFAULT_API_KEY_ENV = 'COMMANDCODE_API_KEY'\n\n/** The single provider route this plugin owns. */\nexport const PROVIDER = 'commandcode'\n/** Default models cache path (mirrors the pi plugin's on-disk cache). */\nexport const DEFAULT_MODELS_CACHE_PATH = join(homedir(), '.commandcode', 'models-cache.json')\n\n/**\n * Plugin config, validated by the same-named schemastery schema and doubling\n * as the `llm-commandcode` settings-section shape. Every field is optional:\n * a missing API key resolves through {@link Config.apiKeyEnv} at each request\n * (the web Models page writes it), with the official Command Code CLI auth\n * file (`~/.commandcode/auth.json`) as the last fallback.\n */\nexport interface Config {\n /** Credential reference (environment-variable name) resolved per request; defaults to `COMMANDCODE_API_KEY`. */\n apiKeyEnv?: string\n /** Literal API key override (composition config only); takes precedence over `apiKeyEnv`. */\n apiKey?: string\n /** API base; defaults to the public Command Code Provider API. */\n apiBase?: string\n /** Working directory reported to the API; defaults to the process cwd. */\n workingDir?: string\n /** Model catalog cache path; defaults to `~/.commandcode/models-cache.json`. */\n modelsCachePath?: string\n}\n\nexport const Config: z<Config> = z.object({\n apiKeyEnv: z.string().role('credential-ref').default(DEFAULT_API_KEY_ENV),\n apiKey: z.string(),\n apiBase: z.string(),\n workingDir: z.string(),\n modelsCachePath: z.string(),\n})\n\n/** One resolution's complete request facts: connection plus credential reference. */\nexport interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {\n apiKeyEnv: CredentialRef\n}\n\n/**\n * The one explicit resolve step from raw config to validated connection\n * facts. Programmatic construction may bypass Schemastery normalization, so\n * every default is re-judged here — for the composition entry at load and for\n * each settings snapshot at its first use.\n */\nexport function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions {\n return {\n apiKeyEnv: credentialRef(config.apiKeyEnv ?? DEFAULT_API_KEY_ENV),\n apiBase: config.apiBase ?? DEFAULT_API_BASE,\n workingDir: config.workingDir ?? process.cwd(),\n modelsCachePath: config.modelsCachePath ?? DEFAULT_MODELS_CACHE_PATH,\n }\n}\n\nexport function apply(ctx: Context, config: Config): void {\n let current: () => Config = () => config\n let lastRaw: Config | undefined\n let lastGood: ResolvedCommandCodeOptions | undefined\n const options = (): ResolvedCommandCodeOptions => {\n const raw = current()\n if (raw === lastRaw && lastGood !== undefined) return lastGood\n const next = resolveAdapterOptions(raw)\n lastRaw = raw\n lastGood = next\n return next\n }\n options()\n\n const resolveApiKey = async (connection: ResolvedCommandCodeOptions): Promise<string> => {\n // 1. A literal key in composition config wins outright.\n const literal = current().apiKey\n if (literal) return assertUsableApiKey(literal, 'llm-commandcode', 'config.apiKey')\n // 2. The credential seam (web Models page) or the trusted environment.\n const ref = connection.apiKeyEnv\n const credentials = ctx.get('credentials')\n if (credentials !== undefined) {\n const hit = await credentials.resolve(ref)\n if (hit !== undefined) return assertUsableApiKey(hit.value, 'llm-commandcode', ref)\n } else {\n const ambient = launchEnvironmentOf(ctx).get(ref)\n if (ambient !== undefined && ambient.value.length > 0) {\n return assertUsableApiKey(ambient.value, 'llm-commandcode', ref)\n }\n }\n // 3. Last resort: reuse the official Command Code CLI login (~/.commandcode/auth.json).\n const authFileKey = resolveAuthFileApiKey()\n if (authFileKey) return assertUsableApiKey(authFileKey, 'llm-commandcode', '~/.commandcode/auth.json')\n throw new LlmError(\n `llm-commandcode: no API key for provider route \"${PROVIDER}\"; store ${ref} through the`\n + ' credentials service (the web Models page writes it), export it in the launching'\n + ' environment, set config.apiKey, or run `command-code login` to write'\n + ' ~/.commandcode/auth.json',\n 'MISSING_CREDENTIAL',\n )\n }\n\n const adapter = new CommandCodeAdapter({ options, resolveApiKey })\n // The Models page card: a configurable provider with a settings address.\n // settingsPath [] means the whole `llm-commandcode` section configures it.\n ctx.llm.registerConfigurableProviders([\n { provider: PROVIDER, displayName: 'Command Code', settingsNs: NS, settingsPath: [] },\n ])\n // The live route: this is what makes models requestable under `commandcode`.\n ctx.llm.registerAdapter([PROVIDER], adapter)\n\n installSettingsSection(ctx, NS, Config, config, {\n setSource: (source) => {\n current = source\n },\n // Everything the adapter reads is resolved per request, so a settings\n // change needs no registration-level action.\n onChange: () => {},\n })\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mars-sea/dsh-commandcode-provider",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Unofficial DeepSeek Harness LLM provider plugin for Command Code, ported from pi-commandcode-provider (MIT). Registers the 'commandcode' provider route with a Models-page card and live model catalog.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -17,13 +17,15 @@
|
|
|
17
17
|
"lib",
|
|
18
18
|
"cordis.patch.yml",
|
|
19
19
|
"README.md",
|
|
20
|
+
"README.zh-CN.md",
|
|
20
21
|
"CHANGELOG.md",
|
|
21
22
|
"LICENSE"
|
|
22
23
|
],
|
|
23
24
|
"scripts": {
|
|
24
25
|
"build": "tsdown",
|
|
25
26
|
"prepare": "tsdown",
|
|
26
|
-
"typecheck": "tsc --noEmit"
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "node --import tsx --test tests/**/*.test.ts"
|
|
27
29
|
},
|
|
28
30
|
"dsh": {
|
|
29
31
|
"bundle": {
|
|
@@ -73,6 +75,7 @@
|
|
|
73
75
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
74
76
|
"@types/node": "^22.0.0",
|
|
75
77
|
"tsdown": "^0.22.2",
|
|
78
|
+
"tsx": "^4.23.12",
|
|
76
79
|
"typescript": "^6.0.3"
|
|
77
80
|
}
|
|
78
81
|
}
|