@mingmaple/dsh-handover 0.9.14 → 0.9.22
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 +46 -19
- package/docs/migrate.md +6 -6
- package/docs/releases/0.9.22.md +34 -0
- package/docs/troubleshoot.md +34 -10
- package/package.json +71 -71
- package/scripts/blank-dsh.mjs +29 -23
- package/scripts/blank-smoke.mjs +205 -87
- package/scripts/e2e-migration.mjs +2 -2
- package/scripts/office.mjs +3 -3
- package/src/client.js +159 -120
- package/src/index.mjs +65 -58
- package/src/lib/api.mjs +9 -7
- package/src/lib/brief.mjs +2 -2
- package/src/lib/config.mjs +3 -3
- package/src/lib/consent.mjs +54 -1
- package/src/lib/docmap.mjs +143 -0
- package/src/lib/gates.mjs +25 -1
- package/src/lib/guide.mjs +35 -44
- package/src/lib/lint.mjs +3 -2
- package/src/lib/manual.mjs +48 -9
- package/src/lib/mover.mjs +10 -10
- package/src/lib/names.mjs +14 -19
- package/src/lib/office.mjs +22 -14
- package/src/lib/pack-ops.mjs +2 -2
- package/src/lib/peer.mjs +4 -4
- package/src/lib/role.mjs +8 -5
- package/src/lib/scaffold.mjs +42 -20
- package/src/lib/schedule.mjs +1 -2
- package/src/lib/session-create.mjs +1 -1
- package/src/lib/session-ops.mjs +16 -16
- package/src/lib/sessions.mjs +1 -1
- package/src/lib/status.mjs +205 -45
- package/src/lib/succession.mjs +7 -7
- package/src/lib/zstd-log.mjs +1 -1
- package/src/selftest.mjs +6 -6
- package/src/templates/Prompt_Templates.md +13 -13
- package/src/templates/Runtime_Manual.md +56 -30
- package/src/templates/rules/Handover_Rules.md +2 -1
- package/src/templates/rules/Migration_Rules.md +1 -1
- package/src/templates/standards/README.md +25 -0
- package/src/tools/ho_backup.mjs +135 -0
- package/src/tools/ho_checkpoint.mjs +12 -11
- package/src/tools/ho_docmap.mjs +153 -0
- package/src/tools/ho_gate.mjs +2 -1
- package/src/tools/ho_office.mjs +1 -1
- package/src/tools/ho_sessions.mjs +3 -4
- package/src/tools/ho_status.mjs +246 -0
- package/src/tools/ho_succeed.mjs +1 -1
- package/src/tools/ho_workspace.mjs +86 -14
- package/src/tools/peer.mjs +205 -0
- package/src/tools/ho_brief.mjs +0 -57
- package/src/tools/ho_diag.mjs +0 -87
- package/src/tools/ho_drift.mjs +0 -41
- package/src/tools/ho_init.mjs +0 -82
- package/src/tools/ho_pack.mjs +0 -38
- package/src/tools/ho_phase.mjs +0 -37
- package/src/tools/ho_snapshot.mjs +0 -104
- package/src/tools/ho_tokens.mjs +0 -57
- package/src/tools/peer_list.mjs +0 -37
- package/src/tools/peer_new.mjs +0 -75
- package/src/tools/peer_peek.mjs +0 -41
- package/src/tools/peer_rename.mjs +0 -31
- package/src/tools/peer_send.mjs +0 -52
- package/src/tools/peer_status.mjs +0 -46
package/README.md
CHANGED
|
@@ -11,15 +11,16 @@ DeepSeek Harness 插件,用于管理长会话的上下文水位、交接文档
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
13
|
- 起始简报:水位、闸门、活跃与沉默、阶段建议,一条命令返回。
|
|
14
|
-
-
|
|
14
|
+
- 交接体检:检查交接文档的结构、字段与占位符,逐条列出问题;覆盖全局、已登记的项目与已登记的杂项任务。
|
|
15
15
|
- 压缩与续跑:由水位与剩余压缩次数共同判定时机,由用户授权,回合结束后执行;压缩后的去向由助手在登记时选择,继续工作时续跑,任务已收尾时静默等待;状态切换与失败原因写入结果。
|
|
16
|
-
-
|
|
16
|
+
- 在任登记与查询:每一类会话(全局、各个项目、各个杂项任务)都登记当前在任的会话与历史编号,记录保存在工作区内的 `Office.json`;按名字或旧编号查询现任,不启动会话也可用命令行查询。
|
|
17
17
|
- 换任由会话自行办理:在任会话在用户授权后自行检查交接、建立接任会话并登记在任,不再由全局会话转交。
|
|
18
18
|
- 会话清点与角色:查看会话水位与状态,设定角色,建立下一代会话,归档与解归档。
|
|
19
19
|
- 会话间通信:会话之间可直接对话,不必经全局转述;默认沉默,任务完成不向全局报告。
|
|
20
|
-
-
|
|
20
|
+
- 工作区迁移:预检、复制并逐文件校验、切换、改写登记、重建链接、清理旧备份。
|
|
21
21
|
- 快照与迁移包:库快照、打包、校验与恢复,包内绝对路径单独体检。
|
|
22
|
-
-
|
|
22
|
+
- 通用规范:各会话共用的做法集中在 `_Control_Center/standards/`,一条规范一个子目录,可随附脚本;写入默认本库,明确「写入通用规范库」一类要求才进共用库。
|
|
23
|
+
- 设置页:常规卡片为授权、移动全局根目录、会话角色、全局前置提示词、会话水位、通用约束条闸门、交接文档体检、插件与最近一次会话间通信判定;末尾另有默认折叠的「工具明细」与「使用说明」。授权与会话水位只列在任会话(全局、各项目、各杂项任务各一行),授权超过五个分页折叠;会话角色按 DSH 工作区分组、默认折叠,已归档与目录已不存在的会话不列出;交接体检覆盖已登记的项目与杂项。尚未接入工作区时置顶显示「首次安装」,可一键部署文件体系、工作区与会话;已接入但还没有全局会话时显示「全局会话」卡片。
|
|
23
24
|
|
|
24
25
|
## 安装
|
|
25
26
|
|
|
@@ -53,11 +54,11 @@ dsh plugin --profile web add @mingmaple/dsh-handover
|
|
|
53
54
|
首次安装后,工作区、文件体系与会话一次部署完成:
|
|
54
55
|
|
|
55
56
|
1. 打开设置页中的 dsh-handover,在「首次安装」卡片粘贴一个长期存在目录的绝对路径。
|
|
56
|
-
2.
|
|
57
|
-
3.
|
|
57
|
+
2. 点击「一键部署」。插件在该目录内建立 `_Workspace` 与整套文件结构,注册为「全局」工作区,并新建一个「全局」会话。
|
|
58
|
+
3. 在左侧「全局」工作区打开该会话即可开始。只需先铺文件时点击「仅建立文件体系」,之后再点击「注册为工作区」。
|
|
58
59
|
4. 工作区已接入但还没有全局会话时,设置页会单独出现「全局会话」卡片,可随时补建。
|
|
59
60
|
|
|
60
|
-
命令行等价操作:`
|
|
61
|
+
命令行等价操作:`ho_workspace(action="init", parent="<已存在目录>", register=true)`,再新建一个标题含「全局」的会话。
|
|
61
62
|
|
|
62
63
|
## 使用
|
|
63
64
|
|
|
@@ -71,18 +72,20 @@ dsh plugin --profile web add @mingmaple/dsh-handover
|
|
|
71
72
|
| 换任 | 写好交接,请用户授权,由本会话自己换任 |
|
|
72
73
|
| 查在任 | 现在全局是谁在任 |
|
|
73
74
|
| 设置角色 | 把 Demo1 设成项目角色,并让它整理自己的文件 |
|
|
75
|
+
| 文档定位 | 把本项目的文档定位写进提示段 |
|
|
76
|
+
| 按规范做事 | 按发布规范进行 |
|
|
74
77
|
| 自检 | 检查插件当前状态 |
|
|
75
78
|
|
|
76
79
|
### 四类会话
|
|
77
80
|
|
|
78
81
|
| 角色 | 提示段 | 工具数 | 说明 |
|
|
79
82
|
|---|---|---|---|
|
|
80
|
-
| 全局 | 有 |
|
|
83
|
+
| 全局 | 有 | 14 | 协调会话、维护规则与交接 |
|
|
81
84
|
| 项目 | 有 | 11 | 管理单个项目库,自己写骨架档案 |
|
|
82
|
-
| 杂项 | 有 |
|
|
85
|
+
| 杂项 | 有 | 10 | 管理单个杂项任务 |
|
|
83
86
|
| 普通 | 无 | 0 | 不注入提示、不加载工具 |
|
|
84
87
|
|
|
85
|
-
代理子会话不装配 `ho_` 与 `
|
|
88
|
+
代理子会话不装配 `ho_` 与 `peer` 工具。宿主逐步解析工具表,子会话在解析阶段即被排除,首轮即不可用。
|
|
86
89
|
|
|
87
90
|
### 交接与压缩
|
|
88
91
|
|
|
@@ -96,21 +99,45 @@ dsh plugin --profile web add @mingmaple/dsh-handover
|
|
|
96
99
|
|
|
97
100
|
压缩次数用尽(默认 3 次)的判定先于水位:额度用尽后,无论水位高低均建议换任;`force` 不能越过额度,`ho_sessions` 的压缩指令(`action="order", order="compact"`)同样会被拒绝。
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
压缩须由用户在设置页「授权」卡片点击「授权压缩」,单次授权 5 分钟内有效;`confirm=true` 只表示意图。压缩在回合结束后执行;登记时以 `resume` 选择去向,继续工作时续跑,任务已收尾时不唤醒。全局交接写在 `_Control_Center/records/Global_Handover.md`,项目与杂项交接写在各自目录,每次写入前备份。
|
|
100
103
|
|
|
101
104
|
归档文件名为 `<原文件名>_<YYYYMMDD_HHMMSS>.md`,同一秒重复时追加 `-2`。全局与项目的归档位于 `_Archives/<范围>/Handover/`,杂项归档位于 `_Misc/tasks/<任务>/_archive/`。
|
|
102
105
|
|
|
103
|
-
换任由在任会话自行办理:写完交接后,由用户在聊天框发送 `/allow-succeed
|
|
106
|
+
换任由在任会话自行办理:写完交接后,由用户在聊天框发送 `/allow-succeed`,或在设置页「授权」卡片点击「授权换任」。授权一次有效,5 分钟内可用,按会话生效。随后会话调用 `ho_succeed`,插件依次校验授权与交接结构,按记录分配下一代编号,建立接任会话并写入角色,登记在任,投递启动提示词,并在旧交接末尾追加换任登记。任何一项校验不通过时,整体不做任何改动,并逐条列出缺项。全局的建会话与换任能力保留,作为自动流程失败时的备选方案。
|
|
107
|
+
|
|
108
|
+
### 文档定位与授权提示
|
|
109
|
+
|
|
110
|
+
全局、每个项目、每个杂项任务各可写一份文档定位,放在 `_Control_Center/records/docmap/`,三列为路径、一句话介绍、什么时候该读。写好后注入对应会话的角色提示段:只指路,是否读正文由会话自己判断;空 map 不注入;不设字数上限。
|
|
111
|
+
|
|
112
|
+
写入用 `ho_docmap`。写入范围由会话已登记的角色决定,不接受传入项目名;只有对应的在任会话能写,已交出的旧会话只读;全局不代写项目与杂项的 map。写入前逐条校验路径存在,缺项整条拒绝;覆盖前留一份 `.bak`;写盘后当场重装提示段,下一轮即生效。`ho_gate` 会检查 map 里列出的路径是否仍然存在。
|
|
113
|
+
|
|
114
|
+
用户授权压缩或换任后,目标会话的提示段会在下一轮多一行「用户已授权…至…(一次性,用后失效)」,到期或用掉后消失,无授权不占位。`ho_status(view="phase")` 与 `view="brief"` 的输出里另有「授权」一行,给出剩余分钟与到期时刻。
|
|
115
|
+
|
|
116
|
+
### 通用规范
|
|
117
|
+
|
|
118
|
+
跨会话共用的做法放在 `_Control_Center/standards/`,一条规范一个子目录,目录名即规范名。正文入口为子目录内的 `README.md`;规范自带的脚本与附件放在同一子目录,不混入 `_Control_Center/tools/`。
|
|
119
|
+
|
|
120
|
+
用户提到「按某某规范进行」一类要求时,查找范围包括本库与该目录:先看本库有无同名规范,再看规范库;两处都有时按本库那份执行,规范库那份作为通用版本。本库指会话自己所在的工作区。
|
|
121
|
+
|
|
122
|
+
用户提到「把某某写成规范」时,未指明范围就写本库;说「写入通用规范库」「写成通用规范」「写成共用规范」的才写规范库。规范库由全局会话维护,项目与杂项会话只读;项目与杂项遇到这类要求时,报全局处理。
|
|
123
|
+
|
|
124
|
+
规范正文只写做法、判据与验收条件,不记某一次作业的进度与结果;进度归交接与台账。目录内仅有 `README.md` 说明时表示尚无共用规范,各库按自己的文档执行。
|
|
125
|
+
|
|
126
|
+
### 工具整合
|
|
127
|
+
|
|
128
|
+
0.9.15 起按「会话一次要做的一件事」合并入口,现有十四个:`ho_status`、`ho_gate`、`ho_sessions`、`ho_charter`、`ho_office`、`ho_docmap`、`ho_handover`、`ho_checkpoint`、`ho_changelog`、`ho_backup`、`ho_workspace`、`ho_profile`、`ho_succeed` 与 `peer`。
|
|
129
|
+
|
|
130
|
+
原先的 phase、brief、diag、drift、tokens 五个只读入口并入 `ho_status` 的 `view`;快照与迁移包并入 `ho_backup` 的 `action`;首次建立文件体系并入 `ho_workspace` 的 `action="init"`;平级会话的六个入口并入 `peer` 的 `action`。旧入口不再注册,调用会得到未知工具的报错,按本节说明改用新入口。动作级权限未变:`peer` 的 `list`、`peek`、`rename` 仅全局可用,`send` 与 `status` 各角色可用,`new` 仅全局可用、杂项可建到 `_Misc` 下。
|
|
104
131
|
|
|
105
132
|
### 设置页
|
|
106
133
|
|
|
107
|
-
|
|
134
|
+
设置页为单页卡片式,常用区直接展开,低频与长文段折叠。未接入工作区时,首次安装卡片置顶出现。删除旧备份须先输入「删除」两字才能解锁按钮;保留旧备份不算待处理,迁移卡片只在待切换、登记未改、链接失效或校验有差异时提示。时间显示为 `YYYY-MM-DD HH:mm` 加本机时区偏移。
|
|
108
135
|
|
|
109
136
|
## 迁移与恢复
|
|
110
137
|
|
|
111
|
-
|
|
138
|
+
换盘或搬动全局根目录时,按预检、复制并校验、切换、改写登记、清理旧备份五步执行,每一步均可在设置页「移动全局根目录」卡片内完成。切换须在 DSH 完全退出后由后台助手执行,原路径随后成为链接。
|
|
112
139
|
|
|
113
|
-
详见 [
|
|
140
|
+
详见 [迁移全局根目录](docs/migrate.md)。
|
|
114
141
|
|
|
115
142
|
## 故障处理
|
|
116
143
|
|
|
@@ -120,13 +147,13 @@ dsh plugin --profile web add @mingmaple/dsh-handover
|
|
|
120
147
|
|
|
121
148
|
## 上下文开销
|
|
122
149
|
|
|
123
|
-
固定开销为工具 schema 与提示段。按 0.9.
|
|
150
|
+
固定开销为工具 schema 与提示段。按 0.9.17 实测,按角色载入后,全局提示段约 526 加权 token(长路径加迁移提示行约 576),项目与杂项约 514(最坏约 563),随项目名、路径长度与文档定位条数波动;十四个入口的 schema 合计约 1.1 万字符,单条工具描述最宽约 70。以上为实测参考值,不设硬性上限:某条判定需要写清楚时,优先保证表达完整。
|
|
124
151
|
|
|
125
152
|
## 边界与限制
|
|
126
153
|
|
|
127
154
|
- 依赖 DSH 的 `ctx.compaction` 服务;未挂载时压缩相关工具明确报错。
|
|
128
155
|
- `ptc` 呈现模式下,插件工具只能经程序调用。
|
|
129
|
-
- 会话压力读取依赖宿主保存的会话状态文件布局;字段变化时用 `
|
|
156
|
+
- 会话压力读取依赖宿主保存的会话状态文件布局;字段变化时用 `ho_status(view="diag")` 排查。
|
|
130
157
|
- 迁移只搬文件与清单,不改写文件内容;写死的绝对路径以体检形式报出。
|
|
131
158
|
- 工具可见性按每一步计算:换角色在下一轮请求即生效,不必重启 DSH。插件重载后,已存在的会话沿用旧提示段文本,需要新文本时重启一次。
|
|
132
159
|
- 项目名与任务名按目录名校验:项目名不超过 24 字符,任务名不超过 40 字符;不含 `< > : " / \ | ? *` 与控制字符;不以点或空格结尾;不使用设备保留名。名字来自自由文本时同样校验,不合法则报错且不写入磁盘。
|
|
@@ -136,7 +163,7 @@ dsh plugin --profile web add @mingmaple/dsh-handover
|
|
|
136
163
|
|
|
137
164
|
```bash
|
|
138
165
|
npm test # 开发自测:逐个工具跑只读用例
|
|
139
|
-
npm run test:blank # 空白 DSH 验收:临时 HOME 与空目录跑
|
|
166
|
+
npm run test:blank # 空白 DSH 验收:临时 HOME 与空目录跑 14 工具及迁移四件
|
|
140
167
|
npm run test:smoke # 空白环境冒烟:工具装配、状态路由、浏览器半渲染、语体扫描
|
|
141
168
|
npm run test:migrate # 迁移与恢复端到端
|
|
142
169
|
npm run test:docs # 文档校验:工具名、旧数、链接、版本、语体与长度上限
|
|
@@ -146,7 +173,7 @@ npm run test:docs # 文档校验:工具名、旧数、链
|
|
|
146
173
|
|
|
147
174
|
## 版本
|
|
148
175
|
|
|
149
|
-
当前版本 0.9.
|
|
176
|
+
当前版本 0.9.22,首次公开版本为 0.9.6。内部版本史不随仓库发布。
|
|
150
177
|
|
|
151
178
|
支持的内核为 0.2.1-rc.2 至 0.3.0(不含 0.3.0 及其候选版),见 `package.json` 的 `engines.dsh`;0.2.2-rc.1 上的工具装配、角色裁剪与压缩调度已实测通过。
|
|
152
179
|
|
package/docs/migrate.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 迁移全局根目录
|
|
2
2
|
|
|
3
3
|
适用场景:把全局根目录换到另一块盘,例如从 D: 换到 E:。全程由 `ho_workspace` 的迁移动作完成,插件不改写文件内容。
|
|
4
4
|
|
|
5
5
|
## 前提
|
|
6
6
|
|
|
7
|
-
- 先跑一次完整备份或 `
|
|
7
|
+
- 先跑一次完整备份或 `ho_backup(action="snapshot", project="<项目名>")`。
|
|
8
8
|
- 目标父目录可以不存在,插件会自动创建;目标不得在源内部,也不得等于源。
|
|
9
9
|
- 切换必须在 DSH 完全退出后执行:源目录在运行期间被占用,目录改名与建链接都会失败。
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ ho_workspace(action="move-probe", to="<目标父目录>")
|
|
|
21
21
|
## 2. 复制并校验
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
ho_workspace(action="move")
|
|
24
|
+
ho_workspace(action="move", to="<目标父目录>")
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
复制到新位置,两边各算一遍逐文件 sha256 清单并比对。不一致时不生成切换脚本,报告差异文件。
|
|
@@ -32,7 +32,7 @@ ho_workspace(action="move")
|
|
|
32
32
|
ho_workspace(action="move-switch")
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
生成并派出后台助手,待插件使用者完全退出 DSH 后自动完成:旧目录改名为 `<旧>.old-<时间戳>`,再在原位置建 junction 指向新位置,并校验指向。日志写在 `~/.dsh/storages/dsh-handover.move.log`。
|
|
36
36
|
|
|
37
37
|
也可以双击生成的 `dsh-handover.move.cmd`。切换后原路径成为链接,工作区登记、profile 与会话工作目录都无需修改。
|
|
38
38
|
|
|
@@ -46,9 +46,9 @@ ho_workspace(action="move-retarget")
|
|
|
46
46
|
|
|
47
47
|
只替换 JSON 文本里的路径字符串,结构不动,每份先备份 `.bak-<时间>`。
|
|
48
48
|
|
|
49
|
-
## 5.
|
|
49
|
+
## 5. 清理旧备份
|
|
50
50
|
|
|
51
|
-
确认新位置可正常工作、并已重启 DSH
|
|
51
|
+
确认新位置可正常工作、并已重启 DSH 后,可在设置页「移动全局根目录」卡片里输入「删除」确认,再执行(旧备份保留不影响使用,不必急着删):
|
|
52
52
|
|
|
53
53
|
```text
|
|
54
54
|
ho_workspace(action="move-cleanup", confirm=true)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 0.9.22
|
|
2
|
+
|
|
3
|
+
设置页「会话角色」改为按 DSH 工作区分组,默认全部折叠;已归档会话与目录已不存在的会话不再罗列;卡片下的说明文字一并删去。插件与文档中的比喻性称谓(「血脉」「历代」「退位」等)改为书面说法(「登记」「历史编号」「已交出的会话」),用户可见文案的「点」统一为「点击」,提示段里过时的按钮名「压缩授权」改为「授权压缩」。本说明新增「安装与使用」一节。工具与提示段不变。
|
|
4
|
+
|
|
5
|
+
## 自 v0.9.14 以来的累计变化
|
|
6
|
+
|
|
7
|
+
0.9.15 至 0.9.21 均未单独发布,本次一并发布,累计变化如下。
|
|
8
|
+
|
|
9
|
+
- 工具整合:入口由 24 个降为 14 个(13 个 `ho_*` 与 `peer`),按「一次做一件事」合并;旧工具名不设兼容桩,替代关系见下文与 README「工具整合」。
|
|
10
|
+
- 文档定位:`ho_docmap` 提供读、写、查;写入范围由会话已登记的角色决定,只允许对应的在任会话写入;写入前逐条校验路径、覆盖前留 `.bak`、写盘后当场重装提示段;`ho_gate` 增加路径检查。
|
|
11
|
+
- 授权提示:用户授权压缩或换任后,目标会话的提示段在下一轮多一行到期时刻与一次性说明;`ho_status` 的 `phase` 与 `brief` 视图给出「授权」一行。
|
|
12
|
+
- 交接类文档不设体积上限:只判结构与占位符。
|
|
13
|
+
- 通用规范库:`_Control_Center/standards/` 一条规范一个子目录;三档角色段加查找指针;写入分两档(默认写本库,明确「写入通用规范库」一类说法才写共用库);`ho_workspace(action="scaffold")` 用于补齐既有工作区。
|
|
14
|
+
- 设置页:授权卡改名并按在任会话折叠;「待处理」合并进既有卡片;工具清单独立为默认折叠的「工具明细」;会话水位、通知与交接体检统一以 `_Control_Center/records/Office.json` 的在任为准,普通会话不参与;交接体检只查已登记的项目与杂项,并接受有序列表;会话角色按 DSH 工作区分组、默认折叠、已归档与无目录会话不列;迁移卡片不再把保留的旧备份当作待处理;全页文案与注释改为规范书面语。
|
|
15
|
+
- 使用说明:逐条按实现核对,起始简报、换任入口、压缩去向、打包格式、会话清点输出、自检项与文档定位权限均按当前输出改写。
|
|
16
|
+
|
|
17
|
+
## 会话角色
|
|
18
|
+
|
|
19
|
+
- 分组依据 `~/.dsh/storages/workspace.json`:以工作区的会话归属为准;未登记的会话按 cwd 的真实路径匹配工作区路径(旧根现为链接,取 realpath 后归组)。
|
|
20
|
+
- 每个工作区一行摘要,显示标题与会话数;默认收起,点击展开后可见该工作区的会话表。表内仍按全局、项目、杂项、普通排序,同角色按最近活动。卡片下不再保留说明文字。
|
|
21
|
+
- 不在任何工作区下的会话归入末组「未归属工作区」,组内显示其 cwd。
|
|
22
|
+
- 已归档会话(`workspace.json` 的 `archivedSessionIds`)不列出;会话目录已不存在的老会话(旧树里删掉的项目库等)同样不列出。
|
|
23
|
+
|
|
24
|
+
## 数据
|
|
25
|
+
|
|
26
|
+
- 授权列表与会话水位沿用 `Office.json` 的在任口径,同时受上述归档与目录过滤约束。
|
|
27
|
+
|
|
28
|
+
## 安装与使用
|
|
29
|
+
|
|
30
|
+
安装并启用插件后,可在设置的 dsh-handover 页面创建或指定全局;页面底部「使用说明」可供参考。后续将在 GitHub 仓库建立「使用说明」文档。
|
|
31
|
+
|
|
32
|
+
## 升级
|
|
33
|
+
|
|
34
|
+
替换 `dist/` 后在插件列表停用再启用;浏览器半不热更新,需刷新设置页。本版未改提示段与工具。
|
package/docs/troubleshoot.md
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## 工具缺失或数量不对
|
|
4
4
|
|
|
5
|
-
1. 在全局会话执行 `
|
|
6
|
-
2. 全局应为
|
|
5
|
+
1. 在全局会话执行 `ho_status(view="diag")`,看「角色」与「角色装配」两行。
|
|
6
|
+
2. 全局应为 14 个,项目 11 个,杂项 10 个,普通 0 个。
|
|
7
7
|
3. 新建会话时角色表中尚无该会话,插件会判为普通;角色写入后,该会话下一轮请求即按新角色装配。
|
|
8
|
-
4. 仍未装配时,在设置页「会话角色」卡片里重新设一次角色;仍无效则执行 `
|
|
8
|
+
4. 仍未装配时,在设置页「会话角色」卡片里重新设一次角色;仍无效则执行 `ho_status(view="diag")` 查 `roleGating` 字段。
|
|
9
9
|
5. 改过源码但未生效:执行 `node scripts/build.mjs`,然后在插件列表停用并启用一次,不必重启 DSH。提示段文本不随重载替换,仍显示旧文本时重启 DSH。
|
|
10
|
-
6. 子会话不装配 `ho_` 与 `
|
|
10
|
+
6. 子会话不装配 `ho_` 与 `peer` 工具,属正常:子会话在工具表解析阶段即被排除,与角色设置无关。
|
|
11
11
|
|
|
12
12
|
## 工作区未接入
|
|
13
13
|
|
|
14
|
-
`
|
|
14
|
+
`ho_status(view="diag")` 或设置页显示未接入时,走设置页「首次安装」卡片:粘贴绝对路径后点击「一键部署」,文件体系、工作区与会话一次建好;也可以只点击「仅建立文件体系」,再点击「注册为工作区」。命令行等价操作:
|
|
15
15
|
|
|
16
16
|
```text
|
|
17
|
-
|
|
17
|
+
ho_workspace(action="init", parent="<已存在目录的绝对路径>", register=true)
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
装配里没有写死 `workspaceRoot`。工具侧按配置项、会话工作目录向上查找的顺序定位,向上找不到时再查工作区登记;设置页没有会话上下文,按配置项、标题含「全局」且带 `_Control_Center` 的工作区、任一带 `_Control_Center` 的工作区定位。
|
|
@@ -31,10 +31,10 @@ ho_init(parent="<已存在目录的绝对路径>", register=true)
|
|
|
31
31
|
|
|
32
32
|
## 设置角色后工具没有变化
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
会话休眠时设定角色,插件会在它下次开轮时装配工具与提示段,不必重启 DSH。若仍看不到应有的工具:
|
|
35
35
|
|
|
36
36
|
1. 在设置页「会话角色」重新设定一次,注意「存活会话当场生效」一栏的提示。
|
|
37
|
-
2. 执行 `
|
|
37
|
+
2. 执行 `ho_status(view="diag")`,看「角色装配」一行里的已装配会话数与最近时间。
|
|
38
38
|
3. 插件刚从旧版本换上来时,已存在的会话沿用旧提示段文本;重启 DSH 一次即换成新文本,工具裁剪不受影响。
|
|
39
39
|
|
|
40
40
|
## 设置页刷新失败
|
|
@@ -47,7 +47,7 @@ ho_init(parent="<已存在目录的绝对路径>", register=true)
|
|
|
47
47
|
|
|
48
48
|
## 压缩未生效
|
|
49
49
|
|
|
50
|
-
1.
|
|
50
|
+
1. 压缩须由用户在设置页「授权」卡片点击「授权压缩」,单次授权 5 分钟内有效,或在聊天框发送 `/allow-compact`。
|
|
51
51
|
2. `ho_checkpoint` 只登记,由调度器在回合结束后执行;目标必须空闲。
|
|
52
52
|
3. 交接体检不通过时拒绝排压缩,先用 `ho_handover(action=read)` 检查结构。
|
|
53
53
|
4. 已压满 3 次后不再压缩,应换任:由本会话写好交接后调用 `ho_succeed` 自行换任,须用户先发送 `/allow-succeed` 授权。额度用尽的判定先于水位;低水位与 `force` 均不能越过,`ho_sessions` 的压缩指令(`action="order", order="compact"`)同样会被拒绝。
|
|
@@ -56,7 +56,7 @@ ho_init(parent="<已存在目录的绝对路径>", register=true)
|
|
|
56
56
|
|
|
57
57
|
`ho_succeed` 报「换任未执行,未做任何写入」时,按报出的原因逐项处理:
|
|
58
58
|
|
|
59
|
-
1. 没有授权:由用户在聊天框发送 `/allow-succeed`(可留空,也可带 8
|
|
59
|
+
1. 没有授权:由用户在聊天框发送 `/allow-succeed`(可留空,也可带 8 位短号授权别的会话),或在设置页「授权」卡片点击「授权换任」。授权一次性、5 分钟有效、按会话生效;压缩的授权不能顶替换任的授权。
|
|
60
60
|
2. 不是在任者:只有登记表中该类会话的现任本人可以换任;已记过一次换任的旧会话也不得再次换任。先用 `ho_office` 确认现任的名字与会话 id,再由现任会话执行。
|
|
61
61
|
3. 交接体检不合格:报错逐条列出缺项——「下一步」一节缺失或没有条目、内容为空、仍有「待填」「TODO」一类占位符。补齐后用 `ho_handover(action=read)` 复核,再重新调用。
|
|
62
62
|
|
|
@@ -70,6 +70,30 @@ ho_init(parent="<已存在目录的绝对路径>", register=true)
|
|
|
70
70
|
|
|
71
71
|
名字合法但被判为普通角色的会话,用设置页「会话角色」卡片或 `ho_sessions(action="role")` 明确设定。
|
|
72
72
|
|
|
73
|
+
## 文档定位报路径失效
|
|
74
|
+
|
|
75
|
+
`ho_gate` 的「文档定位 map」一节报「失效 N 条」时,说明 map 里列的某个路径已被移动或删除。由对应会话的在任者执行:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
ho_docmap(action="check")
|
|
79
|
+
ho_docmap(action="write", entries=[{ path: "<新路径>", about: "<一句话介绍>", when: "<何时读>" }])
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
map 整份替换,写入前逐条校验路径存在,缺项整条拒绝。只有对应的在任会话能写,已交出的旧会话只读;全局不代写项目与杂项的 map。
|
|
83
|
+
|
|
84
|
+
## 按规范做事时找不到规范
|
|
85
|
+
|
|
86
|
+
用户提到某个规范而手头没有时,按两处查找:当前库内有无同名规范,以及 `_Control_Center/standards/` 下有无同名子目录。
|
|
87
|
+
|
|
88
|
+
1. 先看本库:规范可能就在本库的文档目录内,本库那份优先。
|
|
89
|
+
2. 再看规范库:直接列 `_Control_Center/standards/` 下的子目录,目录名即规范名;该目录只有 `README.md` 说明时表示尚无共用规范。
|
|
90
|
+
3. 两处都没有:不要凭记忆补全步骤,向用户说明缺哪份规范,由其决定新建还是改用别的口径。
|
|
91
|
+
4. 需要新增或改写时:未指明范围就写本库(会话所在的工作区);说「写入通用规范库」「写成通用规范」「写成共用规范」的才由全局会话在 `_Control_Center/standards/<规范名>/` 下写 `README.md`,项目与杂项会话只读、报全局。
|
|
92
|
+
|
|
93
|
+
## 授权后会话没有反应
|
|
94
|
+
|
|
95
|
+
授权写入后,目标会话的提示段会在下一轮开头带上「用户已授权…至…(一次性,用后失效)」。正在作业的会话要等它下一个请求;空闲会话不会因此被唤醒。可用 `ho_status(view="phase")` 查看授权状态与剩余分钟。授权过期未用属于正常,重新授权即可。
|
|
96
|
+
|
|
73
97
|
## 迁移后原路径失效
|
|
74
98
|
|
|
75
99
|
若链接被误删,页面会显示「原路径不存在」与「重建链接」。执行:
|
package/package.json
CHANGED
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mingmaple/dsh-handover",
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "DeepSeek Harness 插件:把「全局」的交接、闸门、会话清点与上下文压缩续跑流程做成工具(dsh-handover)",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
"access": "public"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/MingMaple/dsh-handover.git"
|
|
13
|
-
},
|
|
14
|
-
"homepage": "https://github.com/MingMaple/dsh-handover#readme",
|
|
15
|
-
"bugs": {
|
|
16
|
-
"url": "https://github.com/MingMaple/dsh-handover/issues"
|
|
17
|
-
},
|
|
18
|
-
"keywords": [
|
|
19
|
-
"dsh",
|
|
20
|
-
"deepseek-harness",
|
|
21
|
-
"plugin",
|
|
22
|
-
"handover",
|
|
23
|
-
"context-compaction"
|
|
24
|
-
],
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=20",
|
|
27
|
-
"dsh": ">=0.2.1-rc.2 <0.3.0-0"
|
|
28
|
-
},
|
|
29
|
-
"exports": {
|
|
30
|
-
".": "./src/index.mjs",
|
|
31
|
-
"./client": "./src/client.js"
|
|
32
|
-
},
|
|
33
|
-
"files": [
|
|
34
|
-
"src",
|
|
35
|
-
"scripts",
|
|
36
|
-
"docs",
|
|
37
|
-
"README.md",
|
|
38
|
-
"LICENSE"
|
|
39
|
-
],
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "node scripts/build.mjs",
|
|
42
|
-
"test": "node src/selftest.mjs --tool all",
|
|
43
|
-
"test:blank": "node scripts/blank-dsh.mjs",
|
|
44
|
-
"test:smoke": "node scripts/blank-smoke.mjs",
|
|
45
|
-
"test:migrate": "node scripts/e2e-migration.mjs",
|
|
46
|
-
"test:docs": "node scripts/check-docs.mjs"
|
|
47
|
-
},
|
|
48
|
-
"dsh": {
|
|
49
|
-
"bundle": {
|
|
50
|
-
"patch": "./src/cordis.patch.yml"
|
|
51
|
-
},
|
|
52
|
-
"client": {
|
|
53
|
-
"platform": "web",
|
|
54
|
-
"inject": [
|
|
55
|
-
"@deepseek-ai/dsh-client-ui-settings",
|
|
56
|
-
"@deepseek-ai/dsh-client-connection"
|
|
57
|
-
]
|
|
58
|
-
},
|
|
59
|
-
"compatibility": {
|
|
60
|
-
"dsh": "0.2.2-rc.1",
|
|
61
|
-
"profiles": [
|
|
62
|
-
"desktop",
|
|
63
|
-
"web"
|
|
64
|
-
],
|
|
65
|
-
"dshReleases": {
|
|
66
|
-
"0.2.1-rc.2": "compatible",
|
|
67
|
-
"0.2.2-rc.1": "compatible"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mingmaple/dsh-handover",
|
|
3
|
+
"version": "0.9.22",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "DeepSeek Harness 插件:把「全局」的交接、闸门、会话清点与上下文压缩续跑流程做成工具(dsh-handover)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/MingMaple/dsh-handover.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/MingMaple/dsh-handover#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/MingMaple/dsh-handover/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"dsh",
|
|
20
|
+
"deepseek-harness",
|
|
21
|
+
"plugin",
|
|
22
|
+
"handover",
|
|
23
|
+
"context-compaction"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20",
|
|
27
|
+
"dsh": ">=0.2.1-rc.2 <0.3.0-0"
|
|
28
|
+
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./src/index.mjs",
|
|
31
|
+
"./client": "./src/client.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"scripts",
|
|
36
|
+
"docs",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "node scripts/build.mjs",
|
|
42
|
+
"test": "node src/selftest.mjs --tool all",
|
|
43
|
+
"test:blank": "node scripts/blank-dsh.mjs",
|
|
44
|
+
"test:smoke": "node scripts/blank-smoke.mjs",
|
|
45
|
+
"test:migrate": "node scripts/e2e-migration.mjs",
|
|
46
|
+
"test:docs": "node scripts/check-docs.mjs"
|
|
47
|
+
},
|
|
48
|
+
"dsh": {
|
|
49
|
+
"bundle": {
|
|
50
|
+
"patch": "./src/cordis.patch.yml"
|
|
51
|
+
},
|
|
52
|
+
"client": {
|
|
53
|
+
"platform": "web",
|
|
54
|
+
"inject": [
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
56
|
+
"@deepseek-ai/dsh-client-connection"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"compatibility": {
|
|
60
|
+
"dsh": "0.2.2-rc.1",
|
|
61
|
+
"profiles": [
|
|
62
|
+
"desktop",
|
|
63
|
+
"web"
|
|
64
|
+
],
|
|
65
|
+
"dshReleases": {
|
|
66
|
+
"0.2.1-rc.2": "compatible",
|
|
67
|
+
"0.2.2-rc.1": "compatible"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
package/scripts/blank-dsh.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 空白 DSH 验收:证明「移到一个没有任何旧全局文件的空 DSH 上,插件所有功能 100% 可用」。
|
|
3
|
-
* 做法:临时 HOME(无 ~/.dsh 状态)→ 只靠 dist/ 自带的东西跑完
|
|
3
|
+
* 做法:临时 HOME(无 ~/.dsh 状态)→ 只靠 dist/ 自带的东西跑完 14 个工具 + 迁移四件。
|
|
4
4
|
* 额外覆盖:7-Zip 不存在(强制 format=tar)、工作区规则文件被删光(必须退回内置模板)。
|
|
5
5
|
* 用法:node scripts/blank-dsh.mjs
|
|
6
6
|
*/
|
|
@@ -58,10 +58,10 @@ const ctx = {
|
|
|
58
58
|
apply(ctx, { packFormat: 'tar' }); // 强制内置归档器:模拟一台没有 7-Zip 的机器
|
|
59
59
|
|
|
60
60
|
section('装配');
|
|
61
|
-
ok(reg.tools.length ===
|
|
61
|
+
ok(reg.tools.length === 14, '注册 14 个工具', String(reg.tools.length));
|
|
62
62
|
ok(reg.tools.every((t) => t && t.name && t.description && typeof t.execute === 'function'), '每个工具都有 name/description/execute');
|
|
63
63
|
const names = reg.tools.map((t) => t.name).sort();
|
|
64
|
-
ok(names.indexOf('
|
|
64
|
+
ok(names.indexOf('ho_backup') !== -1 && names.indexOf('peer') !== -1 && names.indexOf('ho_docmap') !== -1, '关键工具都在');
|
|
65
65
|
|
|
66
66
|
const byName = new Map(reg.tools.map((t) => [t.name, t]));
|
|
67
67
|
function execFor(cwd, id, title) {
|
|
@@ -79,8 +79,8 @@ async function run(tool, args, cwd, id, title) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
section('首次安装(只用插件自带模板)');
|
|
82
|
-
const init = await run('
|
|
83
|
-
ok(!init.err, '
|
|
82
|
+
const init = await run('ho_workspace', { action: 'init', parent: WORK, name: '_Workspace', register: false }, WORK, 'session-blank-test', '空白验收');
|
|
83
|
+
ok(!init.err, 'ho_workspace(action=init) 不抛错', init.err);
|
|
84
84
|
const WS = path.join(WORK, '_Workspace');
|
|
85
85
|
ok(fs.existsSync(WS), '全局根已建', WS);
|
|
86
86
|
for (const rel of [
|
|
@@ -96,33 +96,39 @@ for (const rel of [
|
|
|
96
96
|
ok(fs.existsSync(path.join(WS, rel)), '铺好 ' + rel);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
{
|
|
100
|
+
const { writeRole } = await import(pathToFileURL(path.join(dist, 'lib', 'role.mjs')).href);
|
|
101
|
+
writeRole({}, 'session-blank-test', { role: 'global' });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
section('14 个工具在空白工作区逐个跑');
|
|
100
105
|
const calls = [
|
|
101
|
-
['
|
|
102
|
-
['
|
|
106
|
+
['ho_status', { view: 'diag' }],
|
|
107
|
+
['ho_status', { view: 'brief' }],
|
|
108
|
+
['ho_status', { view: 'phase' }],
|
|
109
|
+
['ho_status', { view: 'drift' }],
|
|
110
|
+
['ho_status', { view: 'tokens', sessions: ['session-blank-test'] }],
|
|
103
111
|
['ho_gate', { scope: 'all' }],
|
|
104
112
|
['ho_sessions', { action: 'list' }],
|
|
105
|
-
['ho_phase', {}],
|
|
106
113
|
['ho_charter', { doc: 'runtime' }],
|
|
107
114
|
['ho_charter', { doc: 'charter', section: '10' }],
|
|
108
115
|
['ho_handover', { action: 'read' }],
|
|
109
116
|
['ho_handover', { action: 'write', text: '# 全局交接\n\n## 0 身份与寻址\n- 本文件:_Control_Center/records/Global_Handover.md\n\n## 1 正在做的事\n空白验收\n\n## 2 下一步\n- 无\n\n## 3 等用户拍板\n- 无\n\n## 4 用户要求逐条落位\n- 无\n\n## 5 坑点与禁区\n- 无\n\n## 6 关键路径\n- 无\n\n## 7 会话 id\n- session-blank-test\n' }],
|
|
110
117
|
['ho_checkpoint', { at_risk: true }],
|
|
111
|
-
['
|
|
112
|
-
['
|
|
118
|
+
['ho_backup', { action: 'snapshot', project: 'NoSuchProject' }],
|
|
119
|
+
['ho_backup', { action: 'check', items: ['global'] }],
|
|
113
120
|
['ho_changelog', { summary: '空白验收写入一行' }],
|
|
114
|
-
['ho_tokens', { sessions: ['session-blank-test'] }],
|
|
115
|
-
['ho_pack', { action: 'check', items: ['global'] }],
|
|
116
121
|
['ho_workspace', { action: 'list' }],
|
|
117
|
-
['
|
|
118
|
-
['
|
|
119
|
-
['
|
|
120
|
-
['
|
|
122
|
+
['ho_docmap', { action: 'read' }],
|
|
123
|
+
['peer', { action: 'list' }],
|
|
124
|
+
['peer', { action: 'status', session_id: 'session-blank-test' }],
|
|
125
|
+
['peer', { action: 'peek', session_id: 'session-blank-test', limit: 2 }],
|
|
126
|
+
['peer', { action: 'rename', session_id: 'session-blank-test', title: '空白验收' }],
|
|
121
127
|
['ho_succeed', {}],
|
|
122
128
|
];
|
|
123
129
|
for (const [tool, args] of calls) {
|
|
124
130
|
const r = await run(tool, args, WS, 'session-blank-test', '空白验收');
|
|
125
|
-
const acceptable = !r.err ||
|
|
131
|
+
const acceptable = !r.err || /找不到项目|日志找不到|没有可读的会话历史|not found/i.test(r.err);
|
|
126
132
|
ok(acceptable, tool + ' 可用', r.err);
|
|
127
133
|
}
|
|
128
134
|
|
|
@@ -166,17 +172,17 @@ fs.writeFileSync(path.join(WS, 'Projects', 'Demo', 'Demo库', 'RULES.md'), '# De
|
|
|
166
172
|
fs.mkdirSync(path.join(WS, '_Project_Meta', 'Demo'), { recursive: true });
|
|
167
173
|
fs.writeFileSync(path.join(WS, '_Project_Meta', 'Demo', 'Handover.md'), '# Demo 交接\n\n## 1 正在做的事\n- 空\n\n## 2 下一步\n- 空\n\n## 3 坑点\n- 空\n', 'utf8');
|
|
168
174
|
const packOut = path.join(ROOT, 'packs');
|
|
169
|
-
const packed = await run('
|
|
175
|
+
const packed = await run('ho_backup', { action: 'pack', kind: 'project', name: 'Demo', out: packOut, format: 'tar' }, WS, 'session-blank-test', '空白验收');
|
|
170
176
|
ok(!packed.err, 'pack 打包成功', packed.err);
|
|
171
177
|
const pkg = fs.existsSync(packOut) ? fs.readdirSync(packOut).filter((f) => f.endsWith('.tar.gz')) : [];
|
|
172
178
|
ok(pkg.length === 1, '产出 1 个 .tar.gz', pkg.join(','));
|
|
173
179
|
if (pkg.length === 1) {
|
|
174
180
|
const packPath = path.join(packOut, pkg[0]);
|
|
175
|
-
const ver = await run('
|
|
181
|
+
const ver = await run('ho_backup', { action: 'verify', pack: packPath }, WS, 'session-blank-test', '空白验收');
|
|
176
182
|
ok(!ver.err && /一致/.test(ver.text), 'verify 校包可跑', ver.err);
|
|
177
|
-
const dry = await run('
|
|
183
|
+
const dry = await run('ho_backup', { action: 'restore', pack: packPath, target: path.join(ROOT, 'target'), dry_run: true }, WS, 'session-blank-test', '空白验收');
|
|
178
184
|
ok(!dry.err && /预演/.test(dry.text), 'restore 预演不写盘', dry.err);
|
|
179
|
-
const applied = await run('
|
|
185
|
+
const applied = await run('ho_backup', { action: 'restore', pack: packPath, target: path.join(ROOT, 'target'), apply: true }, WS, 'session-blank-test', '空白验收');
|
|
180
186
|
ok(!applied.err, 'restore 写入成功', applied.err);
|
|
181
187
|
const restored = path.join(ROOT, 'target', 'Projects', 'Demo', 'Demo库', 'RULES.md');
|
|
182
188
|
ok(fs.existsSync(restored), '恢复出来的文件在(相对路径正确)', restored);
|
|
@@ -200,5 +206,5 @@ if (fails.length) {
|
|
|
200
206
|
for (const f of fails) console.log(' - ' + f);
|
|
201
207
|
process.exit(1);
|
|
202
208
|
}
|
|
203
|
-
console.log('BLANK-DSH OK(空白 DSH 上
|
|
209
|
+
console.log('BLANK-DSH OK(空白 DSH 上 14 工具 + 迁移四件全部可用)');
|
|
204
210
|
|