@zhushanwen/pi-base-tool-enhance 0.5.0 → 0.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhushanwen/pi-base-tool-enhance",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Base tool enhancement - override builtin bash tool: foreground delegates to pi official factory, incremental background mode (design: docs/design/base-tool-enhance.md)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -28,10 +28,10 @@
28
28
  "skills/"
29
29
  ],
30
30
  "dependencies": {
31
- "@xyz-agent/extension-protocol": "0.8.2",
32
- "@zhushanwen/pi-extension-logger": "0.4.1",
33
- "@zhushanwen/pi-file-lock": "0.2.1",
34
- "@zhushanwen/pi-llm-shared": "0.5.1"
31
+ "@xyz-agent/extension-protocol": "0.9.0",
32
+ "@zhushanwen/pi-extension-logger": "0.6.0",
33
+ "@zhushanwen/pi-file-lock": "0.4.0",
34
+ "@zhushanwen/pi-llm-shared": "0.7.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@vitest/coverage-v8": "^4.1.9",
@@ -40,7 +40,7 @@
40
40
  "peerDependencies": {
41
41
  "@earendil-works/pi-coding-agent": "^0.84.4",
42
42
  "typebox": "*",
43
- "@zhushanwen/pi-pending-notifications": "0.5.3"
43
+ "@zhushanwen/pi-pending-notifications": "0.7.0"
44
44
  },
45
45
  "peerDependenciesMeta": {
46
46
  "@zhushanwen/pi-pending-notifications": {
@@ -121,7 +121,7 @@ describe("session_start chain: reconcile (M3, reap sunk into runtime by u-bte-re
121
121
  status: "cancelled",
122
122
  }),
123
123
  );
124
- // 对账之外尽力补一次 emit(listener 内存视图同步,失败无害)
124
+ // 对账之外尽力补一次 emit(幂等兜底,纯日志性质;失败无害)
125
125
  expect(pi.events.emit).toHaveBeenCalledWith("pending:unregister", {
126
126
  id: "bt-1700000000-idx001",
127
127
  reason: "cancelled",
@@ -5,23 +5,23 @@
5
5
  // - reconcilePendingEntries 是 session 级豁免类,每 session_start 派发都执行
6
6
  // (startup/resume/new 多派发 ×N——含 factory 二调 handler 累积的真实形态)
7
7
  // - 触发面消失:reaper.ts 模块文件已删除(文件级断言,见首条用例)+ 维护链不再触发
8
- // 全局文件锁(withFileLock——原 reapOrphanedTasks 的 reaper.lock 路径)
8
+ // 全局文件锁(原 reapOrphanedTasks 的 reaper.lock 路径随模块删除一并消失)
9
9
  // - 入口无条件 debug 日志按派发次数出现,detail 仅含 reason(reapSkipped 字段
10
10
  // 随 reap 调用移除,S6 观测通道语义更新)
11
- // 断言方式:reconcile / logger / file-lock 全部间谍注入,观察调用次数与参数。
11
+ // 断言方式:reconcile / logger 间谍注入观察调用次数与参数;file-lock 为 mock
12
+ // 缺键守卫 + withFileLockSync throw 哨兵(不计数)。
12
13
  import { existsSync } from "node:fs";
13
14
  import { dirname, join } from "node:path";
14
15
  import { fileURLToPath } from "node:url";
15
16
 
16
17
  import { describe, expect, it, vi, beforeEach } from "vitest";
17
18
 
18
- const { reconcileMock, loggerMock, officialBashFactoryMock, dataDirRef, withFileLockMock } =
19
+ const { reconcileMock, loggerMock, officialBashFactoryMock, dataDirRef } =
19
20
  vi.hoisted(() => ({
20
21
  reconcileMock: vi.fn(),
21
22
  loggerMock: { debug: vi.fn(), warn: vi.fn(), error: vi.fn() },
22
23
  officialBashFactoryMock: vi.fn(),
23
24
  dataDirRef: { dir: "/tmp/bte-fake-agent-dir" },
24
- withFileLockMock: vi.fn(),
25
25
  }));
26
26
 
27
27
  vi.mock("@earendil-works/pi-coding-agent", () => ({
@@ -31,10 +31,10 @@ vi.mock("@earendil-works/pi-coding-agent", () => ({
31
31
  vi.mock("@zhushanwen/pi-extension-logger", () => ({
32
32
  getLogger: () => loggerMock,
33
33
  }));
34
- // 全局扫描探针:withFileLock 是原 reapOrphanedTasks 持 reaper.lock 的唯一锁路径
35
- // (registry 写走的是 withFileLockSync)——维护链触发它 = 全局扫描回流
34
+ // 守卫形态 = mock 工厂缺键:包入口已删除的 async 锁导出不在工厂注册——维护链若
35
+ // 误回流,对已删导出的任何访问(调用与 typeof 均计)即抛错(vitest mock 缺键语义;
36
+ // 模块导入本身不抛)。withFileLockSync 哨兵保留:registry 写路径误入维护链即抛
36
37
  vi.mock("@zhushanwen/pi-file-lock", () => ({
37
- withFileLock: withFileLockMock,
38
38
  withFileLockSync: vi.fn(() => {
39
39
  throw new Error("unexpected registry write in maintenance chain");
40
40
  }),
@@ -86,7 +86,6 @@ beforeEach(() => {
86
86
  parameters: {},
87
87
  execute: vi.fn(),
88
88
  });
89
- withFileLockMock.mockReset();
90
89
  loggerMock.debug.mockClear();
91
90
  loggerMock.warn.mockClear();
92
91
  loggerMock.error.mockClear();
@@ -118,8 +117,7 @@ describe("session_start maintenance chain after reap sink (u-bte-remove)", () =>
118
117
  expect(reconcileMock).toHaveBeenCalledTimes(3);
119
118
  expect(reconcileMock).toHaveBeenNthCalledWith(1, expect.anything(), dataDirRef.dir, "sid-once", []);
120
119
  expect(reconcileMock).toHaveBeenLastCalledWith(expect.anything(), dataDirRef.dir, "sid-once", []);
121
- // 无全局扫描:维护链不触发原 reaper 的跨进程锁路径,也无告警
122
- expect(withFileLockMock).not.toHaveBeenCalled();
120
+ // 无全局扫描回流:误触发已删锁导出的任何访问会被 mock 缺键直接抛错(守卫见工厂注释),无告警
123
121
  expect(loggerMock.warn).not.toHaveBeenCalled();
124
122
  });
125
123
 
@@ -8,12 +8,14 @@
8
8
  * ③ fork 后任务完成通知写进新 session,旧 session 文件的 register 成僵尸。
9
9
  *
10
10
  * 收尾写法(权威路径):直接 pi.appendEntry("pending:unregister", {id, reason,
11
- * status})——**不走 bus emit 作为权威**:pending-notifications 的 unregister listener
12
- * 落盘条件是其内存 registry 该 id active(其 registry 只在自身 session_start rebuild
13
- * 后非空),两个 extension 的加载/派发顺序(CLI --extension 顺序用户可控)无保障,
14
- * 顺序反转时 emit 被静默吞、对账失效。差集消费方 goal 从持久化 entries 算差集
15
- * (agent-end.ts getEntries(),不读 pending 内存 registry),appendEntry 对守卫直接
16
- * 生效。appendEntry 之外尽力补一次 emit(listener 就绪时同步其内存视图,失败无害)。
11
+ * status})——**不走 bus emit 作为权威**:appendEntry 不依赖 listener 存活,两个
12
+ * extension 的加载/派发顺序(CLI --extension 顺序用户可控)无保障,顺序反转时
13
+ * emit 无人接收、对账失效。差集消费方 goal 从持久化 entries 算差集
14
+ * (agent-end.ts getEntries()),appendEntry 同步入账(pi dist 实证)对守卫直接
15
+ * 生效,无不一致窗口。appendEntry 之外尽力补一次 emit(幂等兜底,纯日志性质:
16
+ * pending-notifications 的 unregister listener 落盘前置判断 isPendingActive 对
17
+ * getEntries() 现算——其内存 registry/rebuild 已随 ext-simplify-12 删除,emit
18
+ * 到达时该 id 已注销即跳过,失败无害)。
17
19
  *
18
20
  * 终态判据:registry state ∈ {exited, orphaned},或(state=running/killing 且
19
21
  * kill(pid,0) 判死:收殓/写盘失败遗留的 running 条目按事实终态处理)。
@@ -112,7 +114,7 @@ export function reconcilePendingEntries(
112
114
  if (entry === undefined) {
113
115
  // registry 无条目:终态无从判定(LRU 淘汰的终态条目其 unregister entry 应已
114
116
  // 落盘,差集里还出现 = spawn 后 registry 写失败等罕见路径)——保守不动作,
115
- // 差集残留交给 pending 自身 TTL 之外的 next-session 对账重查
117
+ // pending-notifications 已无任何 TTL 清理,差集残留由 next-session 对账重查收口
116
118
  result.skipped.push(id);
117
119
  continue;
118
120
  }
@@ -130,8 +132,9 @@ export function reconcilePendingEntries(
130
132
  });
131
133
  continue;
132
134
  }
133
- // 尽力补 emit(listener 就绪时同步 pending 内存视图,缩短 pending_notifications
134
- // 工具列表的不一致窗口;失败无害——appendEntry 已是权威路径)
135
+ // 尽力补 emit(幂等兜底,纯日志性质:listener 落盘前置 isPendingActive 对
136
+ // entries 现算,该 id 已注销即跳过——appendEntry 同步入账已无不一致窗口;
137
+ // 失败无害)
135
138
  try {
136
139
  pi.events.emit("pending:unregister", { id, reason: pendingReason });
137
140
  } catch (err) {