dsh-session-superagent 0.8.12 → 0.8.14

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
@@ -2,6 +2,91 @@
2
2
 
3
3
  格式参照 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## [0.8.14] - 2026-11-02 —— 第四轮审核:1 条文档 + 3 条代码建议
6
+
7
+ 审核范围 0.8.9→0.8.13(上一轮门禁只覆盖到 0.8.8)。结论:代码侧无阻塞,文档有 1 处必须修。
8
+
9
+ ### 修复
10
+ - **幽灵会话不退避**(真问题):绑到「已删除会话」的 watcher 每次轮询都打一次 GitHub 且永不休止
11
+ (0.8.11 的分支直接 `return`,没走 `bumpFailure`)。现在会正常进入 30 分钟退避。
12
+ - **删掉 `/client-hello` 路由**:客户端只在那里发过一次 fire-and-forget fetch,而 `note('apply')`
13
+ 已经覆盖同一用途。路由 7 → 6,并加用例锁死路由集合(`/config`、`/client-hello` 都不该回来)。
14
+
15
+ ### 文档
16
+ - HANDOFF 版本号 0.8.11 → 0.8.14;README / MAINTENANCE / HANDOFF 的测试数 77 → 80。
17
+
18
+ ### 未采纳(附理由)
19
+ - **goal 文本里的 `【主理鱼】` 内联**:已压平换行(实测伪造抬头不会独占一行),
20
+ 且 goal 只能由面板或本地 POST 写入,风险低;强行改写用户文本得不偿失。
21
+ - **`sync-profile --repair`**:断链(inode 不同)目前只警告。已在 HANDOFF 写明「新增文件后必须跑」,
22
+ 留作后续(改起来简单,但此刻没有证据表明它造成过事故)。
23
+
24
+ ### 其他
25
+ - `scripts/smoke-observe.mjs` 加 `gh auth status` 预检:没登录时明确 SKIP 并退出 0,
26
+ 不再把「凭证/网络问题」混报成逻辑失败(第四轮审核的建议)。
27
+
28
+ ### 测试
29
+ - 合计 **80 例**(新增路由集合用例)。
30
+
31
+ ## [0.8.13] - 2026-11-02 —— 真机跑「只观察」闭环,抓出两个真 bug
32
+
33
+ 拿真仓库(MYCF711/dsh-GOkifu-compact,3 个真 issue)跑 observe 模式验证,抓到:
34
+
35
+ ### 修复
36
+ - **`filteredLog` 从没落过盘**:`filteredLog` 不在 `POLL_RESULT_FIELDS` 白名单里,
37
+ 内存里写得好好的,`persistEntry` 一过滤就没了 → 面板「最近被过滤」永远是空的。
38
+ 现在进白名单,并补了守门用例。
39
+ - **空轮询不清理 `lastDeferred`**:把过滤器改严之后一条都不该唤醒,但面板仍显示上一轮的
40
+ 「仅观察:本轮本会唤醒 4 条(#4 #2 #3 #1)」——那是过期信息。现在 `fresh.length === 0` 时清空。
41
+
42
+ ### 真机证据(修复前)
43
+ ```
44
+ observe: true
45
+ lastDeferred: 仅观察:本轮本会唤醒 4 条(#4 #2 #3 #1)
46
+ history: [{"numbers":[4,2,3,1],"ok":false,"reason":"observe"}]
47
+ filteredLog: [] ← 改成 labels:["ai-fix"] 后仍为空(3 个 issue 都没这个标签)
48
+ ```
49
+
50
+ ### 发布与真机验证
51
+ - 已发 `dsh-session-superagent@0.8.13`。
52
+ - **`watch_ack` 第一次在真仓库上验证**:给 `MYCF711/dsh-GOkifu-compact#2` 打上 `主理鱼:已处理`——
53
+ GitHub **接受中文 + 冒号**的标签名(此前审核把它列为"未验证");重复 ack 幂等不报错;
54
+ 验证完已把 issue 标签与仓库标签定义都撤掉,不留痕迹。
55
+
56
+ ### 测试
57
+ - 合计 **79 例**。
58
+
59
+ ### 进程内冒烟(补证:这两个修复到底生效没有)
60
+ `pnpm run smoke:observe`(`scripts/smoke-observe.mjs`)—— 独立进程、独立状态目录、
61
+ 捕获 `setInterval` 手动驱动,会真的读 GitHub 只读 API:
62
+
63
+ ```
64
+ OK 观模式仍未唤醒 (followups = 0)
65
+ OK filteredLog 已落盘 (4 条)
66
+ OK 过滤原因可读 ("不在标签白名单: ai-fix")
67
+ OK /state 能读到过滤记录
68
+ OK 空轮询清掉了过期的 lastDeferred
69
+
70
+ == 场景 B:真唤醒 + 隔离 worktree ==
71
+ OK 唤醒了一次 (followups = 1)
72
+ OK 消息带【主理鱼】抬头
73
+ OK 消息带条目编号 (#2 #4 #3 #1,真 GitHub 数据)
74
+ OK 消息带本条目主理目标 (「把 widget 的 issue 都处理完」)
75
+ OK 消息带隔离路径
76
+ OK worktree 真的建了 (.dsh-zhuli/MYCF711-dsh-GOkifu-compact-smoke-se-…)
77
+ OK .dsh-zhuli 下正好一个副本
78
+ ```
79
+
80
+ 消息实样(真数据):
81
+
82
+ ```
83
+ 【主理鱼】MYCF711/dsh-GOkifu-compact 有 4 条新动态:
84
+ #2 [open] docs/bench:给「351 tokens」和「失败保留 8/8」补一条可复跑的复现命令 — @MYCF711 (issue) …
85
+ #4 [closed] 【联调】v0.1.0 唤醒链路验证 — @MYCF711 (issue) …
86
+ 【隔离工作区】…\.dsh-zhuli\MYCF711-dsh-GOkifu-compact-smoke-se-…
87
+ 本条目主理目标:把 widget 的 issue 都处理完
88
+ ```
89
+
5
90
  ## [0.8.12] - 2026-11-02 —— 体验打磨四条
6
91
 
7
92
  ### 改了什么
@@ -13,8 +98,15 @@
13
98
  - **删掉 `/session-superagent/config`**:它和 `/state` 重复,是未鉴权的 GET,而且上一轮
14
99
  `ReferenceError: gh is not defined` 就出在它身上。现在路由从 8 条减到 7 条,测试改为断言它已下线。
15
100
 
101
+ ### 发布与验证
102
+ - 已发 `dsh-session-superagent@0.8.12`(registry 确认 `latest=0.8.12`)。
103
+ - **从 registry 真装一遍验证**(不是只看 `npm pack`):
104
+ `npm i dsh-session-superagent@0.8.12` → `import(...)/lib/index.js` → `apply()` 成功、
105
+ 路由 **7** 条(`/config` 确实没了)、`node --check client.js` 通过。
106
+ - 新增守门:`lib/` 里每个相对 import 必须能解析到真实文件(发布前挡住 `body.js` 那类事故)。
107
+
16
108
  ### 测试
17
- - 合计 **77 例**(`/config` 用例改为「路由表里不应再有它」)。
109
+ - 合计 **78 例**(`/config` 用例改为「路由表里不应再有它」+ 相对 import 守门)。
18
110
 
19
111
  ## [0.8.11] - 2026-11-02 —— 真机验证隔离执行 + watch_doctor
20
112
 
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # dsh-session-superagent
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
- [![Version](https://img.shields.io/badge/version-0.8.12-green.svg)](https://github.com/MYCF711/dsh-session-superagent/releases)
4
+ [![Version](https://img.shields.io/badge/version-0.8.14-green.svg)](https://github.com/MYCF711/dsh-session-superagent/releases)
5
5
  [![npm](https://img.shields.io/npm/v/dsh-session-superagent.svg)](https://www.npmjs.com/package/dsh-session-superagent)
6
6
  [![dsh](https://img.shields.io/badge/DeepSeek%20Harness-plugin-orange.svg)](https://github.com/topics/dsh-plugin)
7
7
 
package/client.js CHANGED
@@ -14,7 +14,7 @@ window.__ModuleLoader__.load({
14
14
  const { useCallback, useEffect, useRef, useState } = React
15
15
 
16
16
  // 客户端版本探针:每次模块加载写一次,用来确认浏览器里跑的是哪一版
17
- const CLIENT_VERSION = '0.8.12'
17
+ const CLIENT_VERSION = '0.8.14'
18
18
  const BASE = '/session-superagent'
19
19
  const ENDPOINT = BASE + '/state'
20
20
  const POLL_MS = 5000
@@ -974,7 +974,6 @@ window.__ModuleLoader__.load({
974
974
  apply(ctx) {
975
975
  try { noteOnce('client-version', CLIENT_VERSION) } catch {}
976
976
  try { note('apply', 'start') } catch {}
977
- try { fetch(BASE + '/client-hello').catch(() => {}) } catch {}
978
977
 
979
978
  // ① the 主理鱼 tab in the centre-column view ring
980
979
  ctx.effect(() => {
package/lib/index.js CHANGED
@@ -422,7 +422,11 @@ async function pollOnce(ctx, entry, baseMs) {
422
422
  const newestAbsorbed = newestUpdatedAt(absorbed)
423
423
  if (!entry.cursor || Date.parse(newestAbsorbed) > Date.parse(entry.cursor)) entry.cursor = newestAbsorbed
424
424
  }
425
- if (fresh.length === 0) return
425
+ if (fresh.length === 0) {
426
+ // 这一轮没有新增:上一轮的说法(比如「仅观察:本会唤醒 4 条」)已经过期了
427
+ entry.lastDeferred = null
428
+ return
429
+ }
426
430
 
427
431
  // 仅观察模式(对标官方 observe):照常判定,但只记录「本会唤醒哪几条」,不真唤醒
428
432
  if (entry.observe === true) {
@@ -466,8 +470,10 @@ async function pollOnce(ctx, entry, baseMs) {
466
470
  // 会话忙就别开隔离区了:白建一个没人用的 worktree
467
471
  const liveAgent = ctx.agents && typeof ctx.agents.get === 'function' ? ctx.agents.get(entry.sessionId) : undefined
468
472
  if (!liveAgent) {
469
- // 会话已经不在了(被删/换机器):别开隔离区,也别假装在盯
473
+ // 会话已经不在了(被删/换机器):别开隔离区,也别假装在盯。
474
+ // 必须走 bumpFailure —— 否则这条会每 intervalSec 打一次 GitHub,永不退避(第四轮审核指出)。
470
475
  entry.lastError = '会话已不在:请删除或重建这条主理鱼'
476
+ bumpFailure(entry, baseMs)
471
477
  return
472
478
  }
473
479
  const gate = decideWake(liveAgent && liveAgent.status)
@@ -622,11 +628,6 @@ export function apply(ctx) {
622
628
  }))
623
629
  },
624
630
  }))
625
- routes.push(httpServer.register({
626
- kind: 'exact',
627
- path: '/session-superagent/client-hello',
628
- handler: (req, res) => { record('hello', String(req.url)); res.statusCode = 204; res.end() },
629
- }))
630
631
  routes.push(httpServer.register({
631
632
  kind: 'exact',
632
633
  path: '/session-superagent/client-note',
package/lib/watch.js CHANGED
@@ -350,6 +350,8 @@ export const POLL_RESULT_FIELDS = [
350
350
  'lastPoll', 'lastError', 'nextAt', 'consecutiveFailures', 'seen', 'cursor', 'lastReported',
351
351
  'lastWake', 'lastWakeCount', 'lastBatch', 'lastAbsorbed', 'wakeTimes', 'lastDeferred',
352
352
  'history', 'lastWorktree', 'lastAcked', 'lastTrigger',
353
+ // 过滤记录也是轮询结果:漏了它面板上的「最近被过滤」永远是空的
354
+ 'filteredLog',
353
355
  ]
354
356
 
355
357
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-session-superagent",
3
- "version": "0.8.12",
3
+ "version": "0.8.14",
4
4
  "description": "Session-level superagent for DeepSeek Harness: watch a GitHub repository and wake a session when something needs doing. Credentials never reach the model.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -30,7 +30,8 @@
30
30
  "test": "node --test",
31
31
  "check": "node --test",
32
32
  "preview:orbit": "node scripts/preview-orbit.mjs",
33
- "sync:profile": "node scripts/sync-profile.mjs"
33
+ "sync:profile": "node scripts/sync-profile.mjs",
34
+ "smoke:observe": "node scripts/smoke-observe.mjs"
34
35
  },
35
36
  "keywords": [
36
37
  "dsh",