@zhushanwen/pi-base-tool-enhance 0.5.1 → 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.
|
|
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.
|
|
32
|
-
"@zhushanwen/pi-extension-logger": "0.
|
|
33
|
-
"@zhushanwen/pi-file-lock": "0.
|
|
34
|
-
"@zhushanwen/pi-llm-shared": "0.
|
|
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.
|
|
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
|
|
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
|
-
//
|
|
8
|
+
// 全局文件锁(原 reapOrphanedTasks 的 reaper.lock 路径随模块删除一并消失)
|
|
9
9
|
// - 入口无条件 debug 日志按派发次数出现,detail 仅含 reason(reapSkipped 字段
|
|
10
10
|
// 随 reap 调用移除,S6 观测通道语义更新)
|
|
11
|
-
// 断言方式:reconcile / logger
|
|
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
|
|
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
|
-
//
|
|
35
|
-
//
|
|
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
|
-
//
|
|
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 作为权威**:
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
//
|
|
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
|
|
134
|
-
//
|
|
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) {
|