@marsken/dsh-studio 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.
@@ -6,11 +6,11 @@
6
6
 
7
7
  | 项 | 值 |
8
8
  | --- | --- |
9
- | dsh-studio | `package.json` `version: 0.1.0` |
9
+ | dsh-studio | `package.json` `version: 0.1.1` |
10
10
  | DeepSeek Harness | `0.2.2-rc.1`(`dsh --version`) |
11
11
  | Node | `v24.22.2`(Linux 目标机);本机 Windows `v24.19.0` |
12
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`) |
13
+ | 插件安装方式 | npm:`dsh plugin --profile web add @marsken/dsh-studio`;本地开发:`add link:~/dsh-studio`(profile `web`) |
14
14
  | 兼容声明 | `engines.dsh: ">=0.2.2-rc.1"`、`dsh.compatibility.dshReleases: { "0.2.2-rc.1+": "compatible" }` |
15
15
 
16
16
  > 结论:只在 **0.2.2-rc.1** 上做过端到端验证。0.2.2 正式版、以及 `<0.2.2` 均未验证。
@@ -22,7 +22,7 @@
22
22
  | `export const inject = ['tools','systemPrompt']` | 插件声明必须的服务 | 插件不加载;面板消失 |
23
23
  | `ctx.systemPrompt.section({ name, order, text })` | 注入 `studio-protocol`(order 70),告诉 agent 如何用 `studio_*` 工具 | agent 不写讨论、不推进卡片 |
24
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,面板空壳 |
25
+ | `ctx.inject(['webServer'], ctx => ctx.webServer.register({ kind:'prefix', path:'/studio-api', handler }))` | 所有 HTTP 路由(125 条,含 `/suite/*`、`/coding/gitlab`、`/requirement/impact`、`/task/design`) | 前端全 404,面板空壳 |
26
26
  | `ctx.inject(['agents','sessionController','workspaceRegistry','permissionPresets','agentDefaultModel'], …)` | 派单引擎 `Dispatcher`:起会话、发指令、收 `agent/status` 事件 | 派单报「这一列还没人负责」或会话永远 idle |
27
27
  | `ctx.agents.create / resume / get / list / abort` | 一卡一会话(`studio-<taskId>-<expertId>`) | 会话起不来;`has no provider/model`;槽位泄漏 |
28
28
  | `ctx.agents.create({ agentOptions:{ provider, model }, setup })` + `agentPresets.resolve(id)` + `presets.mount(scope, id)` | 三件缺一不可,否则没有 shell/文件工具 | agent 只会说话、改不了代码 |
@@ -60,7 +60,7 @@
60
60
  | 网络可达 GitLab | MR 回写、流水线状态 | 「集成健康」四通道 |
61
61
  | `systemd` 单元 `dsh-web` | 常驻与重启 | `systemctl is-active dsh-web` |
62
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`。
63
+ 文件布局:插件目录由安装方式决定(npm 装在 profile 的 `node_modules`,本地开发是 `~/dsh-studio`),数据 `~/.dsh/dsh-studio.db`、密钥 `~/.dsh/dsh-studio.secrets.json`、技能 `~/.dsh/skills/<name>/SKILL.md`、会话日志 `~/.dsh/sessions/<workspace>/studio-*/session.v4.jsonl.zstd`。
64
64
 
65
65
  ## 5. 升级 dsh 的验证 runbook
66
66
 
@@ -72,6 +72,8 @@
72
72
  4. 工具数:`/studio-api/state` 之外,问 agent「你有哪些 studio 工具」应能看到 `studio_task_create` 等;或查 `/studio-api/tools` 若存在。
73
73
  5. 派单一次:在看板对一张卡点「马上处理」,30 秒内该卡「讨论」应出现 agent 消息。没有 → 读会话日志找 `turn/end reason.kind=error`。
74
74
  6. 门禁:把一张未勾清单的卡推向「已完成」,应返回 400「准出没过:…」。
75
+ 6.1 设计闸门(若已开启):设置 → 列的负责人 打开「设计闸门」,把一张没有评审记录的卡推进 `dev`,应返回 400「进开发被拦:…」。
76
+ 6.2 回归:用例页点「▶ 跑」默认套件,回归历史应新增一条,且 `/studio-api/state` 的 `revision` 递增。
75
77
  7. 拖拽:卡片拖到相邻列,`/studio-api/state` 里该卡 `status` 变化。
76
78
  8. 若任何一步失败,`journalctl -u dsh-web -n 100 --no-pager` + 浏览器 console + 会话日志三处取证,再决定是降级 dsh 还是适配本插件。
77
79
 
@@ -85,8 +87,8 @@
85
87
 
86
88
  ## 7. 已知限制与未验证项
87
89
 
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
+ - **LDAP**:公司 LDAP(`ldap.<公司域>:389`)从目标机不可达(解析到内网地址,ping 全丢),只做过本地 slapd 联调;线上登录实际走「本地超管」(`admin` / 默认口令,scrypt 存储)。
91
+ - **GitLab**:公司 GitLab(`git.<公司域>/<group>/<repo>`)未配置真实令牌(需 Role Developer+ 与 `api` scope),MR 回写只做过离线/模拟验证。
90
92
  - **发布门禁**:`releaseGate` 硬拦截不能被 `force` 跳过(`force` 只跳过规则项且必须给 `forceNote`)——这是设计选择,不是缺陷。
91
93
  - **UI/设备自动化**:POS(Windows/Android)真机自动化未接入。
92
94
  - **无障碍**:键盘可达性补丁已上线(`data-kb`/Enter/Space);Windows 高对比度 `forced-colors` 只写了样式,未实机验证。
Binary file
Binary file
Binary file
package/docs/publish.md CHANGED
@@ -83,4 +83,41 @@ dsh plugin --profile web add @marsken/dsh-studio # npm 源
83
83
  dsh plugin --profile web add github:marsken88/dsh-studio#v0.2.0
84
84
  ```
85
85
 
86
- 装完重启 dsh,跑 `node tools/visual/smoke.mjs`(需要 token 与 Chrome)确认九项检查全过。
86
+ 装完重启 dsh,跑 `node tools/visual/smoke.mjs`(需要 token 与 Chrome)确认九项检查全过。
87
+
88
+ ## 踩坑记录(2026-11-13 首次发布 @marsken/dsh-studio@0.1.0)
89
+
90
+ 这一节是实发时真撞上的,下次照做能省一圈:
91
+
92
+ **1. 先查名字,别想当然。**
93
+
94
+ ```bash
95
+ npm view dsh-studio version # → 0.0.1,别人 8 月占的位
96
+ npm view @<你的用户名>/dsh-studio version # → 404 说明可用
97
+ ```
98
+
99
+ npm 不允许覆盖别人的包名,撞名只能改作用域包(`@user/name`)或换名。
100
+
101
+ **2. 账号开了 2FA 时,普通 token 发不出去。**
102
+
103
+ ```
104
+ npm error 403 Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages.
105
+ ```
106
+
107
+ 两条路:①生成 **Granular Access Token** 并勾上 **Bypass two-factor authentication**(推荐,之后 CI/脚本都能用);②本机 `npm publish` 手输 6 位验证码。
108
+
109
+ **3. 发布成功 ≠ 立刻可查。**
110
+
111
+ `npm publish` 打出 `+ @marsken/dsh-studio@0.1.0` 之后,registry 仍会 404 **约 10 分钟**(npm 提示 `being processed`)。别急着重发,先轮询:
112
+
113
+ ```bash
114
+ curl -s -o /dev/null -w '%{http_code}\n' https://registry.npmjs.org/@marsken%2Fdsh-studio # 等到 200
115
+ npm view @marsken/dsh-studio version # 再确认版本号
116
+ curl -s -o /dev/null -w '%{http_code} %{size_download}\n' $(npm view @marsken/dsh-studio dist.tarball)
117
+ ```
118
+
119
+ **4. 凭据用完即删、发完即换。**
120
+
121
+ token 只写进临时 npmrc(放在仓库外或 `tmp/` 且不提交),发完立刻 `rm`;发完去 npm 后台 revoke 重新生成——凡是贴进聊天/工单/日志的 token 都当作已泄露。
122
+
123
+ **5. 作用域包必须带 `--access public`**,否则默认私有,市场里别人装不了(表现为 anonymous 访问 404)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marsken/dsh-studio",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "DSH Studio: role-based multi-agent workspace (product / architect / developer / QA) with a live work board, GitLab + Feishu connection settings, all configurable from the web GUI.",
6
6
  "main": "index.js",
@@ -32,6 +32,7 @@
32
32
  "client.src.js",
33
33
  "AGENTS.md",
34
34
  "docs/*.md",
35
+ "docs/images/*.png",
35
36
  "scripts/*.mjs"
36
37
  ],
37
38
  "dsh": {
@@ -260,7 +260,7 @@ export function defaultConfig() {
260
260
  /** 统一登录:LDAP。bindPassword 只进密钥文件,落库时清空。 */
261
261
  ldap: {
262
262
  enabled: false,
263
- url: 'ldap://ldap.laiyifen.com:389',
263
+ url: 'ldap://localhost:389',
264
264
  baseDN: 'DC=LYF,DC=COM',
265
265
  bindDN: 'cn=root',
266
266
  bindPassword: '',
@@ -293,7 +293,7 @@ export function sanitizeLdap(raw) {
293
293
  const timeout = Number(input.timeoutMs)
294
294
  return {
295
295
  enabled: input.enabled === true,
296
- url: /^ldaps?:\/\/[^\s]+$/i.test(url) ? url : 'ldap://ldap.laiyifen.com:389',
296
+ url: /^ldaps?:\/\/[^\s]+$/i.test(url) ? url : 'ldap://localhost:389',
297
297
  baseDN: baseDN === '' ? 'DC=LYF,DC=COM' : baseDN,
298
298
  bindDN: bindDN === '' ? 'cn=root' : bindDN,
299
299
  bindPassword: String(input.bindPassword ?? '').trim().slice(0, 200),
package/src/host/tools.js CHANGED
@@ -842,7 +842,7 @@ export function registerTools(ctx, store) {
842
842
  artifactId: { type: 'string', description: 'Required for update / remove.' },
843
843
  kind: { type: 'string', description: `requirement | design | mr | cases | report | release | doc | screenshot | other` },
844
844
  title: { type: 'string', description: 'What this deliverable is.' },
845
- ref: { type: 'string', description: 'Path or URL (e.g. /home/lyf/dsh-workspace/docs/x.md or the MR link).' },
845
+ ref: { type: 'string', description: 'Path or URL (e.g. ~/dsh-workspace/docs/x.md or the MR link).' },
846
846
  content: { type: 'string', description: '交付物正文(Markdown)。写到云盘文档里的就是这段;不填就只有标题和元信息。' },
847
847
  by: { type: 'string', description: '登记人:填你自己的专家名字(例如「架构师」)。看板靠它区分 AI 产出和人手工登记。' },
848
848
  sync: { type: 'boolean', description: '登记后是否立刻同步到飞书云盘(需求文件夹下的 .md 文档)。默认 true。' },