跨会话接力文档。新会话接手时先读本文件,再读代码。 最后更新:2026-10-31 · 对应版本
v1.1.2
是什么:dsh-commandcode 是一个 DSH-Desktop(DeepSeek Harness 桌面版)的 LLM 提供商插件,把 Command Code 的模型接入 DSH 的模型选择器。它在社区原版 Mars-Sea/dsh-commandcode-provider(MIT)的基础上重写增强:SWR 模型目录、可配置超时与重试、多账户轮换、结构化错误诊断、按套餐过滤模型、用量与计费面板、中英双语设置页。
当前状态(截至 2026-10-21)
| 项 | 状态 |
|---|---|
| 版本 | package.json = 1.1.2 |
| 分支 | main |
| 已验证功能 | 提供商路由注册、Models 页卡片、模型目录 SWR、设置页(连接/用量与套餐/多账户/高级)、/commandcode 终端命令、OAuth 回环登录、用量与套餐面板、多账户轮换 |
| 测试 | npm test 覆盖 tests/ 下 6 个文件(accounts / errors / login / retry / adapter / catalog,Node 内置 test runner),101 个用例 |
| CI | .github/workflows/ci.yml:Node 22 → npm ci → typecheck → test → build → 校验 lib/ 三件产物存在 |
| 发布渠道 | ①GitHub 公开发布(tag + Release);②DSH 插件市场(awesome-dsh-plugin,条目已收录,PR #3925 于 2026-08-31 合并);③未发布到 npm(dsh-commandcode 在 npm 上为 404) |
| 市场条目 | data/plugins/wjf1__dsh-commandcode.yml,install 为 dsh plugin --profile web add github:wjf1/dsh-commandcode,目录中 version/npm 均为空、无截图 |
| 已知缺口 | assets/ 目录尚未入库(README 截图章节指向 assets/*.png,需补真实截图);screenshots.json 目前是 {"screenshots": []} |
- 语言/构建:TypeScript + ESM(
"type": "module"),构建器tsdown(tsdown.config.ts为源,仓库同时保留编译出的tsdown.config.js)。 - 运行时基线:DSH-Desktop ≥ 0.7.0(内置 DeepSeek Harness 0.1.2-alpha.1);开发机 Node ≥ 20,CI 用 Node 22。
- 宿主侧:
cordis插件体系,入口由cordis.patch.yml声明(insert一条id: llm-commandcode),在ctx.llm上注册commandcode提供商路由。 - 客户端侧:
package.json的dsh.client声明platform: web、immediately: true、inject: [dsh-client-locale, dsh-client-ui-slots],加载器自动取exports["./client"]。 - 依赖闭包:
vendor/下以file:形式落盘了 0.1.2-alpha.1 的整套@deepseek-ai/*tarball(devDependencies),用于npm ci/ 测试 / 构建的可复现性,直到上游把该版本正式发到 npm。 - 关键上游变更(0.1.2-alpha.1):
LlmAdapter的CallId→ToolCallId;finish reason 新增max-tokens联合成员;@deepseek-ai/dsh-client-runtime被删除,改用@deepseek-ai/dsh-client-store;ctx.typert.register()消失,用量/登录后端改走共享/api精确 Fetch 路由注册表(connection.fetch.register)。 - 常用命令
npm ci # 按 package-lock 还原(含 vendor/ 的 file: 依赖)
npm run typecheck # tsc --noEmit
npm test # node --test tests/*.test.ts
npm run build # tsdown → lib/(ESM + .d.ts)dsh-commandcode/
├── src/
│ ├── index.ts # 宿主入口:注册 commandcode 提供商路由、设置区、装配各服务
│ ├── adapter.ts # LLM 适配器(38KB,最大文件):流式生成、模型目录、用量端点
│ ├── catalog.ts # 模型目录:SWR + 磁盘缓存 + ETag 条件请求 + 熔断器
│ ├── accounts.ts # 多账户池:429/401 自动轮换、冷却账户窗口探测
│ ├── retry.ts # 重试策略:指数退避+抖动、错误分类(RATE_LIMIT/SERVER/TIMEOUT/TRANSPORT/EMPTY_RESPONSE)
│ ├── errors.ts # 结构化错误:稳定错误码 + 诊断上下文 + 用户可读提示
│ ├── login.ts # OAuth 登录:回环回调服务器(端口 18700–18799)
│ ├── login-wire.ts # 登录线路协议类型
│ ├── usage-remote.ts # 用量端点:GET /api/commandcode/report
│ ├── usage-wire.ts # 用量线路协议类型
│ ├── commands.ts # /commandcode 终端命令
│ ├── command-locales.ts # 命令中文/英文字符串(静态 import,见避坑 5)
│ └── client/ # 浏览器侧
│ ├── index.ts # 客户端入口:CSS 注入、slot 注册、控制器装配
│ ├── section.tsx # 设置页主组件(17.5KB)
│ ├── card.tsx # Models 页提供商卡片
│ ├── settings.ts # 设置控制器:状态、实时校验、持久化
│ ├── login.ts # 登录控制器:轮询 /api/commandcode/login/status
│ ├── usage.ts # 用量控制器:拉取、账户标签页
│ ├── locales.ts # 客户端中英文本地化
│ ├── sessions.ts # 图片会话错误包装
│ ├── update.ts # 更新检查
│ └── version.ts # 版本常量
├── tests/ # accounts / errors / login / retry / adapter / catalog 六个回归测试
├── lib/ # 预构建产物,刻意提交(见避坑 1)
├── vendor/ # 0.1.2-alpha.1 依赖闭包 tarball
├── cordis.patch.yml # Bundle 层:insert id=llm-commandcode,config.apiKeyEnv=COMMANDCODE_API_KEY
├── screenshots.json # 市场抓取的截图清单(当前为空)
├── README.md / README.zh-CN.md / CHANGELOG.md / HANDOFF.md / NOTICE / LICENSE
数据流:对话请求 → DSH ctx.llm → adapter.ts(逐请求用 thunk 解析 API Key/端点/超时) → Command Code Provider API POST {apiBase}/alpha/generate(自定义 SSE/JSONL)→ 解析 text-delta / reasoning-* / tool-call / finish / error 事件回流。模型目录走 GET /provider/v1/models,命中缓存即刻返回、后台刷新。
凭证解析优先级(高 → 低):设置页保存的 key → 环境变量 COMMANDCODE_API_KEY → CLI 认证文件 ~/.commandcode/auth.json → 内置 OAuth 登录。
v1.1.2(2026-08-31) — 修 DSH Desktop 插件市场安装失败。根因是 pnpm v10 起默认拦截依赖的生命周期脚本,本插件此前靠 prepare 跑 tsdown 构建,被拦截后市场直接判不可安装。做法:把 lib/ 构建产物提交进仓库、删掉 prepare,安装变成零脚本纯文件拷贝。
v1.1.1(2026-08-30) — 用量与套餐面板按设计稿重做(账户 chip、四张统计卡、三张额度卡、两条窗口进度条、账户标签页真正可切换、挂载即加载);修两个数据 bug:成功率被重复乘 100(显示 10000%)、账期截止把 ISO 字符串当数字解析导致恒空。
v1.1.0(2026-08-30) — 适配 DeepSeek Harness 0.1.2-alpha.1(CallId→ToolCallId、max-tokens、dsh-client-store 接替 dsh-client-runtime、/api Fetch 路由、CredentialRef 品牌化字符串);落盘 vendor/ 依赖闭包;修 tsc --noEmit 从未能跑通、/commandcode 在 ESM 里用 require() 崩、测试用错 assert 导出。
本轮(2026-10-21,未发版) — 补齐发布门禁要求的四文档:新增 HANDOFF.md;双语 README 增加截图章节与 lib/ 提交原因说明、补全项目结构树;CHANGELOG 增加 [Unreleased] 小节。随后创建 首个 annotated tag v1.1.2 与 GitHub Release(此前仓库无任何 tag 与 Release)。
本轮(2026-10-31,未发版) — 测试补齐与市场条目更新:
- 测试补齐:新增
tests/adapter.test.ts(41 用例:SSE 流解析、finish 兜底守卫、429/401 轮换、超时/网络错误映射、getUsage 四端点聚合与 blocked 分类、probeFiveHourWindow、凭证文件解析等)与tests/catalog.test.ts(14 用例:响应解析、SWR、ETag/304、磁盘缓存、熔断门控与强制刷新),tests/retry.test.ts追加buildRetryPolicy/ 重试码常量 /backoffDelay/sleep的 AbortSignal 行为(9 用例)。npm test共 101 个用例全部通过(Node 22 本机验证)。 - 市场条目更新(PR #10798,待合并):
data/plugins/wjf1__dsh-commandcode.yml的 description 对齐双语 README 一句话定位。经查上游scripts/lib/entries.mjs的ENTRY_KEYS白名单(url/name/category/description/icon/tarball/file),条目 schema 不支持 version/npm/install/screenshots 字段:npm 由probe-npm从仓库自动解析、install 命令按 URL 自动生成(当前 npm 404,安装走 GitHub,与实际一致)、version 以 GitHub Release v1.1.2 表达;v1.1.2 Release 无.tgz资产故不写 tarball。提交走 GitHub REST API(merge-upstream 同步 fork → git/refs 建分支update-entry-v1-1-2→ PUT contents → PR)。
本轮(2026-11-01,未发版) — DSH 0.2.x client 半适配加固与装载层阻塞定性:
src/client/index.ts新增whenSlotDeclared:设置页两处槽位注册(settings.section/settings.models.provider-card)改为「探测声明 → 未声明则subscribeDeclaration等声明边界再注册」的防御模式(0.2.x 把设置 chrome 的槽位声明推迟到设置弹窗条目的 children 表;npm run typecheck与npm run build通过,产物已部署本机 profile)。- 装载层根因定性(详见第 5 节第 6 条):插件组件 row
llm-commandcode在 0.2.1-rc.3 上phase: null(fiber 从未创建),dsh-client-modulesregistry 因此不把 client bundle 放进启动 manifest,client 半从未执行——设置 UI 静默失效的根因在宿主装载层,client 槽位名与注册 API 与 0.1.x 相比未变。peer 兼容、bundles 位置、modules overlay、文件解析等假设逐一排除,激活错误因宿主无日志/CLI/主进程调试通道而无法浮出。 - 三张市场截图继续阻塞:UI 未渲染,无法拍摄。排障过程沉淀的全部证据与解锁路径已写入第 5 节第 6 条。
- 盯市场 PR 合并:PR #10798(分支
update-entry-v1-1-2)已在 CI 走查中,合并后确认上游 README 两份生成文件里wjf1/dsh-commandcode行已同步为新 description。 - 补真实截图:在 DSH Desktop 0.7.1 内实拍
assets/panel-usage.png、assets/card-models.png、assets/settings-accounts.png,把screenshots.json从空数组改成实际清单,再向市场提一次条目更新(届时可在 Release 补.tgz资产并加tarball字段,市场索引即可展示版本号)。 可选:发 npm被抢注阻塞(2026-11-01):npm 名dsh-commandcode已被第三方code_tin <code_tin@msn.com>于本日 21:17(UTC 13:17)抢注(连发 0.0.0-stage/0.1.0/0.1.1,实现为同类竞品、无恶意钩子,但会劫持市场 probe-npm 的自动解析)。本账号jianfengwang发布 403。防御:GitHub Releasev1.1.3附官方 npm tarball,市场条目钉tarball:字段指向该资产,市场安装永不落到冒牌包。用户可选项:向 npm 举报抢注 / 换名(如@jianfengwang/dsh-commandcode)/ 接受 GitHub 安装现状。补测试:已完成(2026-10-31)——adapter/catalog/retry的回归已补齐,npm test101 个用例全绿。- 盯上游:
0.1.2-alpha.1正式发到 npm 后,可以把vendor/从file:devDependencies 换回正常版本区间并瘦身仓库。 - 适配 DSH 0.2.x 宿主(2026-11-01 两轮实测,阻塞补截图):本机宿主已自动升级到
0.2.1-rc.3(内部@deepseek-ai/dsh-*同步 0.2.x)。两轮排查后的精确结论: ① UI 槽位名没有变,注册 API 也没有变:0.2.x 的settings.section由设置弹窗 shell(ui-settings-general)的sidebar.settings条目 children 表声明(kind list),settings.models.provider-card由其中 Models 条目的 children 声明(kind keyed,key = provider 的 settingsNsllm-commandcode,renderSlot时传入provider/configured/keyConfiguredprops)。ctx.slots.inject(name, factory)的语义是「声明已存在才调 factory,否则等声明边界再调」(实现在dsh-client-ui-renderer的SlotRegistry.inject)。 ② client 侧已做懒声明防御(whenSlotDeclared:先探测注册、未声明则subscribeDeclaration等声明出现再注册,仅吞 not declared 竞态错误)——src/client/index.ts、已构建部署。0.1.2-alpha.1 的 SlotCore 合同同样有subscribeDeclaration,0.1.x 兼容不受影响。 ③ 真正的卡点在装载层,不在 client:插件详情页(插件 → dsh-commandcode)显示组件llm-commandcode「未运行」——React store 数据为enabled: true, phase: null(row 存在、未禁用、但 fiber 从未创建);而插件页列表的data-plugin-status="running"只是包级安装状态,会掩盖组件未激活。由于dsh-client-modules的ClientModuleRegistry扫描 loader entries 时跳过entry.fiber === void 0的行,本插件 client bundle 从未进入启动 manifest(window.__DSH_BOOT__.entries共 94 项无 dsh-commandcode;fetch /plugins/dsh-commandcode/client.js返回 404),client 半从未被执行(head 中无style[data-plugin="dsh-commandcode"]标记)——这才是设置 UI 静默失效的根因。client 槽位注册代码再正确也不会被调用。 ④ 已排除的原因:peer 兼容性(12 条 dsh-* peer 用宿主同款semver.satisfies(0.2.1-rc.3, range, {includePrerelease: true})逐一验证全部满足);dsh.profile.bundles栈位置(把 dsh-commandcode 从末位前移到 vision-router 之前并重启,无效,已还原);给官方modulesrow 追加inject: [webServer](dsh-vision-router 的已知竞态 workaround,对本例无效,workaround 保留在 cordis.patch.yml 末尾);profile 树内文件解析(createRequire(profiles/desktop/node_modules).resolve('dsh-commandcode/package.json')正常,exports/dsh.client 合法)。 ⑤ 激活错误无法浮出:宿主 0.2.1-rc.3 无常规运行日志文件(logs/只有 crash 转储)、本机无dshCLI、主进程无--inspect;用Start-Process -RedirectStandardError捕获 stderr 也没有 cordis 层 deny/preflight 诊断(dsh-app-boot的prepareProfileEntries会把「disabling profile plugin row …」写到 stderr,本例没有出现,说明 row 未被显式 deny,而是停在未激活)。 ⑥ 补三张截图(panel-usage / card-models / settings-accounts)继续被此项阻塞。解锁路径建议(按性价比排序):a) 给宿主主进程开--inspect或找到上游日志开关后重启,读 llm-commandcode row 的激活错误;b) 若上游发布带 CLI 的版本,用dsh --dump-config对照 include 树中该 row 的最终形态;c) 对照宿主上同样「组件未运行」过的插件(如@michengai/dsh-archive-manager、@michengai/dsh-im-connect曾因 peer 不兼容被 deny 后豁免恢复)确认恢复手法是否适用于本例;d) 等 0.2.1 正式版看装载层是否变化。 本机已按上述状态安装:登记进 profile 的 dependencies + bundles(^1.1.2,裸目录手动部署于profiles/desktop/node_modules/dsh-commandcode,lib/ 与 src/ 同步)。
lib/必须提交,且改src/后必须重建。市场安装不做构建,缺少lib/就是「装了但没反应」。只提交src/的提交等于发布了一个坏包。- 不要在
package.json里加回prepare脚本。pnpm v10 会拦截它,市场安装当场失败——这正是 v1.1.2 修的那个坑。 - 凭证是只写的。API Key 保存后不会随 credentials Remote 视图回读到前端,设置页只显示「已配置」徽章并接受替换。任何「把 key 读回来显示」的需求都要重新设计,不要直接改视图。
- 登录回调只绑回环(127.0.0.1,端口 18700–18799)并做 CORS origin 校验;错误上下文会带 status/model/account/requestId,绝不能带 key。
/commandcode命令的本地化字符串必须静态import,早期在 ESM 里用require()直接运行时崩溃。tsc --noEmit依赖tsconfig.json里的allowImportingTsExtensions,删了它整个类型检查就跑不起来。- 逐请求解析而非启动时快照:API Key、
apiBase、超时都是 thunk,改设置立刻对下一次请求生效,不需要重启。新增配置项请沿用这个模式。 - 线路协议是私有的:
/alpha/generate的自定义 SSE/JSONL 事件名(text-delta/reasoning-*/tool-call/finish/error)由 Command Code 定义,解析器在adapter.ts,上游一改就会断流式。改动前先拿真实响应比对。 - CI 只跑类型检查 + 两个测试文件 + 构建,不跑真实 API 调用;涉及真实模型的改动必须在本机手工走查一遍设置页与对话流(本项目 0.7.1 设计令牌对齐这部分尤甚)。
- 发布流程:测试通过 → 四文档齐备且版本一致 →
git tag -a vX.Y.Z -m "vX.Y.Z: 中文摘要"→ push--tags→ 建 Release(标题与 tag subject 逐字一致,正文按 新增/修复/安全加固 分类)。