@dsh-workbench/core 1.1.13 → 1.1.14-beta.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.
- package/README.md +5 -3
- package/bin/seed-workshop-windows.mjs +10 -13
- package/client.js +158 -132
- package/dist/client/client.body.js +158 -132
- package/dist/client/index.js +158 -132
- package/dist/host/index.js +85 -40
- package/dist/types/app/client.d.ts +4 -1
- package/dist/types/kernel/contract/index.d.ts +2 -1
- package/dist/types/kernel/host/mount-units.d.ts +2 -1
- package/dist/types/shared/api/host/git-exec.d.ts +2 -2
- package/dist/types/shared/hooks/runtime-queries.d.ts +2 -1
- package/dist/types/shared/hooks/use-platform.d.ts +13 -0
- package/dist/types/shared/hooks/use-runtime-capabilities.d.ts +3 -1
- package/package.json +4 -4
- package/scripts/create-workbench.mjs +7 -4
- package/scripts/seed-workshop.sh +45 -7
- package/skills/workbench-module-diy/BUILD.md +33 -24
- package/skills/workbench-module-diy/DATASOURCE.md +3 -2
- package/skills/workbench-module-diy/FAMILY.md +1 -1
- package/skills/workbench-module-diy/FLOW.md +33 -7
- package/skills/workbench-module-diy/KIT.md +3 -1
- package/skills/workbench-module-diy/PANEL.md +7 -6
- package/skills/workbench-module-diy/REVIEW.md +9 -8
- package/skills/workbench-module-diy/SKILL.md +3 -2
- package/skills/workbench-module-diy/STEPS.md +1 -1
- package/skills/workbench-module-diy/TOOLS.md +56 -1
- package/skills/workbench-module-diy/WIRING.md +2 -0
- package/skills/workbench-module-diy/WRITES.md +1 -1
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
| 拿不准 | 先一次性,跑通后用户再要固化 |
|
|
21
21
|
|
|
22
22
|
- **一次性**:不建模块、不写 flow;直接用现有工具 / 命令跑完,告诉用户「这次直接跑,没固化」。
|
|
23
|
-
- **固化**:进入第 2
|
|
23
|
+
- **固化**:进入第 2 节;先画步骤链,再问一次「按这个固化吗?」。
|
|
24
24
|
|
|
25
25
|
不要问「要不要用 FlowDefinition / 怎么写代码 / 选哪个引擎」——这些是实现,用户不决定。
|
|
26
26
|
|
|
@@ -29,15 +29,36 @@
|
|
|
29
29
|
一条 workflow = 模块宿主半侧的一份 `FlowDefinition` + 动作表 + 长任务 + 工具(可选卡片)。
|
|
30
30
|
**v0 没有 flow 仓库,固化就是写进模块**,不是存一份 JSON。
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
跑起来用户看到一条长任务行(五态与停止钮见 [TOOLS.md](TOOLS.md) §9):
|
|
33
33
|
|
|
34
|
-
- 一条长任务行:到哪步、重试第几次、要登录、可停止、失败原因。
|
|
35
34
|
- 写平台前有一次审批(模块清单 `writes: true` + `needsApproval`)。
|
|
36
35
|
- 工具返回 `runId`;再调可看同一条。
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
固化前给用户看一张 ASCII 步骤链 + 一句确认。画,不写句子;一张图 = 一条流程:
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
```
|
|
40
|
+
⚠ 写平台:开跑前先点一次「允许一次」;拒绝就不跑
|
|
41
|
+
|
|
42
|
+
发布(输入:环境 in.env)
|
|
43
|
+
|
|
44
|
+
① 拉代码 ── 读当前版本
|
|
45
|
+
│
|
|
46
|
+
▼
|
|
47
|
+
② 构建 ── 每 5s 查一次 · 最多 5 次
|
|
48
|
+
│ 查到 done 往下;超时 → 失败停在这
|
|
49
|
+
▼
|
|
50
|
+
③ 发布 ── 写平台 · 失败重试 2 次(每次隔 3s)
|
|
51
|
+
│
|
|
52
|
+
▼
|
|
53
|
+
● 发布完成 · 随时可停 · 再调工具按 runId 看同一条
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- 步骤名用长任务行会显示的那句;① ② ③ 的流向就是 `steps` 的顺序。
|
|
57
|
+
- 等 / 轮询 / 重试写在那一步的箭头下:每隔多久、最多几次、超时往哪走(`maxMs: 0` 写「不限时」)。
|
|
58
|
+
- 写平台的步骤只标「写平台」;`⚠` 与审批词写在开跑那一行,审批屏另画([DESIGN.md](DESIGN.md) §3)。
|
|
59
|
+
- 逐项、子流程、登录、分支在动作里,图上只标一句「动作里:…」,不画分支树。
|
|
60
|
+
- `when` 写「不满足就跳过」;`stopWhen` 写「命中就收工」。
|
|
61
|
+
- 用户改哪步就改图再问;图下只留「按这个固化吗?」,不补解释。
|
|
41
62
|
|
|
42
63
|
## 3 怎么写
|
|
43
64
|
|
|
@@ -82,11 +103,16 @@ export const face: UnitModuleFace = {
|
|
|
82
103
|
|
|
83
104
|
在模块 `mount` 里:
|
|
84
105
|
|
|
85
|
-
- `const runs = deps.longTasks.create({ key, run, view, outcome, stopped })`;`run` 调 `deps.flow.run`,把 `onStep` 映射到长任务的 `onStep`;返回 `status === 'failed'` 时 throw,让注册表标 failed
|
|
86
|
-
- `registerTools`
|
|
106
|
+
- `const runs = deps.longTasks.create({ key, run, view, outcome, stopped })`;`run` 调 `deps.flow.run`,把 `onStep` 映射到长任务的 `onStep`;返回 `status === 'failed'` 时 throw,让注册表标 failed。默认映射用 `longTaskStepOf(event)`(`@dsh-workbench/shared/host` 导出,`running`/`ok`/`skipped`/`failed`/`needs-login` 各对应一种 `kind`);要改文案或过滤步骤就自己写映射。
|
|
107
|
+
- `registerTools()`:**调用时才注册**,返回一组清理函数;里面 `tools.register(tool)`(`execute` 里 `runs.start`,返回 `{ ok, runId, status, text }`;再按 `runId` 查)。
|
|
87
108
|
- 写平台的工具:清单 `writes: true` + `needsApproval` / `approvalDetail`;动作里不要自己再问一遍。
|
|
88
109
|
- 校验:`deps.flow.check(flow, actions)`;有问题先修,不装。
|
|
89
110
|
|
|
111
|
+
`registerTools()` 的返回值是**清理函数数组**(外壳卸载 / 热换时逐个调),不是“注册函数数组”。
|
|
112
|
+
清单里每一条 `dsh.workbench.tools` 必须在这里注册一把、名字逐字一致;没有工具就 `() => []`。
|
|
113
|
+
可跑的完整样板:`dsh-wb-module init --template diy` 生成的模块里那把 `__UNIT___run`
|
|
114
|
+
(工具 + 长任务 + 动作通道三处共用一个 `startRun`)。
|
|
115
|
+
|
|
90
116
|
### v0.1 能用的形状
|
|
91
117
|
|
|
92
118
|
| 需要 | 写法 |
|
|
@@ -52,6 +52,7 @@ h(Rows, null,
|
|
|
52
52
|
- `ActivityBlock` / `ActivityLine` / `ActivityAction`:活动记录;时间用它。
|
|
53
53
|
- `LongTaskRow`:长任务行(五态);不画进度条。传 `stop` 需宿主响应 signal 且 peer 下限到位([TOOLS.md](TOOLS.md) §9)。
|
|
54
54
|
- `ApprovalDetail` / `ApprovalPlan`:审批屏两格;形状见 [DESIGN.md](DESIGN.md) §3 末节。
|
|
55
|
+
- 路径显示:`shortenPath` 缩主目录(macOS / Linux / Windows 都认),`pathBase` 取末段(`/` 与 `\` 都认)。
|
|
55
56
|
|
|
56
57
|
## 4 表单
|
|
57
58
|
|
|
@@ -93,6 +94,7 @@ h(Form<{ branch: string }>, {
|
|
|
93
94
|
| 整卡起步(gate + 忙 + 探针 + 上报 + blocker) | `useUnitBoard`(`read(gated)` 内调 `useApiResource`) |
|
|
94
95
|
| 单点 / 整表能力门 | `useCapabilityGate` / `useCapabilityMap` |
|
|
95
96
|
| 写(组件内不 fetch)/ 长任务轮询 | `useHostWrite` / `useLongTask`(`LongTaskRow`;`longTaskIsLive`;写后 `refresh()`) |
|
|
97
|
+
| 平台事实(Desktop / web、宿主 OS、能力) | `usePlatform`:返回 client(浏览器侧现算)与 host(来自 health,可能还没读到,按未知处理) |
|
|
96
98
|
|
|
97
99
|
取数链见 [LINKAGE.md](LINKAGE.md) §8;配置见 [PANEL.md](PANEL.md) §5。
|
|
98
100
|
|
|
@@ -127,7 +129,7 @@ h(FormRows, null,
|
|
|
127
129
|
- `Link`:唯一外链(`h(Link, { href, children })`);不去箭头、文案不带 `→`、不手写 `<a>`。
|
|
128
130
|
- `SettingsSection` / `Stack` / `BlockerState` / `Tip`:设置节 / 竖排 / 阻断屏 / Tooltip(纯图必须有它或 `aria-label`)。
|
|
129
131
|
- 图标:`IconPanelScreen` / `IconModuleMark` / `IconNpm` / `IconOpencli`;其余从 dsh `Icon*Regular` 取,不自绘。
|
|
130
|
-
- 真机造不出的状态:`
|
|
132
|
+
- 真机造不出的状态:`src/components/__tests__/OverviewCard.test.ts` 覆盖五态。
|
|
131
133
|
|
|
132
134
|
## 7 规则
|
|
133
135
|
|
|
@@ -66,7 +66,7 @@ return {
|
|
|
66
66
|
浏览器侧:写走 `prefs`,读取仍走模块只读口。布局与内边距用外壳默认(`Field` / `TextField`),不必为可读性写 CSS。
|
|
67
67
|
|
|
68
68
|
```tsx
|
|
69
|
-
const write = useHostWrite({ channel: 'prefs', resource: 'your-module' });
|
|
69
|
+
const write = useHostWrite({ channel: 'prefs', resource: 'your-module', networkText: '网络不通,稍后重试' });
|
|
70
70
|
write.send({ ignored, timeoutSeconds, workspace }); // 控件:Field + TextField / ChoiceGroup;容器 SettingsSection;保存 SaveBar
|
|
71
71
|
```
|
|
72
72
|
|
|
@@ -97,14 +97,15 @@ write.send({ ignored, timeoutSeconds, workspace }); // 控件:Field + TextFi
|
|
|
97
97
|
|
|
98
98
|
## 7 状态矩阵
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
读到但空 /
|
|
100
|
+
状态全集(界面状态,共 9 个):没有绑定 / 未接入 / 分不清是哪一份 / 正在读 / 有数据 / 正在做 /
|
|
101
|
+
卡住(登录、权限、超时、能力未装)/ 读到但空 / 数字是上一轮。`design.json` 只落 5 个状态族
|
|
102
|
+
(`idle` / `loading` / `ready` / `empty` / `unreadable`),这 9 个界面状态按族填。
|
|
102
103
|
|
|
103
104
|
每格三列:看到什么(哪句话、哪个画面、哪颗点)/ 能做什么(去哪补、点哪、重试)/ agent 能接着做什么(可照做的一句)。
|
|
104
105
|
|
|
105
106
|
规则:每句可照做;平台没给的格不留占位;读不到就说读不到并给原因,不显示 0;有确定答案就不打扰。
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
真机造不出的状态也要在设计里画;卡片五态测试在 `src/components/__tests__/OverviewCard.test.ts`
|
|
108
|
+
(`check --only cards` 用八种外壳侧输入各跑一遍,只判"是否干净退化",不判画的是哪一态)。
|
|
108
109
|
|
|
109
110
|
### 7.1 图例
|
|
110
111
|
|
|
@@ -117,7 +118,7 @@ write.send({ ignored, timeoutSeconds, workspace }); // 控件:Field + TextFi
|
|
|
117
118
|
|
|
118
119
|
## 8 范例
|
|
119
120
|
|
|
120
|
-
`template-diy
|
|
121
|
+
`template-diy/`(唯一模板:真数据源 + 五态卡 + 可跑流程 / 工具样板)。
|
|
121
122
|
|
|
122
123
|
## 9 kit 不够时
|
|
123
124
|
|
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
| 判据 | 检查 | 修法 |
|
|
6
6
|
|---|---|---|
|
|
7
|
-
| `contracts` | 清单 ↔ 代码 ↔ `design.json` 漂移;dsh 组合期不校验清单 | 按报错改:`unit` 重名换名;`dsh.workbenchFaces`
|
|
7
|
+
| `contracts` | 清单 ↔ 代码 ↔ `design.json` 漂移;dsh 组合期不校验清单 | 按报错改:`unit` 重名换名;`dsh.workbenchFaces` 两个源码入口;至少保留 `build` / `typecheck` / `test` / `selfcheck` 四个脚本(模板共 8 个);`private: true`。`dsh.workbench.tools` 与 `registerTools()` 一致;`design.json` 对键名;生成物过期跑 `sync` |
|
|
8
8
|
| `protocol` | `dsh.workbench` 版本 / 形状 / 多余键(外壳静默忽略生字段) | 补 `"apiVersion": 3`;`unit` / `title` / `card` / `tools` / `host` 写全(名字是 `{ zh, en }` 字面量;无卡片 `null`、无工具 `[]`);删协议外键(`faces` 在 `dsh.workbenchFaces`;不写 `scope`) |
|
|
9
9
|
| `bundles` | 运行时互串:浏览器产物含 node 内置 / 宿主产物含 DOM、react | 不 import 对方那侧 |
|
|
10
10
|
| `source` | 非种子 `@deepseek-ai/*`;宿主碰 dsh 浏览器包;`@/` 指外壳;根入口取运行值;客户端引 `/host`;**手写进程 / PATH / 文件锁 / 状态原子写**(import 首选库放行) | 宿主只用 Node 侧;种子词仅在 client 可达文件;`@/` 只指自己 `src/`;运行值:浏览器 `kit`、宿主 `shared/host`;进程/锁/状态写交给外壳 |
|
|
11
11
|
| `primitives` | 声明 `external` 但产物无物证(原语被内联) | `dsh.client.external` 声明;devDependency 精确版对齐;产物中为 `require(...)` |
|
|
12
12
|
| `kit` | 用了 peer 下限外壳没有的成员(首帧 `Element type is invalid`) | 只用 peer 范围内成员;下限抬到实际使用版 |
|
|
13
|
-
| `cards` |
|
|
13
|
+
| `cards` | 八种外壳侧输入 × `zh` / `en` 下崩溃 / 空白 / 脏值 | 五态可画;外层 `Card`;卡片自己用到的文案键双语齐(名字走清单 `title`,不再是卡片键)。不断言具体态(归 `plugin.test.ts`) |
|
|
14
14
|
| `standalone` | 依赖工作台源码才能构建 | 不引用工作台源码;`tsconfig.paths` 用相对路径 |
|
|
15
15
|
| `markers` | 私有源 / 私网地址 / 内网域名进入公开包 | 不进包;配置落到模块配置面;组织特有的词表由 `DSH_WB_INTERNAL_MARKERS` 提供 |
|
|
16
16
|
| `alias` | `@/` 指向工作台源码 | `@/` 只指自己 `src/` |
|
|
17
17
|
| `style` | 模块定义 `.wb-*`;手写行 / 操作区 / 表单(F1–F4);`--dsw-*` / `--wb-*` 不在现读的令牌清单 | 样式走 `*.module.css`(无 `wb-` 前缀);借外壳类用 `:global(.wb-…)`;行 / 操作区用 `FormRow(s)` / `FormActions`,表单用 `Form`([KIT.md](KIT.md) §5)。F4:裸 `<form` 或手写 `wb-formRow` / `wb-formRows` / `wb-field`。令牌名现查:`workbench_diy_components` `scope: 'tokens'` |
|
|
18
|
-
| `arch` | 结构:巨文件 / 反向依赖 / 跨运行时 / 表外目录 /
|
|
19
|
-
| `lint` | 语法:`as any` / `console` / `debugger` / 颜色字面量 / `!important` / **直接读 `process.platform` / `versions.electron` / `dshDesktop` / `
|
|
18
|
+
| `arch` | 结构:巨文件 / 反向依赖 / 跨运行时 / 表外目录 / 模型无测试 / 测试住 `__tests__`;依赖白名单(含 execa / which / proper-lockfile / write-file-atomic / dayjs / zod)+ `shell-quote` / `shelljs` / `zx` deny;能力首选 dayjs / structuredClone / URLSearchParams / zod(日期已是硬门禁) | 见「第十二条」 |
|
|
19
|
+
| `lint` | 语法:`as any` / `console` / `debugger` / 颜色字面量 / `!important` / **直接读 `process.platform` / `versions.electron` / `dshDesktop` / `navigator.userAgent`** / react-hooks | 见「第十三条」 |
|
|
20
20
|
|
|
21
21
|
## 第十二条 `arch`
|
|
22
22
|
|
|
@@ -35,7 +35,8 @@ export default moduleArch();
|
|
|
35
35
|
| `S21` 反向依赖 | 低层引高层(组件引 `../host`) | 被引项下沉 `model/`;只依赖层号 ≤ 自身 |
|
|
36
36
|
| `S23` 跨运行时 | 宿主 import `src/components/**` 或反向 | 组件归 client 面;两侧经服务名 |
|
|
37
37
|
| `S16` 超长 | 文件 >200 行 / 函数 >80(测试豁免) | 拆;或传 `fileLines` / `functionLines`;单文件用 `exceptions` |
|
|
38
|
-
| `
|
|
38
|
+
| `S74` 测试不在 `__tests__` | 测试文件散在 `src/` 里 | 挪进同目录的 `__tests__/`,相对路径的 import 各退一级 |
|
|
39
|
+
| `M08` 无测试 | `src/model/**` 无配对测试 | 补 `src/model/__tests__/X.test.ts` |
|
|
39
40
|
| `D12` 刻度外值 | 手写不在刻度的尺寸 | 用 `--dsw-*` 或刻度值 |
|
|
40
41
|
| `D09` `!important` | 只允许 `src/components/vendor/` | 改选择器 / 层级 |
|
|
41
42
|
| `D17` 未使用类 | `*.module.css` 定义未使用 | 删除 |
|
|
@@ -44,7 +45,7 @@ export default moduleArch();
|
|
|
44
45
|
|
|
45
46
|
```js
|
|
46
47
|
export default moduleArch({
|
|
47
|
-
layers: {
|
|
48
|
+
layers: { data: 3 },
|
|
48
49
|
roles: [{ id: 'lib:platform', pattern: 'src/platform/**', layer: 1 }],
|
|
49
50
|
exceptions: [{ rule: 'S16', glob: 'src/host/service.ts', reason: '…' }],
|
|
50
51
|
});
|
|
@@ -71,7 +72,7 @@ export default moduleLint({ rootDir: import.meta.dirname });
|
|
|
71
72
|
| `no-explicit-any` | `as any` / `: any` | 写真实类型;或在 `moduleLint({ rules })` 放行 |
|
|
72
73
|
| `no-console` | `src/**` 的 `console.log` / `info` / `debug`(`warn` / `error` 放行) | 删除;`scripts/**` 不判 |
|
|
73
74
|
| `no-debugger` | 残留 `debugger` | 删除 |
|
|
74
|
-
| `no-restricted-syntax` | 颜色字面量(`#ff0000` / `rgb(` / `hsl(`)、字符串 `!important
|
|
75
|
+
| `no-restricted-syntax` | 颜色字面量(`#ff0000` / `rgb(` / `hsl(`)、字符串 `!important`、平台原始探测(`process.platform` / `versions.electron` / `dshDesktop` / `navigator.userAgent`) | 用令牌与 `*.module.css`;平台差异走能力面:**宿主面读 `deps.surface`(`HostSurface`),浏览器面读 `kit.hooks.usePlatform()`**,宿主/浏览器面分开写 |
|
|
75
76
|
| `react-hooks/*` | 条件 hook / 渲染期写 ref / 漏依赖 | 提到顶层;副作用进 `useEffect`;补依赖 |
|
|
76
77
|
| `no-unused-vars` | 死代码(`^_` 放行) | 删除或改 `_x` |
|
|
77
78
|
| 其他 `recommended` / `react/*` | 语法规则 | 按 eslint 原文 |
|
|
@@ -101,7 +102,7 @@ export default [
|
|
|
101
102
|
1. `workbench_diy_panel`:每卡的读取状态(宿主码与原文)、是否崩过(原因、次数)。有结论即止。
|
|
102
103
|
2. 看卡片:`workbench_diy_screenshot` / `_html` / `_find` / `_eval`,作用于用户当前页的该卡(`unit=…`)。
|
|
103
104
|
这一族(14 把 + `logs_*`)需先 `workbench_diy_debug_start`(`unit=…`,审批一次),否则拒绝;
|
|
104
|
-
`_panel` / `_status` / `read=` 档不需要。用完 `
|
|
105
|
+
`_panel` / `_status` / `read=` 档不需要。用完 `_debug_pause`,收工 `_debug_stop`。
|
|
105
106
|
3. `workbench_diy_status`(`unit=…`):看"起得来"行(装配错误 / 声明被拒原文)。
|
|
106
107
|
4. 直接请求路由:`curl '<工作台地址>/workbench/api/<unit>/<route>'`(默认 `http://127.0.0.1:3081`)。
|
|
107
108
|
接口对 → 渲染侧;接口错 → 宿主侧(按 [DATASOURCE.md](DATASOURCE.md) 重探)。需要在页面内请求时用
|
|
@@ -40,7 +40,8 @@ description: 在工作台里把当前面板调明白,或者给它造一块新
|
|
|
40
40
|
→ `dsh-wb-module sync` → `data.request`),配方盖不住的写 `custom: { why }`;写三态。
|
|
41
41
|
写操作先读 [WRITES.md](WRITES.md) 四步 + 执行体;有写工具就把审批屏画进 ASCII([DESIGN.md](DESIGN.md) §3 末节)。
|
|
42
42
|
4. **套模板** —— [BUILD.md](BUILD.md) §1–§2:`pnpm exec dsh-wb-module init <unit> --template diy`,
|
|
43
|
-
先把 `design.json`
|
|
43
|
+
先把 `design.json` 改成问出来的那份,再改数据源与渲染。依赖由 setup 装好,一般不用再装;
|
|
44
|
+
确实要装就在**工作区根**跑 `pnpm install`(会话沙箱里跑会 EPERM:link 目标在可写根之外)。不从零写。
|
|
44
45
|
改渲染时文案按 [COPY.md](COPY.md):先判读者(卡片给人 / 描述给 agent / 原始输出进 detail)。
|
|
45
46
|
5. **过门禁** —— `dsh-wb-module build` + `check` + `design check`;红了自己修([REVIEW.md](REVIEW.md)),
|
|
46
47
|
不把报错贴给用户。
|
|
@@ -83,7 +84,7 @@ description: 在工作台里把当前面板调明白,或者给它造一块新
|
|
|
83
84
|
1. `dsh-wb-module check --only <判据>` 的报错原文。
|
|
84
85
|
2. kit / dsh 原语 / CSS 令牌:`workbench_diy_components`(DIY 会话;令牌给 `scope: 'tokens'`,现读现给);
|
|
85
86
|
工程域 `check --only kit` / `--only primitives`。
|
|
86
|
-
3. 模板:`node_modules/@dsh-workbench/module-tools/template-diy
|
|
87
|
+
3. 模板:`node_modules/@dsh-workbench/module-tools/template-diy/`。
|
|
87
88
|
4. 安装包的类型面:`node_modules/@dsh-workbench/core/dist/types/**`;本指引:`node_modules/@dsh-workbench/core/skills/workbench-module-diy/**`。
|
|
88
89
|
|
|
89
90
|
## 硬约束
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
取值范围、给错怎么改。
|
|
59
59
|
3. **全场景**:正常 / 没有 / 分不清是哪一份(不许猜)/ 参数错 / 超上限 / 能力未装好 / 要登录或超时 /
|
|
60
60
|
还有下一批 / 截断(说清截了什么、多少)/ 没有当前项目。
|
|
61
|
-
4.
|
|
61
|
+
4. **写操作两拍**:先预览(说清将要做什么;画法见 [TOOLS.md](TOOLS.md) §5),再执行。预览让用户判断"要不要做",不是"要不要允许"。
|
|
62
62
|
5. **点头范围**:改平台 / 改这台机器 / 改面板。点头时展示这次具体发生什么(对象、版本、环境);
|
|
63
63
|
说不清就不问,停下让 agent 去查。
|
|
64
64
|
|
|
@@ -50,6 +50,20 @@
|
|
|
50
50
|
1. 预览:说清对象、值、去向,等确认。用户判断"要不要做"。
|
|
51
51
|
2. 执行:确认后动平台,回报结果。
|
|
52
52
|
|
|
53
|
+
拍一在对话里给用户看的是这样一张小卡(拍二由审批屏答「允许吗」,见 [DESIGN.md](DESIGN.md) §3):
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌─ 将要提交 ─────────────────────────────────┐
|
|
57
|
+
│ 对象 订单 #2024-0815 │
|
|
58
|
+
│ 现值 待审核 → 已通过 │
|
|
59
|
+
│ 去向 订单平台 · 预发环境 │
|
|
60
|
+
│ 影响 1 单;可撤销(撤回审核) │
|
|
61
|
+
└────────────────────────────────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- 值现读;读不到写「读不到」并说清还差什么,不猜、不写 0。
|
|
65
|
+
- 只说这次发生什么,不写「这个操作会改数据」。
|
|
66
|
+
|
|
53
67
|
一个动作一条链路:用户按按钮与 agent 调用是同一件事;重复发起要幂等(先查是否已有,进行中则续看)。
|
|
54
68
|
用户自按入口不点头:最小确认条(将要做什么 + 取消 / 执行),按下变"正在做…",失败留在条内说明。
|
|
55
69
|
|
|
@@ -67,7 +81,7 @@
|
|
|
67
81
|
- `key` 用 lowerCamelCase;跑 `dsh-wb-module sync` 生成 `src/declared-tools.ts`,代码写
|
|
68
82
|
`DECLARED_TOOLS.rebuild.name`。工具名字面量只留清单一处;键错编译错,生成物过期 / 半写 / 又写字面量都红。
|
|
69
83
|
- `needsApproval` 返回:
|
|
70
|
-
`{ kind: 'read' }` 不问;`{ kind: 'ask', question, fallback }` 要问;
|
|
84
|
+
`{ kind: 'read' }` 不问;`{ kind: 'ask', reason, question, fallback }` 要问;
|
|
71
85
|
`{ kind: 'deny', reason }` 拒绝(reason 交给 agent;只放策略同步可判的事实)。`writes: true` 未认领 = deny。
|
|
72
86
|
`question` / `fallback` 需 zh / en。
|
|
73
87
|
- `approvalDetail` 拿不到材料时返回 `{ blocked: '…' }` = 不弹。标题与详情形状见 [DESIGN.md](DESIGN.md) §3 末节:
|
|
@@ -129,6 +143,8 @@
|
|
|
129
143
|
- `sources` 按顺序试(本地 → 私有 → 公共)。没写 `sources` 就是「我自己装,你只帮我判」——外壳只探不代装。
|
|
130
144
|
- `bin` 想让人一键装,就写 `install.line`(一条能直接粘进终端的命令,`platforms` 可限定平台);
|
|
131
145
|
不写就只显示「缺这条命令」,按钮都不会有。`docs` 是给人和 agent 看的补充链接。
|
|
146
|
+
跨平台要么按 `darwin` / `linux` / `win32` 各写一条 `install.platforms`,要么只写你那一个平台并说明;
|
|
147
|
+
别让 Windows 用户看到 `brew install`。`install.kind: "npm"` 则由外壳装进隔离运行时并接上 PATH。
|
|
132
148
|
- `lib` 自己起运行时的命令(比如发布编排库自己 `execFile('opencli')`)就写 `runs: ["opencli"]`:
|
|
133
149
|
外壳把它手上那份「跑 opencli」的执行器注入进去(库侧约定暴露 `setOpencliRunner`),
|
|
134
150
|
于是编排与面板用同一份 opencli(同一套插件、同一份登录态)。不写 `runs` 就按库自己的 PATH 找。
|
|
@@ -152,8 +168,24 @@ longTasks.create({ key, run, step, outcome, view, stopped })
|
|
|
152
168
|
```
|
|
153
169
|
|
|
154
170
|
- 来源:在工具里 `runs.start({ …, session: deps.sessionIdOf(exec) ?? undefined })`。不记 = 用户按的 → 停止需审批。
|
|
171
|
+
- 流程事件默认用 `longTaskStepOf(event)`。
|
|
155
172
|
- 浏览器侧:`useLongTask` → `feed.runs` / `feed.stop(id)` / `feed.stopping` / `feed.stopFailed`;
|
|
156
173
|
画 `LongTaskRow`(五态:`running` / `needs-login` / `stopped` / `ok` / `failed`)。
|
|
174
|
+
|
|
175
|
+
五态长这样(自上而下:跑着 / 要登录 / 好了 / 失败 / 按停):
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
● 正在发布(2/3) [⏹]
|
|
179
|
+
● 要登录腾讯云 [登录 →]
|
|
180
|
+
● 发布完成 [日志 →]
|
|
181
|
+
● 发布失败
|
|
182
|
+
站点回的是 HTTP 403
|
|
183
|
+
▸ 步骤 ▸ 原文
|
|
184
|
+
● 发布已停止(用户按停)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
- 链接在行尾;失败才展开「步骤」「原文」两块。
|
|
188
|
+
|
|
157
189
|
- 停止:`run` 收到 `signal` 被 abort = 有人按停止;在循环点与每条子命令前后查 `signal.aborted`。
|
|
158
190
|
不认 signal 就不要画停止钮。画钮传 `stop`(`onStop: () => feed.stop(run.id)`、`busy: feed.stopping === run.id`、
|
|
159
191
|
`failed: feed.stopFailed`、`label: 停止任务 {label}`、`askLabel: '确认停止'`);失败文案画在行下,
|
|
@@ -166,6 +198,29 @@ longTasks.create({ key, run, step, outcome, view, stopped })
|
|
|
166
198
|
- 左栏 loading 点由外壳按 `live()` 驱动,模块不做。
|
|
167
199
|
- 用 `stop` / `session` / 外壳长任务工具需把 `@dsh-workbench/core` peer 下限抬到含它们的版本(`check --only kit` 查)。
|
|
168
200
|
|
|
201
|
+
长任务与工具在 `mount` 里长这样(类型从 `@dsh-workbench/core/contract` 取,`TEXT_OUTPUT` 从 `@dsh-workbench/shared/host` 取):
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
mount(deps) {
|
|
205
|
+
const runs = deps.longTasks?.create<LongTaskBase>({ key, run, step, outcome, view, stopped });
|
|
206
|
+
const tool: DshToolDefinition = {
|
|
207
|
+
name: RUN_TOOL, description: '…', parameters: { type: 'object', properties: {} },
|
|
208
|
+
output: TEXT_OUTPUT, async execute(args, exec) { /* runs.start(...) → { ok, runId, text } */ },
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
routes: {},
|
|
212
|
+
registerTools: () => {
|
|
213
|
+
const tools = deps.ctx.get<DshToolRegistry>('tools');
|
|
214
|
+
return tools === undefined ? [] : [tools.register(tool)];
|
|
215
|
+
},
|
|
216
|
+
...(runs === undefined ? {} : { longTasks: runs }),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`registerTools()` 是**调用时才注册**、返回清理函数;工具名必须与 `dsh.workbench.tools` 一字不差,
|
|
222
|
+
没有工具就 `() => []`。可跑样板:`dsh-wb-module init` 生成的模块。
|
|
223
|
+
|
|
169
224
|
## 9.1 多步流程(workflow)
|
|
170
225
|
|
|
171
226
|
多步、要等、要重试、要取消、以后还要跑 → 先按 [FLOW.md](FLOW.md) 问用户是否固化。
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
| 需要 | 来源 |
|
|
8
8
|
|---|---|
|
|
9
9
|
| 宿主侧纯函数 / 常量 | 优先工具 / 挂载里的 `deps`(`HostKit`);模块顶层常量仍从 `@dsh-workbench/shared/host` 取(`dependencies`) |
|
|
10
|
+
| 宿主平台事实(deployment / 能力 / 宿主机工具链) | `mount(deps)` 里的 `deps.surface`(`HostSurface`):工具(`registerTools`)在闭包里用它;不要自己读 `process.platform` |
|
|
11
|
+
| 浏览器平台事实(Desktop / web、hostOs、能力) | `kit.hooks.usePlatform()`:`client` 现算、`host` 来自 health(没读到按未知处理) |
|
|
10
12
|
| 浏览器侧 hooks / 组件 / 图标 / 文案工具 | `@dsh-workbench/core/client` 的 `kit` |
|
|
11
13
|
| kit 没有的 dsh 控件 / 图标 | `@deepseek-ai/dsh-client-ui-primitives`(`dsh.client.external` + 精确版 devDependency;[KIT.md](KIT.md) §8) |
|
|
12
14
|
| 类型 | `import type` |
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
| `failure` | 失败形态(含"可能已经写了") |
|
|
109
109
|
| `probeCommand`(可空) | 探明 / 预览调用原文 |
|
|
110
110
|
| `key` + `recipe`(可空,成对) | 调用形状(配方):写走 `data.submit` 时填,`sync` 把它和读一起生成进 `src/datasource.ts`(`DATASOURCE.<key>`)。`key` 不许和读撞,撞了 `design check` 红 |
|
|
111
|
-
| `custom`(可空) | 只记 `why`:配方盖不住的写(签名 / 多步 / 一次性 token),脚本仍留代码里;与 `recipe` 二选一,`design check`
|
|
111
|
+
| `custom`(可空) | 只记 `why`:配方盖不住的写(签名 / 多步 / 一次性 token),脚本仍留代码里;与 `recipe` 二选一,`design check` 记红 |
|
|
112
112
|
|
|
113
113
|
写了 `key + recipe` 的写,预览用 `describeRecipe(DATASOURCE.<key>)`,执行用
|
|
114
114
|
`data.submit(DATASOURCE.<key>, overrides)`;不再把 origin / path 写进代码。
|