dsh-helper 0.16.1 → 0.16.6

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/CHANGELOG.md CHANGED
@@ -8,6 +8,131 @@
8
8
  > (`package-lock.json` 根节点跟齐)与本文件顶部段落,两者连同提交一起走;发布只补 annotated tag,
9
9
  > 不再用 `npm version` 升版。
10
10
 
11
+ ## [0.16.6] — 未发布
12
+
13
+ **新增 `npm run verify:ci`** —— 在本地按 CI 的方式跑一遍,把那两处"本机比 CI 富"的地方补平。
14
+
15
+ ### 新增
16
+
17
+ - `tools/verify-ci.mjs` + `npm run verify:ci`。它做两件本机默认不会做的事:
18
+ 1. 把仓库复制到临时目录(排除 `node_modules` 与 `.git`)后 `npm ci --ignore-scripts` ——
19
+ 模拟 CI 的独立检出,**上层没有 `~/web/t-team/node_modules` 可借**;
20
+ 2. 用临时 `HOME` 跑那批可能依赖 home 的步骤 —— 模拟 CI 的 `/home/runner`。
21
+
22
+ 然后按 `ci.yml` 的顺序跑完六步,外加产物一致性(构建后与仓库里的 `lib/client.js` 逐字节比对,
23
+ 不等就说明改了 `src/client/` 却忘了 `npm run build`)与包形态(`npm pack --dry-run`)。
24
+
25
+ - 三种用法:`npm run verify:ci`(完整,约 1 分钟)、`npm run verify:ci -- --fast`(只换 HOME,
26
+ 几秒)、`npm run verify:ci -- --keep`(保留临时目录,便于进去手查)。
27
+ - **为什么不并进 `npm run verify`**:那是发布预检,每次都复制一遍仓库 + `npm ci` 太慢;而 CI
28
+ 那边本来就会跑。它是"本地想提前对齐 CI"时的显式动作。
29
+
30
+ ### 由来
31
+
32
+ 0.16.3–0.16.5 连修的三个 CI 失败,全是「本机环境比 CI 富、于是本地永远绿」这一类。这个脚本把
33
+ 那两处差异显式化,下次同类问题在本地就能撞出来,不必等 CI 通知。
34
+
35
+ ## [0.16.5] — 未发布
36
+
37
+ **修 CI 的第三条:一条冒烟断言硬编码了本机 home** —— 前两条修完,CI 走到 host-smoke 才停下。
38
+
39
+ ### 修复
40
+
41
+ - `tools/host-smoke.mjs` 的「迁移幂等性」用例里,旧数据文件路径原先是**硬编码**的
42
+ `/Users/biaoge/.t-team/schedule.json`,而引擎那边算的是
43
+ `process.env.DSH_HELPER_PATCH_SCHEDULE_LEGACY ?? join(homedir(), ".t-team", "schedule.json")` ——
44
+ 两边的 home 一旦不同就判不相等,`snapshot()` 于是继续透传迁移提示:
45
+
46
+ ```
47
+ ✗ 迁移幂等性:target 顶层 migration.legacy 标记存在时,snapshot 不再透传提示
48
+ true !== false
49
+ ```
50
+
51
+ - **为什么本地永远绿、CI 一直红**:本机 home 恰好就是 `/Users/biaoge`,硬编码值**碰巧**与引擎
52
+ 算出的一致;CI 的 home 是 `/home/runner`,匹配失败。现改为用与引擎同一套规则算路径。
53
+ - **不用等 CI 的复现办法**:`HOME=/tmp/fakehome npm run host-smoke` —— 修复前必挂,
54
+ 修复后 114 项全过;带 `DSH_HELPER_PATCH_SCHEDULE_LEGACY` 覆盖时同样全过。
55
+
56
+ ### 验证
57
+
58
+ - 本地 `npm run verify` 全绿(host 冒烟 114 项)。
59
+ - `HOME=/tmp/fakehome npm run host-smoke` → 全过(这正是 CI 失败的那个场景)。
60
+ - 干净目录 + `npm ci --ignore-scripts`,CI 六步逐一跑过 → 全部退出码 0。
61
+
62
+ ## [0.16.4] — 未发布
63
+
64
+ **继续修 CI:`react` / `react-dom` 同样没装** —— 0.16.3 修好 typecheck 后,CI 往下走一步又
65
+ 撞上同一类问题。
66
+
67
+ ### 修复
68
+
69
+ - `devDependencies` 增加 **`react` 与 `react-dom`**(`^18.2.0`,与 peer 声明一致)。
70
+ `npm run render-smoke` 要 `require("react")` + `require("react-dom/server")` 把每个组件真渲染
71
+ 一遍,而这两个包只写在 `peerDependencies` 里(设计上由 DSH 宿主在运行期提供)—— 在
72
+ `legacy-peer-deps` 下 npm 不会自动装,CI 的干净检出里就没有:
73
+
74
+ ```
75
+ > dsh-helper@0.16.3 render-smoke
76
+ Error: Cannot find module 'react'
77
+ ```
78
+
79
+ - 本地同样发现不了:`~/web/t-team/node_modules` 里有 react 18.3.1 / react-dom 18.3.1
80
+ (工作区共用依赖),Node 向上查找就命中了。**与 0.16.3 的 cordis 是同一个根因**:
81
+ 本机环境比 CI 富,于是本地永远绿、CI 一直红。
82
+ - `render-smoke.mjs` 的注释本来就写着「产物必须落在仓库内,它 `require("react")` 才能解析到
83
+ **本仓的** react」—— 补上 devDependency 正是让这句话成立的前提。
84
+
85
+ ### 验证
86
+
87
+ - 干净目录 + `npm ci --ignore-scripts`,把 CI 的六步逐一跑过:
88
+ `typecheck / smoke / render-smoke / host-smoke / build / pack` → **全部退出码 0**。
89
+ - 本仓 `npm run verify` 全绿(host 冒烟 114 项)。
90
+
91
+ ## [0.16.3] — 未发布
92
+
93
+ **修 CI 的 typecheck 失败** —— `lib/schedule-remote.js` 用到的 `this.ctx`,在 CI 的干净检出里
94
+ 拿不到类型。
95
+
96
+ ### 修复
97
+
98
+ - `devDependencies` 增加 **`"@deepseek-ai/cordis": "~4.0.4"`**。它是
99
+ `@deepseek-ai/dsh-typert-protocol` 声明的 **peer**,而本仓 `.npmrc` 开着 `legacy-peer-deps`,
100
+ npm 不会自动装 peer —— 于是 CI(独立检出 + 干净 `npm ci`)里 cordis 缺席,
101
+ `TypertRemoteService extends Service` 的 `Service` 解析不出来,`this.ctx` 就被判成非法属性:
102
+
103
+ ```
104
+ lib/schedule-remote.js(209,26): error TS2339:
105
+ Property 'ctx' does not exist on type 'HelperPatchScheduleRemote'.
106
+ ```
107
+
108
+ - **为什么本地一直没发现**:本机 `~/web/t-team/node_modules` 里躺着 cordis 4.0.4
109
+ (工作区共用依赖,`dsh-expert/node_modules` 的软链),TS 向上查找时把它解析到了 ——
110
+ 于是本地 `tsc` 退出码 0、CI 退出码 2,同一份代码两种结果。复现办法:把仓库复制到一个干净
111
+ 目录(不带 node_modules、上层也没有)再跑 `tsc`。
112
+ - **治本而不是绕过**:没有用 `@ts-expect-error` 盖住 —— 那样在本地反而会报 unused directive,
113
+ 两边永远对不上;而是让**两边的依赖树一致**。同文件 166 行那个 `@ts-expect-error` 是另一回事
114
+ (`TypertRegistry.register` 未写进 contract),与本次无关,保持原样。
115
+
116
+ ### 验证
117
+
118
+ - 干净目录 + `npm ci --ignore-scripts` + `tsc -p tsconfig.json` → 退出码 **0**(修复前是 2)。
119
+ - 本仓 `npm run verify` 全绿(host 冒烟 114 项)。
120
+
121
+ ## [0.16.2] — 未发布
122
+
123
+ **README 标题整体降一级** —— `#` 在 GitHub / npm 上会渲染成 2 倍字号的大标题,看着"顶"。
124
+
125
+ ### 变更
126
+
127
+ - 首行 `# 辅助补丁(dsh-helper)` → `##`,其余 `##`/`###` 章节顺延一级
128
+ (h2×1 + h3×15 + h4×9,共 25 个标题)。
129
+ - 为什么这么做:Markdown 的 `#` 是 h1,所有标准渲染器都把它放大到约 2 倍并加底部横线;而
130
+ GitHub 仓库页顶部本来就用大字显示仓库名,README 里再写一遍是同一句话说两遍。实测市场里
131
+ star 前 5 的插件有 4 个从 `##` 开始,只有 1 个用 h1。
132
+ - 纯排版改动,不影响功能;**代码块里的 `# 1.` / `# 2.`(shell 注释)刻意未动** —— 它们在
133
+ 围栏内,本来就不会被渲染成标题。文内两处 `[常见问题](#常见问题)` 锚点也不受影响:锚点由
134
+ 标题**文本**生成,与 `#` 的个数无关。
135
+
11
136
  ## [0.16.1] — 未发布
12
137
 
13
138
  **修交叉引用,以及一条真的会坏的路径** —— 两个仓库互相引用对方的包名/目录名,这次改名各改各的。
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # 辅助补丁(dsh-helper)
1
+ ## 辅助补丁(dsh-helper)
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/dsh-helper.svg)](https://www.npmjs.com/package/dsh-helper)
4
4
  [![license](https://img.shields.io/npm/l/dsh-helper.svg)](./LICENSE)
@@ -24,13 +24,13 @@
24
24
 
25
25
  ---
26
26
 
27
- ## 解决什么问题
27
+ ### 解决什么问题
28
28
 
29
29
  IM 插件自己的文件投递只发生在**它接管的那个 IM 会话里**:回合结束时,把它认得的产出(`write`/`edit` 成功的文件、`present` 明确交付的文件)回传到聊天窗口。所以「在 DSH 桌面/网页对话框里说『把这个文件发我微信』」这条路它覆盖不到——文件交付不出 IM 会话。
30
30
 
31
31
  本插件补的就是这一段:在任何会话(含网页 / CLI / 定时任务新开的会话)主动把本机文件投递到 IM。做法是复用 IM 插件**已经写好的实现**、由本插件完成编排,而不是复刻协议:登录态、CDN 加密上传、`context_token` 发送、图片/视频/文件分流都归上游。为什么不 patch 上游、也不复刻协议,见[开发文档](./docs/DEVELOPMENT.md#im-只读复用)。
32
32
 
33
- ## 安装
33
+ ### 安装
34
34
 
35
35
  **前提:先装好一个 IM 插件并接入微信。** 本插件复用它的通道与账号配置,没有它投递无法工作(其余能力不受影响):
36
36
 
@@ -56,9 +56,9 @@ dsh plugin --profile web add dsh-helper
56
56
  装完**重启 DSH**。你会得到:插件信息页的设置卡片、Agent 工具 `send_file_to_im`、
57
57
  侧栏「定时任务」入口、任何会话可用的 HTTP 投递端点。
58
58
 
59
- ## 把文件发到微信
59
+ ### 把文件发到微信
60
60
 
61
- ### 入口一:工具 `send_file_to_im`
61
+ #### 入口一:工具 `send_file_to_im`
62
62
 
63
63
  给 Agent 用,**只对「建立时已加载本插件」的会话可见**(已在跑的会话请用 HTTP 入口)。
64
64
 
@@ -67,7 +67,7 @@ dsh plugin --profile web add dsh-helper
67
67
  | `path` | 是 | 文件绝对路径,或相对当前工作区的路径 |
68
68
  | `toUserId` | 否 | 临时指定收件人 |
69
69
 
70
- ### 入口二:HTTP 端点
70
+ #### 入口二:HTTP 端点
71
71
 
72
72
  给任何会话、任何脚本用,不依赖工具表:
73
73
 
@@ -113,7 +113,7 @@ curl -s -X POST http://127.0.0.1:19387/api/dsh-helper/send-file \
113
113
  - 目录白名单对**工具路径同样生效**(`send_file_to_im` 也走同一个读文件收口点),否则模型调用那条路就成了绕过白名单的后门。
114
114
  - 白名单两侧都会做 `realpath`:既防止"在白名单目录里放一个指向 `/etc/passwd` 的符号链接"这种绕过,也保证 macOS 上 `/tmp`(真实路径 `/private/tmp`)这类写法不会把合法路径误拒。目录可用 `~` 表示家目录。
115
115
 
116
- ### 图片 / 视频自动走「图片消息」「视频消息」
116
+ #### 图片 / 视频自动走「图片消息」「视频消息」
117
117
 
118
118
  微信的附件分成互不相通的消息类型:按文件发落成一张要点开的文件卡片,按图片/视频发则能直接预览。**谁来判定,取决于后端**:
119
119
 
@@ -124,11 +124,11 @@ curl -s -X POST http://127.0.0.1:19387/api/dsh-helper/send-file \
124
124
 
125
125
  dsh-im 后端另有一个自动降级:上游还没有 `sendImage`(老版本)时自动退回按文件发。
126
126
 
127
- ## 定时任务
127
+ ### 定时任务
128
128
 
129
129
  按 cron 把一段提示词交给一个**全新**的 agent 会话执行。面板在**侧栏 → 定时任务**。
130
130
 
131
- ### 新建一条
131
+ #### 新建一条
132
132
 
133
133
  | 字段 | 说明 |
134
134
  | --- | --- |
@@ -142,21 +142,21 @@ dsh-im 后端另有一个自动降级:上游还没有 `sendImage`(老版本
142
142
 
143
143
  **总开关**(设置卡片里的「启用定时任务」)控制整个功能:关闭后左侧入口整条消失、停止全部触发、拒绝手动执行;任务与记录保留,重新打开后一起恢复。
144
144
 
145
- ### 自然语言建任务
145
+ #### 自然语言建任务
146
146
 
147
147
  在对话里说「帮我每天 9 点半获取每日热点新闻 10 条」,Agent 会调用 `create_schedule_task` 建好。若 DSH 官方的「自动化任务」也开着,Agent 会**先弹窗让你选**独立任务还是会话内提醒,不替你决定。除创建外还有 `list_schedule_tasks` / `update_schedule_task` / `delete_schedule_task`,改和删都会先回显目标标题与 cron 让你确认。
148
148
 
149
- ### cron 怎么写
149
+ #### cron 怎么写
150
150
 
151
151
  `分 时 日 月 周`,首位可加秒(秒 ≠ 0 时写六段),例如 `0 9 * * *`。面板提供图形化选择器(每天 / 每周 / 工作日 / 每 N 小时 / 每 N 分钟 / 自定义),切「自定义」直接写表达式;保存前显示**最近 5 次执行时间**供确认。
152
152
 
153
- ### 只跑一次("今年 9 月 28 日"这种)
153
+ #### 只跑一次("今年 9 月 28 日"这种)
154
154
 
155
155
  cron 没有「年」这个位置,`0 9 28 9 *` 字面意思是「每年这天」。把**「最多执行次数」填 1** 即可:**成功**跑完那一次自动停用(列表标「限次 1/1」)。上限与已跑次数落盘,重启宿主不重跑。
156
156
 
157
157
  只有成功的运行消耗次数:**失败不计数**(否则一次性任务失败一次就永久停用,连重试的机会都没有),改为**连续失败 5 次自动停用**(列表标「已连续失败 5 次」),成功一次即清零。这个计数同样落盘,重启不会把它重置 —— 它的作用是止损:一个配了坏提示词的分钟级 cron 否则会无限开新会话烧额度。
158
158
 
159
- ### 时区与夏令时
159
+ #### 时区与夏令时
160
160
 
161
161
  cron 按**宿主进程所在的本地时区**解释(不传 `timezone` 给 croner,跟随系统设置)。所以「每天 9 点」就是你这台机器上的 9 点;面板里「最近 5 次执行时间」也按本地时区显示,不会有 8 小时偏移。
162
162
 
@@ -187,13 +187,13 @@ TZ=America/New_York node /tmp/tz-probe.mjs "30 1 * * *" "2026-10-30T12:00:00Z" 3
187
187
 
188
188
  ⚠️ 每个时区要用**独立进程**跑(像上面这样分两条命令):在同一个进程里改 `process.env.TZ` 不总生效,V8 会缓存时区数据,测出来的结果可能是上一个时区的。
189
189
 
190
- ### 执行与记录
190
+ #### 执行与记录
191
191
 
192
192
  执行时在绑定工作区下**新建会话**、挂默认 preset,把提示词作为**用户消息**提交;同一事项**不并发**(上一轮没跑完就跳过本轮)。每条保留**最近 20 次**执行记录(时间、成败、当次提示词,成功还带会话 id),可点「关联会话」跳回或恢复已归档会话。
193
193
 
194
194
  **上限**:事项 200 条、单事项记录 20 条。数据在 `$DSH_HOME/integrations/dsh-helper/schedule.json`(原子写)。
195
195
 
196
- ## 活动呼吸灯
196
+ ### 活动呼吸灯
197
197
 
198
198
  工作区行的**文件夹图标**随会话状态呼吸,不动行背景、不做缩放。
199
199
 
@@ -207,7 +207,7 @@ TZ=America/New_York node /tmp/tz-probe.mjs "30 1 * * *" "2026-10-30T12:00:00Z" 3
207
207
 
208
208
  ![折叠 / 展开 × 活动 / 未读 的三种风格与两种主题](./docs/unread.png)
209
209
 
210
- ## 活跃指示
210
+ ### 活跃指示
211
211
 
212
212
  会话标题栏(右上角那排按钮里)一枚**心电图图标**:有会话正在跑、或有事等你查看时显示彩色,高亮沿着心电路径来回滚动;全部空闲且没有待看的显示灰色、静止。它只是指示,不挡任何点击。
213
213
 
@@ -223,7 +223,7 @@ TZ=America/New_York node /tmp/tz-probe.mjs "30 1 * * *" "2026-10-30T12:00:00Z" 3
223
223
 
224
224
  设置卡片里可以整个关掉(「显示活跃指示」,默认开)。偏好存 `localStorage`,与呼吸灯、提示音一致。这项能力 2026-09-28 从 **T专家(dsh-expert)** 迁来,位置、外观与行为都没变。
225
225
 
226
- ## 对话完成提示音
226
+ ### 对话完成提示音
227
227
 
228
228
  会话**跑完**出一声。声音由浏览器现场合成(Web Audio 振荡器 + 包络),插件不含任何音频文件。
229
229
 
@@ -238,7 +238,7 @@ TZ=America/New_York node /tmp/tz-probe.mjs "30 1 * * *" "2026-10-30T12:00:00Z" 3
238
238
 
239
239
  「完成」= 会话执行状态由跑转停(同一份状态快照,不加宿主钩子)。两条刻意的设计:**停下来等 300ms 再响**(避免多轮任务连响)、**只认顶层会话**(子代理与 Agent Teams 队友不算)。
240
240
 
241
- ## 界面外观
241
+ ### 界面外观
242
242
 
243
243
  | 设置 | 默认 | 说明 |
244
244
  | --- | --- | --- |
@@ -250,11 +250,11 @@ TZ=America/New_York node /tmp/tz-probe.mjs "30 1 * * *" "2026-10-30T12:00:00Z" 3
250
250
 
251
251
  约束两条:只在 macOS 桌面端有效(浏览器里访问同一个 GUI 本来就没有这层材质);侧栏列按 `[class*="_sidebarCol"]` 后缀匹配,官方哪天改了类名这条会降级失效——毛玻璃照样消失,只是侧栏底色仍是官方那层淡色。
252
252
 
253
- ## 一键重启 DeepSeek Harness
253
+ ### 一键重启 DeepSeek Harness
254
254
 
255
255
  「设置 → 通用设置」头部多一个**重启**按钮。点击后弹确认,服务端过**四道闸**:配置开关(`restartEnabled`)、请求来源(同源环回)、调试器附着、进程监督器;然后 spawn 脱离的 helper 起新进程、本进程自杀。不满足条件时按钮禁用并说明原因,失败日志在 `/tmp/dsh-helper-restart-<时间戳>.*.log`。
256
256
 
257
- ## 设置与配置
257
+ ### 设置与配置
258
258
 
259
259
  设置卡片在**插件列表 → 辅助补丁**的插件信息页,按用途分成六张卡片:
260
260
 
@@ -291,7 +291,7 @@ host 侧配置在 `$DSH_HOME/integrations/dsh-helper/config.json`(首次加载
291
291
 
292
292
  设置卡片里会显示**当前走哪个后端**(探测结果,只读)。
293
293
 
294
- ## 常见问题
294
+ ### 常见问题
295
295
 
296
296
  **投递失败,`hadContextToken: false` / 报 `-2 prepare failed`**
297
297
 
@@ -317,7 +317,7 @@ host 侧配置在 `$DSH_HOME/integrations/dsh-helper/config.json`(首次加载
317
317
 
318
318
  上游升级后内部模块路径或导出名变了(本插件只读 import 它们的模块,不复制协议)。升级本插件即可,其余能力不受影响。
319
319
 
320
- ## 兼容性
320
+ ### 兼容性
321
321
 
322
322
  | 项 | 要求 |
323
323
  | --- | --- |
@@ -326,7 +326,7 @@ host 侧配置在 `$DSH_HOME/integrations/dsh-helper/config.json`(首次加载
326
326
  | IM 插件 | `@michengai/dsh-im-connect >=0.1.50` 或 `@xmanrui/dsh-im >=4.24.0`(都是可选 peer;一个都没有时投递不可用,其余正常) |
327
327
  | React | `^18.2.0`(可选 peer,由宿主提供) |
328
328
 
329
- ## 已知限制
329
+ ### 已知限制
330
330
 
331
331
  - 主动投递需要「活的」会话上下文(见[常见问题](#常见问题)),这是上游协议限制。
332
332
  - 投递文件 200 MiB 本地上限(读取前拒绝),微信侧以更小的上游回执为准(单文件通常 50 MiB 左右)。
@@ -340,7 +340,7 @@ host 侧配置在 `$DSH_HOME/integrations/dsh-helper/config.json`(首次加载
340
340
  - 「关闭侧栏毛玻璃」是**样式遮挡**,不是真的关掉窗口的 vibrancy:主进程那层材质还在,只是被不透明底色盖住(想真关得改 `app.asar`,会破坏代码签名与自动更新)。它靠官方侧栏列的类名后缀匹配,官方改名后只剩"窗口底不透明"这一半效果。
341
341
  - dsh-im 后端的图片判定以魔数为主,文本文件改名成 `.jpg` 会按图片发出然后被上游拒绝(有意取舍);im-connect 后端按后缀分流、发送前按魔数纠偏,两种名不副实都会被纠正(视频不纠偏——格式头复杂、场景少,仍按后缀)。
342
342
 
343
- ## 开发与更新日志
343
+ ### 开发与更新日志
344
344
 
345
345
  - 构建、自检、槽位与样式约定、宿主适配的坑见 [docs/DEVELOPMENT.md](./docs/DEVELOPMENT.md)。
346
346
  - 发布流程见 [docs/PUBLISHING.md](./docs/PUBLISHING.md)。
@@ -352,6 +352,6 @@ npm run verify # build + 客户端/host/渲染冒烟
352
352
  npm run preview # 把呼吸灯样式渲染成预览页
353
353
  ```
354
354
 
355
- ## 许可
355
+ ### 许可
356
356
 
357
357
  [MIT](./LICENSE) © jiuaiwo