dsh-pm
dsh-pm(pm = project management)由 春笋(ChunSun) 驱动 —— 把「春笋」AI 原生项目交付平台的能力,作为 DeepSeek Harness(DSH)的一等插件深度接入。
dsh-pm 让 DSH Agent 以「需求」为工作对象自主交付:开 Run、上报 Step、维护验收场景/用例、读写工作记忆、过 completed 硬门禁,并在 GUI 的会话级交付面板(composer 上方状态条 + 「项目管理」视图)实时看交付进度。工作记忆与状态以春笋自部署实例为 SSOT。
结构
src/index.ts —— ChunsunService(TypertRemoteService,@Remote 方法)
src/tools.ts —— 28 个 chunsun_* 模型工具
src/typert.ts / src/remote.ts —— Host ./typert 与 Client ./remote(仓库外需自备;dsh-api-remotes 不会替你 mount)
src/client/index.ts —— 会话级交付 GUI(lazy-CJS):conversation.input.dock 状态条(实时当前需求/Run 轮次/Step)+ conversation.view「项目管理」视图(总览页);apply 内 $mount(./remote) 后再用 ctx.remote.chunsun
cordis.patch.yml —— 组合包 patch(service + tools 两行)
lib/ —— npm run build 的产物(被 .gitignore 忽略)
已提供(Host 工具)
需求(list/show)· Run(start/takeover/status/list/remind)· Step(add/list)· 场景(list/upsert/status)· 用例(upsert/status)· 工作记忆(context_get/put)· 环境变量(env_list/env_get,secret 走审批栈)· reset · status
快速开始:安装到 DSH
前置条件
- Node.js ≥ 20 + npm(本仓库构建用);pnpm(DSH profile 管理插件用)
- 一个可启动的 DSH(下文以
web profile 为例)
- 可选:春笋自部署实例(否则只能看到「未连接」状态)
1. 构建插件(在 dsh-pm 目录内)
npm install
npm run build # tsc 转译,产物输出到 lib/(与 package.json exports 对齐)
构建必须用 tsc(不能用 tsdown):@Remote 是 Stage 3 装饰器,DSH 用原生 Node ESM 加载组合包入口,需要 tsc 降级成 __esDecorate。tsdown/oxc 目前不支持 Stage 3 装饰器,会把 @Remote 原样留在 .js 里导致 Invalid or unexpected token。
2. 装进 DSH profile
dsh plugin --profile web add ./dsh-pm # 在 dsh-pm checkout 目录执行
这条命令等价于:在 ~/.dsh/profiles/web/ 里执行 pnpm add <checkout 绝对路径>,成功后自动把声明了 dsh.bundle 的 dsh-pm 追加到 package.json 的 dsh.profile.bundles。
pnpm 对本地路径依赖创建符号链接(node_modules/dsh-pm -> 你的 checkout),因此之后每次改动只需重新构建,无需重新 add。
如果 dsh 不在 PATH(如从 monorepo checkout 直接跑),用完整路径:
node <dsh-checkout>/apps/cli/lib/bin.js plugin --profile web add ./dsh-pm
手动方式(效果相同):编辑 ~/.dsh/profiles/web/package.json,在 dependencies 加 "dsh-pm": "file:/绝对路径/dsh-pm",在 dsh.profile.bundles 加 "dsh-pm",然后在 profile 目录 pnpm install。
3. 启动并接入
dsh web # 或 dsh --profile web
首次接入:把 CHUNSUN_API_URL + CHUNSUN_SECRET_KEY 写进工作区 .env(与 chunsun CLI 同源)。也可以在 GUI 的「项目管理」视图(conversation.view)里填写并「保存并测试连接」——composer 上方状态条仅作实时状态展示,不含「配置」入口。
开发调试
迭代循环
改 src/*.ts → npm run build → 生效
├─ Host 侧(服务/工具):重启 DSH
└─ Client 侧(面板):刷新浏览器页面
- Host 侧改动(
src/index.ts、src/tools.ts):DSH 启动时加载 lib/index.js / lib/tools.js,必须重启 DSH 才生效。
- Client 侧改动(
src/client/index.ts):webServer 直接服务 lib/client.js(lazy-CJS / __ModuleLoader__.load),重新构建 + 刷新浏览器即可;若同时跑着 DSH 的 dev:web 监视构建,会自动广播重载。
- 依赖变更(package.json):
npm install 后再构建。
提交前快速校验
npx tsc --noEmit # 必须 0 错误
npm run build # 必须无 UNRESOLVED_IMPORT 之类警告
ls lib/ # index.js / tools.js / client.js(+ 对应 .d.ts)
调试手段
| 层 | 手段 |
|---|
| 构建/类型 | npx tsc --noEmit;检查 lib/ 产物是否更新、路径/扩展名是否与 package.json exports 一致;lib/client.js 必须以 window.__ModuleLoader__.load({ 开头 |
| Host 服务/工具 | 看 DSH 启动日志;在 DSH 会话里直接让 Agent 调用 chunsun_* 工具,观察返回 JSON;需要时在源码里加日志 |
| Client 面板 | 浏览器 DevTools:Console 看报错、Network 看 remote.chunsun.* RPC 请求与响应 |
| 接线自检 | 面板「保存并测试连接」→ 依次触发 config-read / config-save / status;curl 春笋实例 /health 可区分是插件问题还是实例问题 |
注意事项与常见坑
- 构建后用
node --check lib/index.js 校验 Host:产物里不应再出现 @Remote;应看到 __esDecorate / Remote('status') 这类降级代码。若仍有裸 @,说明没用 tsc 构建。
- Client 必须是 lazy-CJS:
exports["./client"] 指向的 lib/client.js 必须调用 window.__ModuleLoader__.load({ id: "dsh-pm", factory });普通 ESM(import/export)会报 loaded without registering ... via __ModuleLoader__.load。
remote.chunsun 不会自动出现:仓库外插件必须导出 ./remote,并在 Client apply 里 await ctx.remote.$mount(...);不要 inject: ['remote.chunsun'] 却无人 mount(会一直 pending)。
react 保持 external:客户端 factory 里通过 require("react") 取壳层播种的 React,不要试图打包它。
- 工具参数是 DSL 不是 JSON Schema:
defineTool 的 parameters 是「属性名 → 值 schema」映射,必填以逐属性 required: true 标注(src/tools.ts 的 regTool 已封装)。
- npm 缓存 EPERM:若报
Your cache folder contains root-owned files,执行 sudo chown -R 501:20 ~/.npm,或临时用 npm install --cache <本地目录>。
- git 安装插件:
dsh plugin ... add github:mengqinghe/dsh-pm 会跑 prepare 构建脚本,pnpm 会拦截,需把报错里给出的 key 加进 profile 的 pnpm-workspace.yaml 的 allowBuilds 后重试。
- profile 位置:默认
~/.dsh/profiles/<name>/(可用 DSH_HOME 环境变量改)。
设计文档
详见本仓库 docs/design.md、docs/p5-promotion.md 与 docs/prototype/(动态插件原型源码)。