@marsken/dsh-studio 0.0.0-stage → 0.1.0
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/AGENTS.md +148 -0
- package/LICENSE +202 -0
- package/README.md +1356 -3
- package/client.js +952 -0
- package/client.src.js +2466 -0
- package/cordis.patch.yml +9 -0
- package/dist/client.js +952 -0
- package/docs/compatibility.md +99 -0
- package/docs/publish.md +86 -0
- package/docs/quickstart.md +53 -0
- package/icon.svg +6 -0
- package/index.js +2674 -0
- package/locale/en.json +11 -0
- package/locale/zh.json +11 -0
- package/package.json +63 -4
- package/scripts/smoke-store.mjs +76 -0
- package/src/host/cases.js +135 -0
- package/src/host/design.js +87 -0
- package/src/host/dispatcher.js +936 -0
- package/src/host/domain.js +1966 -0
- package/src/host/executor.js +1396 -0
- package/src/host/gitlab-facts.js +22 -0
- package/src/host/impact.js +32 -0
- package/src/host/integrations.js +587 -0
- package/src/host/quality.js +106 -0
- package/src/host/routes/admin.js +100 -0
- package/src/host/routes/agents.js +71 -0
- package/src/host/routes/auth.js +155 -0
- package/src/host/routes/coding.js +203 -0
- package/src/host/routes/connect.js +166 -0
- package/src/host/routes/exports.js +122 -0
- package/src/host/routes/insights.js +97 -0
- package/src/host/routes/releases.js +335 -0
- package/src/host/routes/requirements.js +430 -0
- package/src/host/routes/skills.js +75 -0
- package/src/host/routes/tasks.js +573 -0
- package/src/host/store.js +522 -0
- package/src/host/team-memory.js +46 -0
- package/src/host/tools.js +1211 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# dsh-studio 与 DeepSeek Harness 的兼容性
|
|
2
|
+
|
|
3
|
+
本文是**单一事实源**:列出 dsh-studio 依赖的每一个宿主接口、它失效时用户看到什么、以及升级 dsh 之后必须按顺序验证什么。改动任何宿主调用(`ctx.*`、`__ModuleLoader__`、CLI 用法)时,必须同步更新本文件。
|
|
4
|
+
|
|
5
|
+
## 1. 已验证版本
|
|
6
|
+
|
|
7
|
+
| 项 | 值 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| dsh-studio | `package.json` `version: 0.1.0` |
|
|
10
|
+
| DeepSeek Harness | `0.2.2-rc.1`(`dsh --version`) |
|
|
11
|
+
| Node | `v24.22.2`(Linux 目标机);本机 Windows `v24.19.0` |
|
|
12
|
+
| 目标系统 | Ubuntu 24.04,`dsh web` 监听 `18080`,nginx `:80` 反代并注入 `dsh-auth-*` cookie |
|
|
13
|
+
| 插件安装方式 | `dsh plugin --profile web add link:/home/lyf/dsh-studio`(profile `web`) |
|
|
14
|
+
| 兼容声明 | `engines.dsh: ">=0.2.2-rc.1"`、`dsh.compatibility.dshReleases: { "0.2.2-rc.1+": "compatible" }` |
|
|
15
|
+
|
|
16
|
+
> 结论:只在 **0.2.2-rc.1** 上做过端到端验证。0.2.2 正式版、以及 `<0.2.2` 均未验证。
|
|
17
|
+
|
|
18
|
+
## 2. 宿主接口依赖(宿主半边)
|
|
19
|
+
|
|
20
|
+
| 接口 | 我们怎么用 | 变更/缺失时的症状 |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `export const inject = ['tools','systemPrompt']` | 插件声明必须的服务 | 插件不加载;面板消失 |
|
|
23
|
+
| `ctx.systemPrompt.section({ name, order, text })` | 注入 `studio-protocol`(order 70),告诉 agent 如何用 `studio_*` 工具 | agent 不写讨论、不推进卡片 |
|
|
24
|
+
| `ctx.tools.register(tool)` ×39 | 全部 `studio_*` 工具(建卡、派单、门禁、发布…) | 工具消失;LLM 报 unknown tool |
|
|
25
|
+
| `ctx.inject(['webServer'], ctx => ctx.webServer.register({ kind:'prefix', path:'/studio-api', handler }))` | 所有 HTTP 路由(约 112 条) | 前端全 404,面板空壳 |
|
|
26
|
+
| `ctx.inject(['agents','sessionController','workspaceRegistry','permissionPresets','agentDefaultModel'], …)` | 派单引擎 `Dispatcher`:起会话、发指令、收 `agent/status` 事件 | 派单报「这一列还没人负责」或会话永远 idle |
|
|
27
|
+
| `ctx.agents.create / resume / get / list / abort` | 一卡一会话(`studio-<taskId>-<expertId>`) | 会话起不来;`has no provider/model`;槽位泄漏 |
|
|
28
|
+
| `ctx.agents.create({ agentOptions:{ provider, model }, setup })` + `agentPresets.resolve(id)` + `presets.mount(scope, id)` | 三件缺一不可,否则没有 shell/文件工具 | agent 只会说话、改不了代码 |
|
|
29
|
+
| `agent.inject()` + `agent.followup(text, { source:{ kind:'user' } })` | 真正驱动一轮 | 会话建好立刻 idle,卡片没有讨论 |
|
|
30
|
+
| `ctx.effect(fn, label)` | 所有长生命周期资源(定时器、工具、section) | 热重载后重复注册 / 内存泄漏 |
|
|
31
|
+
| `ctx.on('agent/status', …)` | `idle` 时结算槽位 | 并发闸门卡死 |
|
|
32
|
+
| `node:sqlite`(`DatabaseSync`) | 状态库 `~/.dsh/dsh-studio.db`(WAL、`meta.state`、10 份快照) | 启动即崩;数据不落盘 |
|
|
33
|
+
| `llm.listModels(provider.id)`(模型下拉) | `/models` 端点 | 模型列表为空 |
|
|
34
|
+
|
|
35
|
+
已知会直接暴露的宿主错误文案(排障关键词):
|
|
36
|
+
|
|
37
|
+
- `dsh web authentication required` —— 反代丢失/改写 `Host`,cookie 绑定 authority
|
|
38
|
+
- `No available channel for model <model> under group arch (distributor)` + `status 503` —— provider 对该模型无通道,重试 5 次后整轮失败且**不写评论**
|
|
39
|
+
- `<agentId> has no provider/model` —— 起会话时漏传 `agentOptions`
|
|
40
|
+
- `no route POST /task/move` —— 前端调了后端不存在的路由(只在浏览器 console 可见)
|
|
41
|
+
|
|
42
|
+
## 3. 宿主接口依赖(浏览器半边)
|
|
43
|
+
|
|
44
|
+
| 接口 | 用法 | 失效症状 |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `window.__ModuleLoader__.load({ id:'dsh-studio', factory })` | 客户端模块注册入口 | 面板不出现 |
|
|
47
|
+
| `require('react')` / `require('react-dom')` | 使用宿主模块表里的 React(**不打包第二份**) | 白屏 / hooks 报错 |
|
|
48
|
+
| `ctx.slots.inject('main', …)` + `ctx.slots.register({ name:'main', key })` | 中央页面 | 页面空 |
|
|
49
|
+
| `ctx.slots.inject('sidebar.panellist', …)` + `register({ id, order, label })` | 侧栏入口「需求&任务工作空间」 | 侧栏没有入口 |
|
|
50
|
+
| 宿主 CSS 约定 | 我们所有 DOM 挂在 `[data-dsh-studio]` 下,弹层额外带 `data-dsh-studio-portal` | 样式失效、弹窗不可见 |
|
|
51
|
+
|
|
52
|
+
## 4. 运行时依赖(目标机)
|
|
53
|
+
|
|
54
|
+
| 依赖 | 用途 | 检查 |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `node >= 22`(实测 24.22.2) | `node:sqlite` 需要 | `node -v` |
|
|
57
|
+
| `git` | 一卡一 worktree、执行记录核对(`git rev-parse/log/diff`) | `git --version` |
|
|
58
|
+
| `unzip` | 上传 `.zip` 技能包 | `unzip -v` |
|
|
59
|
+
| `lark-cli` | 飞书云盘/文档归档(user 身份令牌) | 面板「飞书授权」状态 |
|
|
60
|
+
| 网络可达 GitLab | MR 回写、流水线状态 | 「集成健康」四通道 |
|
|
61
|
+
| `systemd` 单元 `dsh-web` | 常驻与重启 | `systemctl is-active dsh-web` |
|
|
62
|
+
|
|
63
|
+
文件布局:插件目录 `/home/lyf/dsh-studio`(git clone),数据 `~/.dsh/dsh-studio.db`、密钥 `~/.dsh/dsh-studio.secrets.json`、技能 `~/.dsh/skills/<name>/SKILL.md`、会话日志 `~/.dsh/sessions/<workspace>/studio-*/session.v4.jsonl.zstd`。
|
|
64
|
+
|
|
65
|
+
## 5. 升级 dsh 的验证 runbook
|
|
66
|
+
|
|
67
|
+
按顺序做,任何一步不符合期望就停下,不要继续往下:
|
|
68
|
+
|
|
69
|
+
1. `dsh --version` 记录新版本;`systemctl restart dsh-web` 后 `systemctl is-active dsh-web` 应为 `active`。
|
|
70
|
+
2. `curl -s -o /dev/null -w '%{http_code}' http://<host>/studio-api/state`(带 cookie)应为 `200`,且 JSON 有 `revision`、`tasks`。
|
|
71
|
+
3. 打开 `http://<host>/`:侧栏出现「需求&任务工作空间」,点进去 `[data-dsh-studio]` 渲染,`console` 无 error。
|
|
72
|
+
4. 工具数:`/studio-api/state` 之外,问 agent「你有哪些 studio 工具」应能看到 `studio_task_create` 等;或查 `/studio-api/tools` 若存在。
|
|
73
|
+
5. 派单一次:在看板对一张卡点「马上处理」,30 秒内该卡「讨论」应出现 agent 消息。没有 → 读会话日志找 `turn/end reason.kind=error`。
|
|
74
|
+
6. 门禁:把一张未勾清单的卡推向「已完成」,应返回 400「准出没过:…」。
|
|
75
|
+
7. 拖拽:卡片拖到相邻列,`/studio-api/state` 里该卡 `status` 变化。
|
|
76
|
+
8. 若任何一步失败,`journalctl -u dsh-web -n 100 --no-pager` + 浏览器 console + 会话日志三处取证,再决定是降级 dsh 还是适配本插件。
|
|
77
|
+
|
|
78
|
+
## 6. 兼容矩阵
|
|
79
|
+
|
|
80
|
+
| dsh 版本 | 状态 | 备注 |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| 0.2.2-rc.1 | ✅ 端到端通过 | 当前生产 |
|
|
83
|
+
| 0.2.2 正式版 | ⚠️ 未验证 | 升级前必须走第 5 节 runbook |
|
|
84
|
+
| 0.2.1 / 0.2.0 | ❌ 未验证 | 早期接口差异未知 |
|
|
85
|
+
|
|
86
|
+
## 7. 已知限制与未验证项
|
|
87
|
+
|
|
88
|
+
- **LDAP**:`ldap.laiyifen.com:389` 从目标机不可达(解析到 10.1.0.167/166,ping 全丢),只做过本地 slapd 联调;线上登录实际走「本地超管」(`admin` / 默认口令,scrypt 存储)。
|
|
89
|
+
- **GitLab**:`git.lyf.com/RD_ARCH/ai_review` 未配置真实令牌(需 Role Developer+ 与 `api` scope),MR 回写只做过离线/模拟验证。
|
|
90
|
+
- **发布门禁**:`releaseGate` 硬拦截不能被 `force` 跳过(`force` 只跳过规则项且必须给 `forceNote`)——这是设计选择,不是缺陷。
|
|
91
|
+
- **UI/设备自动化**:POS(Windows/Android)真机自动化未接入。
|
|
92
|
+
- **无障碍**:键盘可达性补丁已上线(`data-kb`/Enter/Space);Windows 高对比度 `forced-colors` 只写了样式,未实机验证。
|
|
93
|
+
- **多实例**:派单互斥靠 SQLite `locks` 表租约(TTL 12s),只验证过单实例 + 手工模拟双实例,未做真实多进程压测。
|
|
94
|
+
- **性能**:`/studio-api/state` 原来 1.29 MB(21 张卡,2026-11-13)、gzip 497 KB;已开 gzip、15s 轮询 + 数据指纹判重。2026-11-13 起**交付物正文**(`/task/artifact` 的 `get`)、**评论**(`/task/comments`)、**用例与验收清单**(`/task/parts`)都改成按需取,整包降到 **170 KB(-86.8%)**、gzip **47.7 KB(-90.4%)**。再往下的瓶颈不是字段大小而是卡片数:上千张卡要做分页(尚未实现)。
|
|
95
|
+
|
|
96
|
+
## 模型与通道
|
|
97
|
+
|
|
98
|
+
- 宿主默认模型在部分 provider 上没有可用通道时,会话第一轮就会 `turn/end reason.kind=error`,日志里是 `No available channel for model … 503`。插件的兜底常量是 `FALLBACK_AGENT_MODEL = 'deepseek-v4.1-flash'`(`src/host/dispatcher.js`),不跟随宿主默认。
|
|
99
|
+
- 模型在 **会话创建时固化**:改专家模型不影响已有会话,要重启服务或删 `~/.dsh/sessions/<ws>/studio-*` 才会重建。
|
package/docs/publish.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 发布到 DSH 插件市场(dsh-m)
|
|
2
|
+
|
|
3
|
+
市场里能搜到、能一键装,需要三件事:**包发出去**、**条目被收录**、**版本对得上**。下面按顺序说,都是照着 `dsh-m` 的 `registry.json` 结构写的。
|
|
4
|
+
|
|
5
|
+
## 0. 先确认包本身是「可发布」的
|
|
6
|
+
|
|
7
|
+
`package.json` 里这几项是市场能不能认出来的关键(当前值已就绪):
|
|
8
|
+
|
|
9
|
+
| 字段 | 现在 | 为什么 |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `name` / `version` | `dsh-studio` / 语义化版本 | 市场条目按这两项锁版本 |
|
|
12
|
+
| `private` | **已删除** | 留着就发不出去 |
|
|
13
|
+
| `keywords` | `dsh`, `dsh-plugin`, … | 市场/搜索用来分类 |
|
|
14
|
+
| `license` | `Apache-2.0` | 收录时会看 |
|
|
15
|
+
| `dsh` | `bundle.patch` + `client` + `compatibility` | 宿主靠它挂载面板、判断兼容 |
|
|
16
|
+
| `files` | 只带运行需要的东西 | 别把 `web/`、测试、探针打进去 |
|
|
17
|
+
|
|
18
|
+
发布前必跑:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run check # 语法 + 契约 + 全量测试
|
|
22
|
+
cd web && pnpm build # 产物必须和 client.js 逐字节一致
|
|
23
|
+
cd .. && cmp -s dist/client.js client.js && echo same
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 1. 发版(两条路,市场两种都吃)
|
|
27
|
+
|
|
28
|
+
**A. npm(推荐)** —— 市场条目写 `"source": "npm"`,安装时锁**最新精确版本**:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm publish --access public # 作用域包必须带 --access public 才公开
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**B. GitHub** —— 市场条目写 `"source": "github"`,安装时锁 **commit SHA**,跟踪 tag 而不是 `main`:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git tag v0.2.0 && git push origin v0.2.0
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
> 跟踪 tag 是有意的:`main` 上的中间提交可能不稳定,市场只认你明确打出来的版本。
|
|
41
|
+
|
|
42
|
+
## 2. 收录条目
|
|
43
|
+
|
|
44
|
+
市场读的是条目清单,一个条目长这样(`registry.json` 里的真实结构):
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"id": "dsh-studio",
|
|
49
|
+
"name": "DSH Studio",
|
|
50
|
+
"description": "角色化多智能体工作台:产品/架构/研发/测试 + 看板 + 用例回归",
|
|
51
|
+
"category": "essentials",
|
|
52
|
+
"tags": ["多智能体", "看板", "研发流程"],
|
|
53
|
+
"verified": ["0.2.2-rc.1"],
|
|
54
|
+
"source": "npm",
|
|
55
|
+
"npm": "@marsken/dsh-studio",
|
|
56
|
+
"github": "marsken88/dsh-studio",
|
|
57
|
+
"icon": "https://cdn.jsdelivr.net/npm/@marsken/dsh-studio@0/icon.svg",
|
|
58
|
+
"homepage": "https://github.com/marsken88/dsh-studio"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
要点:
|
|
63
|
+
|
|
64
|
+
- **`verified`** 是「在哪些宿主版本上真跑过」。别乱填——这块就是用户判断能不能装的依据;
|
|
65
|
+
- **`icon`** 走 jsDelivr 直链(`@0` 表示取最新大版本),所以图标要一起发进包里;
|
|
66
|
+
- **社区目录 vs 精选**:社区目录 6,000+ 条,随上游目录增长;精选(装机必备 / 崔添翼精选 / 自研 / 腾讯轻量云 / 观察区)是人工策展的。想让自己的插件进精选,需要向 `dsh-m` 仓库提条目;
|
|
67
|
+
- **`decoupled: true`** 表示「版本无关」,升级宿主不用跟着改,收录时可以争取。
|
|
68
|
+
|
|
69
|
+
## 3. 自查清单(收录前逐条过)
|
|
70
|
+
|
|
71
|
+
- [ ] `npm run check` 全绿;干净 clone 上能构建出**逐字节一致**的产物
|
|
72
|
+
- [ ] `docs/quickstart.md` 里的三条命令在新机器上跑得通
|
|
73
|
+
- [ ] `README.md` 第一节就是「怎么装、怎么开」,没有内部主机名/IP/密码
|
|
74
|
+
- [ ] 没有把密钥、内网地址、个人路径写进仓库(`git grep -nE '192\.168\.|/home/[a-z]+'`)
|
|
75
|
+
- [ ] `license` 与 `LICENSE` 文件一致
|
|
76
|
+
- [ ] 版本号更新,tag 已推
|
|
77
|
+
- [ ] 在**真实 dsh** 上装一遍(`dsh plugin --profile web add <包名>`),面板能开、`pageerror` 为空
|
|
78
|
+
|
|
79
|
+
## 4. 装回来验一遍
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
dsh plugin --profile web add @marsken/dsh-studio # npm 源
|
|
83
|
+
dsh plugin --profile web add github:marsken88/dsh-studio#v0.2.0
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
装完重启 dsh,跑 `node tools/visual/smoke.mjs`(需要 token 与 Chrome)确认九项检查全过。
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 第一天上手(三条命令)
|
|
2
|
+
|
|
3
|
+
这份文档的每一行都**在一个全新 clone 上跑过**(2026-11-13 验证),不是凭印象写的。
|
|
4
|
+
|
|
5
|
+
## 前提
|
|
6
|
+
|
|
7
|
+
- Node **≥ 22**(线上跑 v24;`node:sqlite`、`node:test` 都要它)
|
|
8
|
+
- pnpm(只在构建前端时需要;`npm i -g pnpm` 或 `npx pnpm@10`)
|
|
9
|
+
- 要部署/冒烟还需要:目标机的 ssh 账号、一个系统 Chrome
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
git clone ssh://git@ssh.github.com:443/marsken88/dsh-studio.git
|
|
13
|
+
cd dsh-studio
|
|
14
|
+
npm test # 1) 77 条测试,不用先装依赖
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
只跑到这一步,你已经知道「代码是好的」——测试不需要任何依赖,因为它们只碰纯函数和一个临时 SQLite。
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd web && pnpm install --frozen-lockfile && pnpm build && cd .. # 2) 重建前端
|
|
21
|
+
cmp -s dist/client.js client.js && echo same # 产物必须一致
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`pnpm install` 会提示 `Ignored build scripts: esbuild` —— **正常**,vite 用的是预编译 esbuild,构建照样过。
|
|
25
|
+
`cmp` 打出 `same` 说明你构建的产物和仓库里那份**逐字节一致**(CI 的红线就是这个)。
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
DSH_DEPLOY_HOST=<host> DSH_DEPLOY_USER=<user> DSH_DEPLOY_PASSWORD=<pw> node tools/deploy.mjs # 3) 部署
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
它会传 `index.js` + `dist/client.js` + **整个 `src/host`**,先备份旧文件,跑远端 `node --check`,重启 dsh-web,最后打印 `active= / files= / state=`;不是 `active` 就以非零退出。
|
|
32
|
+
|
|
33
|
+
## 然后:证明它真的活着
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
STUDIO_TOKEN=<面板 token> node tools/visual/smoke.mjs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
九项检查:能打开 → 侧栏进得去 → 面板挂载 → 六个页签 → 看板有卡 → 用例库有行 → 套件渲染 → `pageerror` 必须为空。任何一项不过退出码非零。
|
|
40
|
+
|
|
41
|
+
token 从哪来:dsh web 启动时会把带 token 的地址打进 journal,
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
echo <pw> | sudo -S journalctl -u dsh-web -n 50 | grep -o 'token=[A-Za-z0-9_-]*' | tail -1
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 别做的事
|
|
48
|
+
|
|
49
|
+
- 别手改 `dist/client.js` / 根 `client.js`(下次构建就覆盖,CI 也会红)
|
|
50
|
+
- 别在目标机上直接改文件(下次部署即丢)
|
|
51
|
+
- 别跳过构建就提交前端改动(`git diff --exit-code` 会拦住你)
|
|
52
|
+
|
|
53
|
+
更细的规矩在 `AGENTS.md`;用户向的功能说明在 `README.md`。
|
package/icon.svg
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<rect x="6" y="10" width="15" height="44" rx="3"/>
|
|
3
|
+
<rect x="25" y="10" width="15" height="30" rx="3"/>
|
|
4
|
+
<rect x="44" y="10" width="14" height="38" rx="3"/>
|
|
5
|
+
<path d="M10 20h7M10 26h7M29 20h7M48 20h6"/>
|
|
6
|
+
</svg>
|