@dsh-workbench/core 0.3.9 → 0.3.11

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.
Files changed (84) hide show
  1. package/README.md +19 -7
  2. package/bin/dsh-workbench +2 -2
  3. package/client.js +1687 -1022
  4. package/cordis.patch.yml +60 -35
  5. package/dist/client/client.body.js +1687 -1022
  6. package/dist/client/index.js +1372 -707
  7. package/dist/host/index.js +2897 -2335
  8. package/dist/types/app/client.d.ts +2 -1
  9. package/dist/types/app/layouts/env-gate/boot-gate.d.ts +1 -1
  10. package/dist/types/app/layouts/market/use-module-versions.d.ts +13 -2
  11. package/dist/types/app/layouts/rightbar/MarketView.d.ts +6 -3
  12. package/dist/types/app/layouts/rightbar/market-act.d.ts +6 -3
  13. package/dist/types/app/layouts/rightbar/market-rows.d.ts +1 -1
  14. package/dist/types/app/layouts/rightbar/market-settle-hold.d.ts +2 -0
  15. package/dist/types/app/layouts/rightbar/market-settle.d.ts +20 -0
  16. package/dist/types/app/layouts/rightbar/market-shared-rows.d.ts +0 -1
  17. package/dist/types/app/layouts/rightbar/market-update-verdict.d.ts +41 -0
  18. package/dist/types/app/layouts/rightbar/market-view-text.d.ts +4 -1
  19. package/dist/types/app/layouts/rightbar/store.d.ts +14 -0
  20. package/dist/types/app/layouts/sidebar/LongTaskDot.d.ts +12 -0
  21. package/dist/types/app/layouts/sidebar/LongTaskHover.d.ts +12 -0
  22. package/dist/types/app/layouts/sidebar/edition-boot.d.ts +24 -0
  23. package/dist/types/app/layouts/sidebar/edition.d.ts +22 -0
  24. package/dist/types/app/layouts/workbench-settings/ConfigSyncItem.d.ts +5 -0
  25. package/dist/types/app/layouts/workbench-settings/SettingsItem.d.ts +17 -0
  26. package/dist/types/app/layouts/workbench-settings/SidebarEditionItem.d.ts +11 -0
  27. package/dist/types/app/layouts/workbench-settings/WorkbenchSettingsSection.d.ts +11 -0
  28. package/dist/types/modules/panels/model/approval.d.ts +12 -4
  29. package/dist/types/modules/panels/model/diy-browser-tools.d.ts +1 -1
  30. package/dist/types/modules/panels/model/diy-context.d.ts +31 -14
  31. package/dist/types/modules/panels/model/diy-page.d.ts +3 -2
  32. package/dist/types/modules/panels/model/diy-record.d.ts +3 -3
  33. package/dist/types/modules/panels/model/diy-report.d.ts +6 -7
  34. package/dist/types/modules/panels/model/market-dependency-update.d.ts +21 -0
  35. package/dist/types/modules/panels/model/market-dispatch.d.ts +1 -0
  36. package/dist/types/modules/panels/model/market-types.d.ts +1 -0
  37. package/dist/types/modules/panels/model/market-update-bundle.d.ts +25 -0
  38. package/dist/types/modules/panels/model/market-verify.d.ts +31 -0
  39. package/dist/types/modules/panels/unit.d.ts +3 -4
  40. package/dist/types/shared/api/bundle-install.d.ts +13 -0
  41. package/dist/types/shared/api/host/approval-gate.d.ts +39 -0
  42. package/dist/types/shared/api/host/bundle-routes.d.ts +2 -1
  43. package/dist/types/shared/api/host/diy-artifacts.d.ts +14 -0
  44. package/dist/types/shared/api/host/diy-modules.d.ts +41 -0
  45. package/dist/types/shared/api/host/host-routes.d.ts +13 -0
  46. package/dist/types/shared/api/host/permission-mode.d.ts +9 -0
  47. package/dist/types/shared/api/host/runtime-seed.d.ts +2 -0
  48. package/dist/types/shared/api/host/self-update.d.ts +9 -2
  49. package/dist/types/shared/api/host/sidebar-edition.d.ts +46 -0
  50. package/dist/types/shared/api/host/workspace-root.d.ts +13 -0
  51. package/dist/types/shared/api/sidebar-edition.d.ts +14 -0
  52. package/dist/types/shared/api/unit-board.d.ts +20 -0
  53. package/dist/types/shared/api/write-outcome.d.ts +15 -0
  54. package/dist/types/shared/components/IconModules.d.ts +8 -0
  55. package/dist/types/shared/components/blocker-action.d.ts +16 -0
  56. package/dist/types/shared/hooks/sidebar-edition.d.ts +7 -0
  57. package/dist/types/shared/hooks/use-capabilities.d.ts +5 -0
  58. package/dist/types/shared/hooks/use-capability-gate.d.ts +1 -2
  59. package/dist/types/shared/hooks/use-host-write.d.ts +1 -1
  60. package/dist/types/shared/hooks/use-unit-board.d.ts +1 -1
  61. package/docs/HANDOFF.md +3 -3
  62. package/docs/OPERATIONS.md +16 -5
  63. package/package.json +3 -3
  64. package/preset/diy.patch.yml +2 -2
  65. package/profile/isolation.patch.yml +11 -0
  66. package/skills/workbench-module-diy/BUILD.md +62 -131
  67. package/skills/workbench-module-diy/COPY.md +89 -0
  68. package/skills/workbench-module-diy/DATASOURCE.md +84 -112
  69. package/skills/workbench-module-diy/DESIGN.md +75 -109
  70. package/skills/workbench-module-diy/FAMILY.md +70 -54
  71. package/skills/workbench-module-diy/KIT.md +77 -133
  72. package/skills/workbench-module-diy/LINKAGE.md +66 -105
  73. package/skills/workbench-module-diy/PANEL.md +79 -171
  74. package/skills/workbench-module-diy/REVIEW.md +67 -81
  75. package/skills/workbench-module-diy/SKILL.md +57 -96
  76. package/skills/workbench-module-diy/STEPS.md +66 -69
  77. package/skills/workbench-module-diy/TOOLING.md +34 -51
  78. package/skills/workbench-module-diy/TOOLS.md +110 -103
  79. package/skills/workbench-module-diy/WIRING.md +51 -83
  80. package/skills/workbench-module-diy/WRITES.md +89 -142
  81. package/dist/types/app/layouts/config-sync/ConfigSyncSection.d.ts +0 -5
  82. package/dist/types/shared/api/host/diy-workshop.d.ts +0 -23
  83. package/dist/types/shared/api/host/workshop-root.d.ts +0 -16
  84. /package/dist/types/shared/{api/host/diy-workshop.test.d.ts → components/blocker-action.test.d.ts} +0 -0
@@ -1,148 +1,95 @@
1
- # 写通道:要真改东西的那一下,怎么找到、怎么确认
1
+ # 写通道:找到写命令、取得原文、确认、回读
2
2
 
3
- [DATASOURCE.md](DATASOURCE.md) 只管**读**(数据从哪来)。这一份管**写**:提交 / 发布 / 建单 / 改配置。
4
- 判域用的是同一把尺(**要不要新凭据**,见 [DESIGN.md](DESIGN.md) §0):复用他已有登录、一次调用就能改完的 ⇒ DIY;
5
- 要**新凭据** / 多步长流程(要等、中途要人、失败要接着来)/ 新服务、新进程、新依赖 ⇒ **工程域**,停下来照 [DESIGN.md](DESIGN.md) §0 那张表说清下一步。
3
+ [datasource](DATASOURCE.md) 只管读。本文件管写:提交 / 发布 / 建单 / 改配置。
4
+
5
+ 判域同 [DESIGN.md](DESIGN.md) §0:复用现有登录、一次调用能改完 → DIY;要新凭据 / 多步长流程 / 新服务或依赖 → 工程域。
6
6
 
7
7
  ## 四步
8
8
 
9
- 1. **先找现成写命令** —— `workbench_diy_recon`(`keyword=…`)现在每条命令都**标了读 / 写**:
10
- `读` · `写(可预览)` · `写(无预览档,一次就是真的)`;写命令那一行还带**入参签名**(`--id --yes=false`)。
11
- **命中现成的就别自己造**(自造等于绕过它已经处理好的登录、XSRF 与错误码)。真渲染长这样:
12
-
13
- ```
14
- opencli 自带这 1 组能力(不用装、不用点头):
15
- · antigravity(127.0.0.1) · ui · 要用你的 Chrome 登录
16
- 读 opencli antigravity cookies —— List cookies on the Antigravity renderer…
17
- …
18
- … 还有 6 条(其中写 2 条):opencli antigravity --help
19
- 直接复用:opencli antigravity cookies(这台机器上就能跑,不用装、不用点头)
20
- ```
21
-
22
- 写命令那行长这样:`写(可预览) opencli antigravity delete —— … | 入参:--id --yes=false`。
23
- 只匹配到写命令时,它最后一句会换成:先 `--help` 看入参;带 `--dryRun` / `--yes` 的**先用预览档**;
24
- **没有预览档的不许试写**(那一次就是真的)。
25
- 一条边界:**recon 只查 opencli 自带那份目录** —— `cmdb` / `coding` 这类是另装的**插件**,
26
- 它只回命令名(`opencli cmdb --help` 看全部);插件的入参走第 2 步。
27
-
28
- 2. **入参 / 出参按这个顺序查**(越靠前越可信):
29
- - **`workbench_diy_spec`**(`command='<site> <name>'`,`cmdb publish` / `cmdb/publish` 都认)——
30
- **插件与内置都能问**:它把 `opencli <site> <name> --help -f json` **原样**回,stdout 是 JSON 时另给 `spec` ——
31
- `access`(读 / 写)、`positionals`、`command_options[{name, required, help, default}]`、出参列都在里面;
32
- **不看屏、不要调试约定**。最快的一格,先问它。
33
- - recon 回的 `args`(**必填 / 默认值**)与 `preview` 标记 —— 只覆盖 opencli 自带那份目录;插件以 `_spec` 为准。
34
- - **adapter 源码是接口的一手来源**:隔离 HOME 下 `.opencli/plugins/<site>` 是**符号链接**,
35
- 指到插件包 —— 接口 URL / 方法 / cookie / XSRF 都在那儿。例:coding 的评论接口在
36
- `opencli-plugin-coding/src/issue-utils.js`(`issueCommentsApiUrl`,POST 表单),
37
- cookie 与 `X-XSRF-TOKEN` 在同一个包的 `src/request.js` 里。
38
- - `opencli <site> <name> --help`(`-f yaml` 更好读)—— 补**取值枚举**:manifest 里没有 `choices`,
39
- 枚举只在 help 文本里;`_spec` 那条路回的是 JSON,`-f yaml` 适合人眼扫。
40
-
41
- 3. **没有现成命令时,让他配合录一次**(agent 主导:你备好、他只动那一下、交回来):
42
- - `workbench_diy_record_prepare({ unit, url, doing })` —— 开一扇窗**顶到最前**(**要用户点头一次**:审批屏上写清
43
- 站点、录哪一下、落在哪、录完不替他切回来),窗里有一根浮条。请他 ① 按「开始录制」 ② 做**一次**那动作 ③ 按「结束录制」;
44
- **别让他点第二次**。`url` 必须是**这个模块读源同域**的页面 —— 模块的 `design.json` 说过读源时,跨域会**当场拒**
45
- (没说过就不拦;那一条比的是"别把别处的请求原文带进这个模块")。
46
- - **再让他按一下浮条上的「截图」**:时机是**把表填对之后、点提交之前**(提交完表单就没了)——
47
- 这一下**不另外审批**(屏幕在 prepare 那一拍已经借过)。它同时落下两样东西:一张整页图(落 `shots/rec-shot-<unit>-<n>.png`)
48
- 与一份**页面快照**(每个控件的 `name`/`id`、标签、`required`/`aria-required`/容器 class/`*` 这类必填痕迹、当时的填值、是否空、
49
- 有没有被改过)。**提交那一刻我们会自动再抓一份**,所以他忘了按也不至于空手。
50
- 他按了截图之后,浮条上会多一个「已拍 N 张」,左栏底部那句也跟着带张数。
51
- - `workbench_diy_record_read` 取那一段(他按完结束再取):回的是**清单** `rows`(每条 `index` / `key` / `method` /
52
- `url` / `status` / `ct` / `size` / `source` / `hasRequest` / `hasResponse` / `likelyWrite` / `marked`),
53
- **一条都不删、也不回体**;`expect` 只用来标 ⭐ 并把 ⭐ 排到前面。**正文每一行就把它要的两样摆出来了**:
54
- `· [0] ⭐ POST 站点/路径(捕获 · 入参 有 · 出参 40 B · at 1792583917392)` —— 开头那串就是 `key` 原文(opencli 给的,
55
- 可能带 `#2` 这种后缀),`at` 是毫秒时间戳;**没有 `key` 的钩子行**(页面钩子只记 `method`/`url`,没给 key)会写成
56
- `method url(钩子 · … · 无 key)`,那种行只有还开着时按 `index` 才取得到。要哪一条的原文再调
57
- **`workbench_diy_record_detail`**(给那一行的 `key`,或序号 `index`;**同一个 key 跨轮会重名**,
58
- 再带上那一行的 `at` 才钉得住是哪一次)——它回**入参(`request.body`)与
59
- 出参(`response body`)原文**,外加请求头(可能含凭据,别落进 `design.json`)。他还没按结束时 read 会说清"还在录"
60
- (要等就带 `waitMs`,帽 15 分钟;等不到会挂一条 notice 叫你);浮条被导航干掉过会顺手重新装上。
61
- **抓不满就重新 prepare 一场**:一场就是一个周期(开始 → 结束),结束之后那一页上的「开始」按不动了。
62
- - `workbench_diy_record_stop` 收工:停捕获、收掉那个标签、清状态;**原文另存成 `shots/rec-<unit>.jsonl.last`** ——
63
- 收工之后给 `_record_detail` 一个 `unit` 还能看那一条。**先 read(或先 detail 完)再 stop**。
64
- 左栏底部那一格是给他的状态:等出手 `[取消]` / 录制中 `[停]`,按下去只会**给你一条消息**(他不替你按工具);
65
- **录完那一档没有键** —— 你自己来取、自己收工(宿主每 3 秒看一眼那一页,看到结束就发 notice 叫你)。
66
- - 抓不到的照旧如实说:`<form>` 原生提交 / WebSocket / service worker / **别处的标签**;
67
- 页面钩子只认 `fetch` 与 XHR,缓冲上限 50 条、单条请求体截 16 KB(`sendBeacon` 2026-10-20 起抓了)。
68
- 会话捕获在浏览器那一层,盖得比钩子全、且带体 —— 两处合并去重,同名以钩子为主、缺的 key / 入参 / 出参由捕获补齐。
69
- - **兜底的老路**(那一页在别的浏览器里、或录制族用不上时):`opencli browser <你的会话名> bind`(只认**当前聚焦窗的活动标签**)
70
- 或 `open … --window foreground` 自己开一扇,**先把捕获臂上再让他动手**:`opencli browser <你的会话名> network --follow`
71
- (一次性 `network` 不会替你开捕获;每读一次就把 live 缓冲抽干一次)。取那一段用 `network --raw`
72
- (**同一次调用**才带 body;跨调用的 `--detail` 在我们这份隔离运行时落不了盘,恒 `cache_missing`),
73
- 还是没有请求体就请他打开 DevTools,把那次请求**复制成 curl** 给你。
74
- - agent 自己点只限**测试环境 / 可撤销的目标**(同下面第一条纪律)。
75
- 取证结果要固化成模块自己的写能力:`writes: true` + `needsApproval` + `approvalDetail`([TOOLS.md](TOOLS.md) §6)。
76
-
77
- 4. **文档 / 问用户** —— 接口文档、别人给的 curl 样例都行;这属于**需求确认**那一拍
78
- (照 [STEPS.md](STEPS.md) 那张表问他"你会看到什么",别问技术细节)。
79
-
80
- ## 两条硬纪律
81
-
82
- - **写命令只有少数带预览档**:隔离运行时那份 manifest 实测 **357 条写命令里只有 12 条**有
83
- `yes` / `dryRun` / `confirm`(那 12 条:antigravity `delete`/`revert` · codex `archive` ·
84
- gemini `deep-research` · grok `delete` · kimi `history-rename`/`sign-out` · pinterest 三条 delete ·
85
- slock `task-delete` · twitter `list-delete`)。**`opencli cmdb publish` / `cmdb build` 都没有预览开关**
86
- —— 调一次就是**真发布 / 真构建**。有预览档的先用预览档;没有的**不许 agent 试写**。
87
- - **要新凭据 / 多步长流程 / 新依赖 ⇒ 工程域**(同 [DESIGN.md](DESIGN.md) §0)。
88
-
89
- ## 三条写纪律(与 opencli 自己那份 `deep-recon` 对齐)
90
-
91
- 1. **授权观察一次 ≠ 授权重放。** 他点一次是"给你看这一次";**不许因为你已经看过就再放一次**。
92
- 要再放一次,就得再跟他确认一次(同一场里"再录一段"算同一件事,见下)。
93
- 2. **写后"不确定"要当一档说清,并且**不许自动重试**。命令报错不等于没写成功(可能已经写了);
94
- 这种时候停下、**先回读**把状态读回来再决定,别重放。`design.json` 的 `failure` 那一格要写到这一档。
95
- 3. **写要有配对的撤销 / 反操作**(`follow` ↔ `unfollow`、`publish` ↔ `delete`…)。opencli 自己有一条
96
- 机器判据 `write-without-delete-pair` 盯这个;你交出去的那张卡至少要在**写通道探明记录**里写清
97
- "这一步错了怎么退"(哪条命令 / 平台上哪里点)—— 那就是 `writes[].undo` 那一格,**必填**:
98
- 真没有配对就写"没有配对,一次就是真的"(**空着 = 没想过**,`design check` 会点名 `write.undo`)。
99
-
100
- ## 出参的最终确认靠**回读**
101
-
102
- 写完拿**同族的读**(或卡片那条投影)把那一格读回来,**别看"命令没报错"就当成功** ——
103
- 平台可能收下了却没生效,也可能失败在"**可能已经写了**"那一档。写进模块时,
104
- `design.json` 的 `writes[].readback` 就是这一格(哪条读 / 出参哪个字段)。
105
-
106
- ## 边界(如实)
107
-
108
- - **`browser network --detail` 在工坊会话里拿不到 body**:它依赖一份盘上缓存,默认路径落在会话可写根之外
109
- (`EPERM …/opencli/home/.opencli/cache/browser-network`,工具只发一个 `cache_warning`)⇒ 跨调用的 `--detail` 取不到。
110
- **录制族不依赖它**:它自己那份 `shots/rec-<unit>.jsonl` 就是原文(`_record_detail` 按 key 现取)。
111
- 手工取 body 的另一条路是 `workbench_diy_eval` 里的 `fetch` —— 用它自己的登录在页面里读,返回 JSON;
112
- 或把 `OPENCLI_CACHE_DIR` 指到可写处,再让 `--detail <key>` 生效。
113
- - **两套 opencli 真相**:PATH 上那份、你机器上 `~/.opencli` 那份、工作台**隔离运行时**那份
114
- 可能不是同一代。工坊一律以**隔离运行时**(`$DSH_HOME/workbench/opencli/`)为准;
115
- 核验用工具,别去看错文件。
116
- - **取值枚举只在 help 文本里**(manifest 没有 `choices`),别指望 recon 的 `args` 带它。
117
-
118
- ## 落进 `design.json`
119
-
120
- 写通道填 `writes[]`(一个动作可以打几条写:先建后发布;只有一条写也可以写成 `write: {}`)。
121
- 字段**七个必填**、一个可空;下表右边是 `design render` 渲染出来的**行名(逐字)**:
122
-
123
- | 字段 | 渲染出来的行 |
9
+ 1. **找现成写命令** —— `workbench_diy_recon`(`keyword=…`)标注每条命令的读写:
10
+ `读` · `写(可预览)` · `写(无预览档,一次就是真的)`,并给入参签名(`--id --yes=false`)。
11
+ 命中即复用(自造会绕过登录、XSRF、错误码处理)。
12
+ 只命中写命令时,末句提示:先 `--help` 看入参;带 `--dryRun` / `--yes` 的先走预览;**无预览档不许试写**。
13
+ 边界:recon 只覆盖 opencli 自带目录;`cmdb` / `coding` 等插件只回命令名,参数走第 2 步。
14
+
15
+ 2. **查入参 / 出参**(按可信度):
16
+
17
+ - `workbench_diy_spec`(`command='<site> <name>'`,`cmdb publish` / `cmdb/publish` 均可):
18
+ 返回 `opencli <site> <name> --help -f json` 原文;JSON 时另给 `spec`(`access`、`positionals`、
19
+ `command_options[{name, required, help, default}]`、出参列)。不碰屏、不需约定。
20
+ - recon 的 `args`(必填 / 默认值)与 `preview` 标记,仅覆盖自带目录;插件以 `_spec` 为准。
21
+ - adapter 源码:隔离 HOME 的 `.opencli/plugins/<site>` 指向插件包;接口 URL / 方法 / cookie / XSRF 在源码里。
22
+ - `opencli <site> <name> --help`(`-f yaml` 可读性更好):取枚举值(manifest 无 `choices`,枚举只在 help 里)。
23
+
24
+ 3. **无现成命令 → 让用户录一次**(你准备,用户执行):
25
+
26
+ - `workbench_diy_record_prepare({ unit, url, doing })`:开窗置前(**需审批一次**:站点、录哪一下、落点、
27
+ 录完不切回),装浮条。用户:① 开始录制 ② 做一次动作 ③ 结束录制。不要让用户点第二次。
28
+ `url` 必须与模块读源同域(`design.json` 声明过读源时跨域当场拒)。
29
+ - 表填好、提交前,请用户按浮条「截图」:不额外审批;产出整页图 + 页面快照(控件 `name` / `id`、
30
+ 标签、必填痕迹、填值、是否空、是否改过)。提交时会自动再抓一份。
31
+ - `workbench_diy_record_read`:取清单 `rows`(`index` / `key` / `method` / `url` / `status` / `ct` /
32
+ `size` / `source` / `hasRequest` / `hasResponse` / `likelyWrite` / `marked`),不删行、不回体;
33
+ `expect` 只标 ⭐ 并置顶。按 `key`(或 `index`)调 `workbench_diy_record_detail`:
34
+ 返回请求体与响应体原文 + 请求头(可能含凭据,不写入 `design.json`)。同 key 跨轮重名,带 `at` 定位。
35
+ 未结束时 read 会说"还在录";可带 `waitMs`(上限 15 分钟)。**一场 = 一个周期**;上一场未收工再
36
+ prepare 会当场拒(不弹审批)。
37
+ - `workbench_diy_record_stop`:停捕获、收标签、清状态,原文另存 `shots/rec-<unit>.jsonl.last`。
38
+ **先 read / detail,再 stop**。左栏键只发消息;录完无键。
39
+ - 抓不到:原生 `<form>` 提交 / WebSocket / service worker / 其他标签。页面钩子只认 `fetch` 与 XHR,
40
+ 上限 50 条、单条请求体 16 KB。兜底:`opencli browser <会话> bind`(当前聚焦窗活动标签)或
41
+ `open … --window foreground`,先 `network --follow` 再让用户操作;取 body 用 `network --raw`
42
+ (同一调用内);仍无则请用户从 DevTools 复制 curl。
43
+ - 参数与返回细则见 [FAMILY.md](FAMILY.md) §4。
44
+ - 仅测试环境 / 可撤销目标可让 agent 自己点。
45
+
46
+ 取证结果落成模块的写能力:`writes: true` + `needsApproval` + `approvalDetail`([TOOLS.md](TOOLS.md) §6)。
47
+
48
+ 4. **文档 / 问用户** —— 接口文档、curl 样例都可用于确认需求;问法照 [STEPS.md](STEPS.md),不问技术细节。
49
+
50
+ ## 硬纪律
51
+
52
+ - **预览**:先确认是否有 `yes` / `dryRun` / `confirm` 档;有则先走预览。`opencli cmdb publish` / `cmdb build`
53
+ 无预览开关,调用即真发布 / 真构建。**无预览档不许试写。**
54
+ - 要新凭据 / 多步长流程 / 新依赖 → 工程域。
55
+
56
+ ## 写纪律
57
+
58
+ 1. 授权观察一次 ≠ 授权重放。已看过也要再次确认(一场录制即一个周期)。
59
+ 2. 写后不确定单独报,不自动重试。命令报错可能已写入:停下,先回读,再决定。
60
+ `design.json` 的 `failure` 覆盖这一档。
61
+ 3. 写要有配对的撤销 / 反操作(`follow` ↔ `unfollow`、`publish` ↔ `delete`…)。`writes[].undo` 必填;
62
+ 没有就写"没有配对,一次就是真的"(空 = 未考虑,`design check` 点名)。
63
+
64
+ ## 回读
65
+
66
+ 写后用同族读或卡片投影读回该格。不以"命令没报错"判成功。`writes[].readback` 记录哪条读 / 哪个字段。
67
+
68
+ ## 边界
69
+
70
+ - `browser network --detail` 在本会话取不到 body(缓存落在可写根之外)。录制族不依赖它;
71
+ 手工取 body 用 `workbench_diy_eval` 的 `fetch`,或把 `OPENCLI_CACHE_DIR` 指到可写处。
72
+ - opencli 可能有三份(PATH、`~/.opencli`、隔离运行时);以隔离运行时 `$DSH_HOME/workbench/opencli/` 为准。
73
+ - 枚举值只在 help 文本里。
74
+
75
+ ## design.json:writes[]
76
+
77
+ 字段七个必填、一个可空:
78
+
79
+ | 字段 | 行名 |
124
80
  |---|---|
125
81
  | `command` | 哪条写(命令 / URL + 方法) |
126
- | `params` | 参数(必填 / 取值枚举 / 上限)—— 写"必填"就得带来源括号,见下 |
127
- | `credentials` | 凭据从哪来 |
128
- | `preview` | 有没有预览档(没有就写"没有,一次就是真的") |
129
- | `readback` | 写完之后怎么回读确认(哪条读 / 出参哪个字段) |
130
- | `undo` | 配对的那个撤销 / 删除(没有就写"没有配对,一次就是真的")← 第三条写纪律那一格 |
131
- | `failure` | 失败长什么样(含"可能已经写了") |
132
- | `probeCommand`(可空) | 当初探明 / 预览用的那次调用(原文) |
133
-
134
- `design render` 把它写进 README 的 **`### 写通道探明记录`** 那一节,位置在「数据源探明记录」与「验收」之间
135
- (一条一张表;多条渲染成 `#### 写 N`)。`dsh-wb-module design check` 会把空着的格点名叫出来。
136
- **没有写通道的模块不用写** —— 它不判"一条都没有",`check` 不红。
137
-
138
- `undo` 是 2026-10-19 加的(照 opencli 的 `write-without-delete-pair`):**旧模块**跑 `design check`
139
- 会多出一格 `write.undo` 的空格 —— 补一句"没有配对,一次就是真的"(或真配对那条命令)就过,别的不用动。
140
-
141
- `params` **带证据**是 2026-10-21 加的(照 `undo` 那一格同一套做法):录完一次之后,
142
- `workbench_diy_record_read` 会给到这一场落下的**图**(他按「截图」那几张)与 `workbench_diy_record_detail` 里的**捕获原文** ——
143
- 照它们写:哪一格必填,就看**图上有没有那个红 `*`**,或者看**契约**(`opencli <命令> --help -f json` 里的 `required`)。
144
- 那一格**没有 DOM 快照这条路**(2026-10-21 撤了:页面的弹层/抽屉在真机上是哈希类名,通用规则圈不住他正在填的那一层)。
145
- 判据只咬**来源有没有写出来**:`params` 里出现"必填"时,同一格必须带来源关键词之一
146
- (`已证` / `声明` / `人证` / `契约` / `未定`),否则 `design check` 点名 `write.params.source`。
147
- **旧模块**补一个括号就过 —— `(前端已证)` / `(服务端已证)` / `(人证)` / `(契约)` / `(未定)`;别的不用动。
148
- 写成 `非必填` / `不必填` 的不需要来源(那一格是"可选")。这一条**不校验来源是不是真的** —— 它逼你想过,不逼你造假。
82
+ | `params` | 参数(必填 / 枚举 / 上限);写"必填"需带来源 |
83
+ | `credentials` | 凭据来源 |
84
+ | `preview` | 有无预览档(无则"没有,一次就是真的") |
85
+ | `readback` | 回读方式(哪条读 / 哪个字段) |
86
+ | `undo` | 撤销 / 删除;无则"没有配对,一次就是真的" |
87
+ | `failure` | 失败形态(含"可能已经写了") |
88
+ | `probeCommand`(可空) | 探明 / 预览调用原文 |
89
+
90
+ `design render` 写入 README 的 `### 写通道探明记录`(位于「数据源探明记录」与「验收」之间)。
91
+ `design check` 点名空格;无写通道的模块不写。
92
+
93
+ `params` 来源:依据 `workbench_diy_record_read` 的截图(必填红星)或契约(`--help -f json` 的 `required`)。
94
+ 出现"必填"时须带来源关键词之一:`已证` / `声明` / `人证` / `契约` / `未定`,否则报 `write.params.source`。
95
+ `非必填` / `不必填` 不要求来源。判据只查是否写下来源。
@@ -1,5 +0,0 @@
1
- import type { Translate } from '@dsh-workbench/shared';
2
- export interface ConfigSyncSectionProps {
3
- readonly t: Translate;
4
- }
5
- export declare function ConfigSyncSection({ t }: ConfigSyncSectionProps): JSX.Element;
@@ -1,23 +0,0 @@
1
- export interface WorkshopModule {
2
- readonly unit: string;
3
- readonly name: string;
4
- readonly description: string;
5
- readonly dir: string;
6
- readonly installed: boolean;
7
- }
8
- export declare function insideWorkshop(root: string, target: string): boolean;
9
- export declare function workshopModules(packagesDir: string, installed?: readonly string[]): readonly WorkshopModule[];
10
- export declare function readDesignOfModule(dir: string): unknown;
11
- export interface WorkshopSync {
12
- readonly state: 'ok' | 'syncing' | 'failed';
13
- readonly version: string;
14
- readonly at: string;
15
- readonly reason?: string;
16
- }
17
- export declare function workshopSyncOf(workshopRoot: string): WorkshopSync | undefined;
18
- export interface WorkshopToolchain {
19
- readonly core: string;
20
- readonly moduleTools: string;
21
- readonly shared: string;
22
- }
23
- export declare function workshopToolchainOf(workshopRoot: string): WorkshopToolchain | undefined;
@@ -1,16 +0,0 @@
1
- import type { DshHostContext } from '@dsh-workbench/shared';
2
- export interface WorkshopRoot {
3
- readonly root: string;
4
- readonly packagesDir: string;
5
- readonly title: string;
6
- }
7
- /**
8
- * 工坊**自己的家**(`$DSH_HOME/workbench/diy`)—— 宿主启动时就是按它把工坊登记成工作区的。
9
- * DIY 会话的工坊根取这一份,**不随会话 cwd 漂**:cwd 一离开工坊(用户把自己的项目设成工作区),
10
- * 从 cwd 往上找会撞上任意一个"带 `packages/` 的仓库",于是模块列表、`shots/` 落点、装机名单全跟着变样。
11
- * 这一档拿不到(没有 `dshHomePath` 服务)时才退回 cwd 那套。
12
- * @param ctx - 宿主上下文(要从里面取 `dshHomePath`)。
13
- * @returns 工坊的家;取不到给 `null`。
14
- */
15
- export declare function workshopHomeOf(ctx: DshHostContext): WorkshopRoot | null;
16
- export declare function workshopRootOf(ctx: DshHostContext, workspace: string | null): Promise<WorkshopRoot | null>;