@xgjktech/xg_cwork_im 1.16.44 → 1.17.0

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.
Files changed (59) hide show
  1. package/README.md +433 -433
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +27 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/deliver-text.test.js +22 -22
  6. package/dist/src/dispatch-mentioned-reply.d.ts.map +1 -1
  7. package/dist/src/dispatch-mentioned-reply.js +8 -0
  8. package/dist/src/dispatch-mentioned-reply.js.map +1 -1
  9. package/dist/src/plan-blocked-notice.d.ts +15 -0
  10. package/dist/src/plan-blocked-notice.d.ts.map +1 -0
  11. package/dist/src/plan-blocked-notice.js +28 -0
  12. package/dist/src/plan-blocked-notice.js.map +1 -0
  13. package/dist/src/plan-blocked-notice.test.d.ts +2 -0
  14. package/dist/src/plan-blocked-notice.test.d.ts.map +1 -0
  15. package/dist/src/plan-blocked-notice.test.js +80 -0
  16. package/dist/src/plan-blocked-notice.test.js.map +1 -0
  17. package/dist/src/plan-event-subscription.d.ts +26 -0
  18. package/dist/src/plan-event-subscription.d.ts.map +1 -0
  19. package/dist/src/plan-event-subscription.js +121 -0
  20. package/dist/src/plan-event-subscription.js.map +1 -0
  21. package/dist/src/plan-event-subscription.test.d.ts +2 -0
  22. package/dist/src/plan-event-subscription.test.d.ts.map +1 -0
  23. package/dist/src/plan-event-subscription.test.js +257 -0
  24. package/dist/src/plan-event-subscription.test.js.map +1 -0
  25. package/dist/src/plan-session-registry.d.ts +24 -0
  26. package/dist/src/plan-session-registry.d.ts.map +1 -0
  27. package/dist/src/plan-session-registry.js +84 -0
  28. package/dist/src/plan-session-registry.js.map +1 -0
  29. package/dist/src/plan-session-registry.test.d.ts +2 -0
  30. package/dist/src/plan-session-registry.test.d.ts.map +1 -0
  31. package/dist/src/plan-session-registry.test.js +109 -0
  32. package/dist/src/plan-session-registry.test.js.map +1 -0
  33. package/dist/src/plan-store-access.d.ts +16 -0
  34. package/dist/src/plan-store-access.d.ts.map +1 -0
  35. package/dist/src/plan-store-access.js +76 -0
  36. package/dist/src/plan-store-access.js.map +1 -0
  37. package/dist/src/plan-store-access.test.d.ts +2 -0
  38. package/dist/src/plan-store-access.test.d.ts.map +1 -0
  39. package/dist/src/plan-store-access.test.js +139 -0
  40. package/dist/src/plan-store-access.test.js.map +1 -0
  41. package/dist/src/plan-tool-middleware.d.ts +20 -0
  42. package/dist/src/plan-tool-middleware.d.ts.map +1 -0
  43. package/dist/src/plan-tool-middleware.js +99 -0
  44. package/dist/src/plan-tool-middleware.js.map +1 -0
  45. package/dist/src/plan-tool-middleware.test.d.ts +2 -0
  46. package/dist/src/plan-tool-middleware.test.d.ts.map +1 -0
  47. package/dist/src/plan-tool-middleware.test.js +329 -0
  48. package/dist/src/plan-tool-middleware.test.js.map +1 -0
  49. package/dist/src/plan-tool-result.d.ts +20 -0
  50. package/dist/src/plan-tool-result.d.ts.map +1 -0
  51. package/dist/src/plan-tool-result.js +78 -0
  52. package/dist/src/plan-tool-result.js.map +1 -0
  53. package/dist/src/plan-tool-result.test.d.ts +2 -0
  54. package/dist/src/plan-tool-result.test.d.ts.map +1 -0
  55. package/dist/src/plan-tool-result.test.js +107 -0
  56. package/dist/src/plan-tool-result.test.js.map +1 -0
  57. package/dist/src/turn-deliver-buffer.test.js +25 -25
  58. package/openclaw.plugin.json +27 -26
  59. package/package.json +76 -72
@@ -0,0 +1,257 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { createPlanEventHandler } from "./plan-event-subscription.js";
4
+ const FAKE_CTX = {
5
+ getRunContext: () => undefined,
6
+ setRunContext: () => { },
7
+ clearRunContext: () => { },
8
+ };
9
+ function makeBlockedPayload(overrides = {}) {
10
+ return {
11
+ kind: "plan_update",
12
+ planId: "plan-1",
13
+ goal: "迁移配置到新版本",
14
+ action: "advance",
15
+ taskIndex: 0,
16
+ taskTitle: "备份旧配置",
17
+ taskStatus: "blocked",
18
+ blockedNote: "缺少权限",
19
+ summary: { total: 3, completed: 1, blocked: 1, inProgress: 0 },
20
+ runId: "run-1",
21
+ ...overrides,
22
+ };
23
+ }
24
+ class RecordingSendText {
25
+ calls = [];
26
+ impl = async (groupId, content) => {
27
+ this.calls.push({ groupId, content });
28
+ };
29
+ sendText = (groupId, content) => this.impl(groupId, content);
30
+ }
31
+ describe("createPlanEventHandler: isPlanEventPayload 守卫", () => {
32
+ it("rejects malformed data without pushing or throwing", async () => {
33
+ const recorder = new RecordingSendText();
34
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
35
+ const event = {
36
+ runId: "run-1",
37
+ seq: 1,
38
+ stream: "xg-harness-tools.plan",
39
+ ts: Date.now(),
40
+ data: { kind: "not_plan_update" },
41
+ };
42
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
43
+ assert.equal(recorder.calls.length, 0);
44
+ });
45
+ it("rejects when data is not an object at all", async () => {
46
+ const recorder = new RecordingSendText();
47
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
48
+ const event = {
49
+ runId: "run-1",
50
+ seq: 1,
51
+ stream: "xg-harness-tools.plan",
52
+ ts: Date.now(),
53
+ data: null,
54
+ };
55
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
56
+ assert.equal(recorder.calls.length, 0);
57
+ });
58
+ it("rejects a payload that violates kind only — everything else (routing + copy fields) is valid (pins the guard)", async () => {
59
+ const recorder = new RecordingSendText();
60
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
61
+ const event = {
62
+ runId: "run-1",
63
+ seq: 1,
64
+ stream: "xg-harness-tools.plan",
65
+ ts: Date.now(),
66
+ data: makeBlockedPayload({
67
+ kind: "some_other_plugin_event", // 唯一的不合法项
68
+ deliveryContext: { to: "group-1" },
69
+ }),
70
+ };
71
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
72
+ assert.equal(recorder.calls.length, 0);
73
+ });
74
+ it("rejects a payload with a malformed summary — everything else is valid", async () => {
75
+ const recorder = new RecordingSendText();
76
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
77
+ const event = {
78
+ runId: "run-1",
79
+ seq: 1,
80
+ stream: "xg-harness-tools.plan",
81
+ ts: Date.now(),
82
+ data: makeBlockedPayload({
83
+ summary: {},
84
+ deliveryContext: { to: "group-1" },
85
+ }),
86
+ };
87
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
88
+ assert.equal(recorder.calls.length, 0);
89
+ });
90
+ });
91
+ describe("createPlanEventHandler: 路由字段取自 event.data 而非顶层", () => {
92
+ it("uses deliveryContext.to from event.data, ignoring a same-shaped decoy on the top-level event", async () => {
93
+ const recorder = new RecordingSendText();
94
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
95
+ const event = {
96
+ runId: "run-1",
97
+ seq: 1,
98
+ stream: "xg-harness-tools.plan",
99
+ ts: Date.now(),
100
+ sessionKey: "decoy-top-level-session-key",
101
+ // 顶层伪造一个同名但不存在于真实 AgentEventPayload 上的字段,确认代码不会误取
102
+ deliveryContext: { to: "decoy-top-level-group" },
103
+ data: makeBlockedPayload({ deliveryContext: { to: "real-group-from-data" } }),
104
+ };
105
+ await handle(event, FAKE_CTX);
106
+ assert.equal(recorder.calls.length, 1);
107
+ assert.equal(recorder.calls[0].groupId, "real-group-from-data");
108
+ });
109
+ });
110
+ describe("createPlanEventHandler: blocked payload 推送", () => {
111
+ it("assembles the spec §1.3 copy and calls sendText", async () => {
112
+ const recorder = new RecordingSendText();
113
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
114
+ const event = {
115
+ runId: "run-1",
116
+ seq: 1,
117
+ stream: "xg-harness-tools.plan",
118
+ ts: Date.now(),
119
+ data: makeBlockedPayload({
120
+ deliveryContext: { to: "group-1" },
121
+ goal: "迁移配置到新版本",
122
+ taskTitle: "备份旧配置",
123
+ blockedNote: "缺少权限",
124
+ }),
125
+ };
126
+ await handle(event, FAKE_CTX);
127
+ assert.equal(recorder.calls.length, 1);
128
+ assert.equal(recorder.calls[0].groupId, "group-1");
129
+ assert.equal(recorder.calls[0].content, "计划「迁移配置到新版本」卡在任务「备份旧配置」:缺少权限\n需要人工介入才能继续。");
130
+ });
131
+ it("does not push for non-blocked task status", async () => {
132
+ const recorder = new RecordingSendText();
133
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
134
+ const event = {
135
+ runId: "run-1",
136
+ seq: 1,
137
+ stream: "xg-harness-tools.plan",
138
+ ts: Date.now(),
139
+ data: makeBlockedPayload({
140
+ deliveryContext: { to: "group-1" },
141
+ taskStatus: "completed",
142
+ blockedNote: undefined,
143
+ }),
144
+ };
145
+ await handle(event, FAKE_CTX);
146
+ assert.equal(recorder.calls.length, 0);
147
+ });
148
+ it("does not push when no delivery target can be resolved", async () => {
149
+ const recorder = new RecordingSendText();
150
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
151
+ const event = {
152
+ runId: "run-1",
153
+ seq: 1,
154
+ stream: "xg-harness-tools.plan",
155
+ ts: Date.now(),
156
+ data: makeBlockedPayload(), // 无 deliveryContext/agentAccountId/messageChannel/sessionKey
157
+ };
158
+ await handle(event, FAKE_CTX);
159
+ assert.equal(recorder.calls.length, 0);
160
+ });
161
+ it("does not push when taskStatus is not blocked, even if blockedNote still carries a stale value (pins the taskStatus check)", async () => {
162
+ const recorder = new RecordingSendText();
163
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
164
+ const event = {
165
+ runId: "run-1",
166
+ seq: 1,
167
+ stream: "xg-harness-tools.plan",
168
+ ts: Date.now(),
169
+ data: makeBlockedPayload({
170
+ deliveryContext: { to: "group-1" },
171
+ taskStatus: "completed",
172
+ blockedNote: "缺少权限", // 上游残留的旧阻塞原因,taskStatus 已不再是 blocked
173
+ }),
174
+ };
175
+ await handle(event, FAKE_CTX);
176
+ assert.equal(recorder.calls.length, 0);
177
+ });
178
+ it("does not push when deliveryContext.to is an empty string, everything else valid (pins the empty-string check)", async () => {
179
+ const recorder = new RecordingSendText();
180
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
181
+ const event = {
182
+ runId: "run-1",
183
+ seq: 1,
184
+ stream: "xg-harness-tools.plan",
185
+ ts: Date.now(),
186
+ data: makeBlockedPayload({
187
+ deliveryContext: { to: "" },
188
+ }),
189
+ };
190
+ await handle(event, FAKE_CTX);
191
+ assert.equal(recorder.calls.length, 0);
192
+ });
193
+ it("does not push when deliveryContext.to is not a string", async () => {
194
+ const recorder = new RecordingSendText();
195
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
196
+ const event = {
197
+ runId: "run-1",
198
+ seq: 1,
199
+ stream: "xg-harness-tools.plan",
200
+ ts: Date.now(),
201
+ data: makeBlockedPayload({
202
+ deliveryContext: { to: 123 },
203
+ }),
204
+ };
205
+ await handle(event, FAKE_CTX);
206
+ assert.equal(recorder.calls.length, 0);
207
+ });
208
+ it("does not push when deliveryContext itself is not an object", async () => {
209
+ const recorder = new RecordingSendText();
210
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
211
+ const event = {
212
+ runId: "run-1",
213
+ seq: 1,
214
+ stream: "xg-harness-tools.plan",
215
+ ts: Date.now(),
216
+ data: makeBlockedPayload({
217
+ deliveryContext: "not-an-object",
218
+ }),
219
+ };
220
+ await handle(event, FAKE_CTX);
221
+ assert.equal(recorder.calls.length, 0);
222
+ });
223
+ it("does not push when blockedNote is whitespace-only, everything else valid (pins the trim/blank check)", async () => {
224
+ const recorder = new RecordingSendText();
225
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
226
+ const event = {
227
+ runId: "run-1",
228
+ seq: 1,
229
+ stream: "xg-harness-tools.plan",
230
+ ts: Date.now(),
231
+ data: makeBlockedPayload({
232
+ deliveryContext: { to: "group-1" },
233
+ blockedNote: " ",
234
+ }),
235
+ };
236
+ await handle(event, FAKE_CTX);
237
+ assert.equal(recorder.calls.length, 0);
238
+ });
239
+ });
240
+ describe("createPlanEventHandler: handle 内部出错不外泄", () => {
241
+ it("resolves normally even when sendText rejects", async () => {
242
+ const recorder = new RecordingSendText();
243
+ recorder.impl = async () => {
244
+ throw new Error("boom");
245
+ };
246
+ const handle = createPlanEventHandler({ sendText: recorder.sendText });
247
+ const event = {
248
+ runId: "run-1",
249
+ seq: 1,
250
+ stream: "xg-harness-tools.plan",
251
+ ts: Date.now(),
252
+ data: makeBlockedPayload({ deliveryContext: { to: "group-1" } }),
253
+ };
254
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
255
+ });
256
+ });
257
+ //# sourceMappingURL=plan-event-subscription.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-event-subscription.test.js","sourceRoot":"","sources":["../../src/plan-event-subscription.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { BlockedTaskNotice } from "./plan-blocked-notice.js";
2
+ export interface ToolCallTarget {
3
+ groupId: string;
4
+ token: string;
5
+ sessionKey?: string;
6
+ }
7
+ /** 测试用:替换时间源,避免测 TTL 时 sleep。 */
8
+ export declare function setNowFnForTest(fn: () => number): void;
9
+ export declare function registerToolCallTarget(toolCallId: string, target: ToolCallTarget): void;
10
+ /** 取出并删除(一次性消费)。未命中返回 undefined。 */
11
+ export declare function takeToolCallTarget(toolCallId: string): ToolCallTarget | undefined;
12
+ /**
13
+ * 传入本次扫描出的全部 notice,返回其中「需要推送的新增项」,并同步更新集合。
14
+ *
15
+ * 语义(按 DESIGN.md D2):
16
+ * - 新增 = 本次 keys − 已推送 keys → 返回它们
17
+ * - 清理 = 已推送集中「本次已不在」的 key → 移除(让 blocked→修复→再 blocked 能重新推)
18
+ * - 已推送集 = 已推送 ∪ 新增
19
+ * - 按 planId 分桶
20
+ */
21
+ export declare function diffAndMarkBlockedNotices(planId: string, notices: readonly BlockedTaskNotice[]): BlockedTaskNotice[];
22
+ /** 测试用:重置模块级缓存与 stateDir */
23
+ export declare function resetPlanSessionRegistryForTest(): void;
24
+ //# sourceMappingURL=plan-session-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-session-registry.d.ts","sourceRoot":"","sources":["../../src/plan-session-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAeD,iCAAiC;AACjC,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,MAAM,GAAG,IAAI,CAEtD;AA0BD,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAMvF;AAED,oCAAoC;AACpC,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAUjF;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS,iBAAiB,EAAE,GACtC,iBAAiB,EAAE,CAsBrB;AAED,4BAA4B;AAC5B,wBAAgB,+BAA+B,IAAI,IAAI,CAItD"}
@@ -0,0 +1,84 @@
1
+ /** toolCallId → 投递目标表的 TTL:超过这个时长未被消费的登记视为过期。 */
2
+ const TOOL_CALL_TARGET_TTL_MS = 10 * 60 * 1000;
3
+ /** toolCallId → 投递目标表的容量上限:超出时逐出最旧的条目(插入序)。 */
4
+ const TOOL_CALL_TARGET_CAPACITY = 500;
5
+ let nowFn = () => Date.now();
6
+ /** 测试用:替换时间源,避免测 TTL 时 sleep。 */
7
+ export function setNowFnForTest(fn) {
8
+ nowFn = fn;
9
+ }
10
+ const toolCallTargets = new Map();
11
+ /** planId → 已推送 blocked notice key 集合 */
12
+ const blockedNotifiedKeys = new Map();
13
+ function evictExpiredToolCallTargets() {
14
+ const now = nowFn();
15
+ for (const [toolCallId, entry] of toolCallTargets) {
16
+ if (now - entry.registeredAt > TOOL_CALL_TARGET_TTL_MS) {
17
+ toolCallTargets.delete(toolCallId);
18
+ }
19
+ }
20
+ }
21
+ function evictOldestToolCallTargetsOverCapacity() {
22
+ while (toolCallTargets.size > TOOL_CALL_TARGET_CAPACITY) {
23
+ const oldestKey = toolCallTargets.keys().next().value;
24
+ if (oldestKey === undefined) {
25
+ break;
26
+ }
27
+ toolCallTargets.delete(oldestKey);
28
+ }
29
+ }
30
+ export function registerToolCallTarget(toolCallId, target) {
31
+ evictExpiredToolCallTargets();
32
+ // 重新登记同一 id 应刷新插入序(视为新条目),先删再插
33
+ toolCallTargets.delete(toolCallId);
34
+ toolCallTargets.set(toolCallId, { target, registeredAt: nowFn() });
35
+ evictOldestToolCallTargetsOverCapacity();
36
+ }
37
+ /** 取出并删除(一次性消费)。未命中返回 undefined。 */
38
+ export function takeToolCallTarget(toolCallId) {
39
+ const entry = toolCallTargets.get(toolCallId);
40
+ if (!entry) {
41
+ return undefined;
42
+ }
43
+ toolCallTargets.delete(toolCallId);
44
+ if (nowFn() - entry.registeredAt > TOOL_CALL_TARGET_TTL_MS) {
45
+ return undefined;
46
+ }
47
+ return entry.target;
48
+ }
49
+ /**
50
+ * 传入本次扫描出的全部 notice,返回其中「需要推送的新增项」,并同步更新集合。
51
+ *
52
+ * 语义(按 DESIGN.md D2):
53
+ * - 新增 = 本次 keys − 已推送 keys → 返回它们
54
+ * - 清理 = 已推送集中「本次已不在」的 key → 移除(让 blocked→修复→再 blocked 能重新推)
55
+ * - 已推送集 = 已推送 ∪ 新增
56
+ * - 按 planId 分桶
57
+ */
58
+ export function diffAndMarkBlockedNotices(planId, notices) {
59
+ const notified = blockedNotifiedKeys.get(planId) ?? new Set();
60
+ const currentKeys = new Set(notices.map((n) => n.key));
61
+ const fresh = notices.filter((n) => !notified.has(n.key));
62
+ for (const key of notified) {
63
+ if (!currentKeys.has(key)) {
64
+ notified.delete(key);
65
+ }
66
+ }
67
+ for (const notice of fresh) {
68
+ notified.add(notice.key);
69
+ }
70
+ if (notified.size > 0) {
71
+ blockedNotifiedKeys.set(planId, notified);
72
+ }
73
+ else {
74
+ blockedNotifiedKeys.delete(planId);
75
+ }
76
+ return fresh;
77
+ }
78
+ /** 测试用:重置模块级缓存与 stateDir */
79
+ export function resetPlanSessionRegistryForTest() {
80
+ toolCallTargets.clear();
81
+ blockedNotifiedKeys.clear();
82
+ nowFn = () => Date.now();
83
+ }
84
+ //# sourceMappingURL=plan-session-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-session-registry.js","sourceRoot":"","sources":["../../src/plan-session-registry.ts"],"names":[],"mappings":"AAQA,iDAAiD;AACjD,MAAM,uBAAuB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE/C,+CAA+C;AAC/C,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAOtC,IAAI,KAAK,GAAiB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAE3C,iCAAiC;AACjC,MAAM,UAAU,eAAe,CAAC,EAAgB;IAC5C,KAAK,GAAG,EAAE,CAAC;AACf,CAAC;AAED,MAAM,eAAe,GAAG,IAAI,GAAG,EAA+B,CAAC;AAE/D,yCAAyC;AACzC,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAuB,CAAC;AAE3D,SAAS,2BAA2B;IAChC,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IACpB,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,eAAe,EAAE,CAAC;QAChD,IAAI,GAAG,GAAG,KAAK,CAAC,YAAY,GAAG,uBAAuB,EAAE,CAAC;YACrD,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;IACL,CAAC;AACL,CAAC;AAED,SAAS,sCAAsC;IAC3C,OAAO,eAAe,CAAC,IAAI,GAAG,yBAAyB,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACtD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM;QACV,CAAC;QACD,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAAkB,EAAE,MAAsB;IAC7E,2BAA2B,EAAE,CAAC;IAC9B,+BAA+B;IAC/B,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACnC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACnE,sCAAsC,EAAE,CAAC;AAC7C,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACjD,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACnC,IAAI,KAAK,EAAE,GAAG,KAAK,CAAC,YAAY,GAAG,uBAAuB,EAAE,CAAC;QACzD,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACrC,MAAc,EACd,OAAqC;IAErC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;IACtE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEvD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACL,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACpB,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;SAAM,CAAC;QACJ,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,+BAA+B;IAC3C,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,mBAAmB,CAAC,KAAK,EAAE,CAAC;IAC5B,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-session-registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-session-registry.test.d.ts","sourceRoot":"","sources":["../../src/plan-session-registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,109 @@
1
+ import assert from "node:assert/strict";
2
+ import { beforeEach, describe, it } from "node:test";
3
+ import { diffAndMarkBlockedNotices, registerToolCallTarget, resetPlanSessionRegistryForTest, setNowFnForTest, takeToolCallTarget, } from "./plan-session-registry.js";
4
+ function makeTarget(overrides = {}) {
5
+ return {
6
+ groupId: "group-1",
7
+ token: "token-1",
8
+ ...overrides,
9
+ };
10
+ }
11
+ function makeNotice(overrides = {}) {
12
+ return {
13
+ key: "plan-1::0::缺少权限",
14
+ taskIndex: 0,
15
+ taskTitle: "备份旧配置",
16
+ note: "缺少权限",
17
+ content: "计划「X」卡在任务「备份旧配置」:缺少权限\n需要人工介入才能继续。",
18
+ ...overrides,
19
+ };
20
+ }
21
+ beforeEach(() => {
22
+ resetPlanSessionRegistryForTest();
23
+ });
24
+ describe("registerToolCallTarget / takeToolCallTarget", () => {
25
+ it("hits with the registered target and deletes it on consume (take twice → second undefined)", () => {
26
+ registerToolCallTarget("call-1", makeTarget());
27
+ const first = takeToolCallTarget("call-1");
28
+ assert.deepEqual(first, makeTarget());
29
+ const second = takeToolCallTarget("call-1");
30
+ assert.equal(second, undefined);
31
+ });
32
+ it("misses for an unregistered id", () => {
33
+ assert.equal(takeToolCallTarget("does-not-exist"), undefined);
34
+ });
35
+ it("expires entries past TTL (injected now, no sleep)", () => {
36
+ let t = 0;
37
+ setNowFnForTest(() => t);
38
+ registerToolCallTarget("call-ttl", makeTarget());
39
+ t = 10 * 60 * 1000 + 1; // TTL + 1ms
40
+ assert.equal(takeToolCallTarget("call-ttl"), undefined);
41
+ });
42
+ it("does not expire an entry read exactly at TTL boundary", () => {
43
+ let t = 0;
44
+ setNowFnForTest(() => t);
45
+ registerToolCallTarget("call-boundary", makeTarget());
46
+ t = 10 * 60 * 1000; // exactly TTL, not yet exceeded
47
+ assert.ok(takeToolCallTarget("call-boundary"));
48
+ });
49
+ it("evicts the oldest entry when capacity is exceeded", () => {
50
+ let t = 0;
51
+ setNowFnForTest(() => t);
52
+ for (let i = 0; i < 500; i++) {
53
+ t += 1;
54
+ registerToolCallTarget(`call-${i}`, makeTarget({ groupId: `g${i}` }));
55
+ }
56
+ // 表已满 500 条,call-0 是最旧的
57
+ t += 1;
58
+ registerToolCallTarget("call-500", makeTarget({ groupId: "g500" }));
59
+ assert.equal(takeToolCallTarget("call-0"), undefined, "oldest entry should have been evicted");
60
+ const kept = takeToolCallTarget("call-500");
61
+ assert.ok(kept);
62
+ assert.equal(kept.groupId, "g500");
63
+ });
64
+ });
65
+ describe("diffAndMarkBlockedNotices", () => {
66
+ it("returns all notices on first call", () => {
67
+ const notices = [makeNotice()];
68
+ const fresh = diffAndMarkBlockedNotices("plan-1", notices);
69
+ assert.deepEqual(fresh, notices);
70
+ });
71
+ it("returns empty on repeated identical call", () => {
72
+ const notices = [makeNotice()];
73
+ diffAndMarkBlockedNotices("plan-1", notices);
74
+ const second = diffAndMarkBlockedNotices("plan-1", notices);
75
+ assert.deepEqual(second, []);
76
+ });
77
+ it("treats a note change as a new notification (different key)", () => {
78
+ const first = [makeNotice({ key: "plan-1::0::缺少权限" })];
79
+ diffAndMarkBlockedNotices("plan-1", first);
80
+ const changed = [makeNotice({ key: "plan-1::0::权限问题已升级", note: "权限问题已升级" })];
81
+ const fresh = diffAndMarkBlockedNotices("plan-1", changed);
82
+ assert.deepEqual(fresh, changed);
83
+ });
84
+ it("clears a key once the task is no longer blocked, allowing re-notification later", () => {
85
+ const notice = makeNotice({ key: "plan-1::0::缺少权限" });
86
+ diffAndMarkBlockedNotices("plan-1", [notice]);
87
+ // task 修复:本次扫描不再含该 key
88
+ const clearedFresh = diffAndMarkBlockedNotices("plan-1", []);
89
+ assert.deepEqual(clearedFresh, []);
90
+ // 再次 blocked,同 key 应视为新增重新推送
91
+ const reblocked = diffAndMarkBlockedNotices("plan-1", [notice]);
92
+ assert.deepEqual(reblocked, [notice]);
93
+ });
94
+ it("keeps separate planIds independent", () => {
95
+ const noticeA = makeNotice({ key: "plan-a::0::原因A" });
96
+ const noticeB = makeNotice({ key: "plan-b::0::原因B" });
97
+ const freshA = diffAndMarkBlockedNotices("plan-a", [noticeA]);
98
+ const freshB = diffAndMarkBlockedNotices("plan-b", [noticeB]);
99
+ assert.deepEqual(freshA, [noticeA]);
100
+ assert.deepEqual(freshB, [noticeB]);
101
+ // plan-a 重复调用不应受 plan-b 影响,反之亦然
102
+ assert.deepEqual(diffAndMarkBlockedNotices("plan-a", [noticeA]), []);
103
+ assert.deepEqual(diffAndMarkBlockedNotices("plan-b", [noticeB]), []);
104
+ });
105
+ it("returns an empty array and does not throw when there are no notices", () => {
106
+ assert.deepEqual(diffAndMarkBlockedNotices("plan-empty", []), []);
107
+ });
108
+ });
109
+ //# sourceMappingURL=plan-session-registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-session-registry.test.js","sourceRoot":"","sources":["../../src/plan-session-registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Plan, PlanSummary } from "@xgjktech/xg-openclaw-shared";
2
+ /** 注入 stateDir(来自 api.runtime.state.resolveStateDir())。register(api) 时调用一次。 */
3
+ export declare function setPlanStateDir(dir: string): void;
4
+ /** 测试用:重置模块级缓存与 stateDir */
5
+ export declare function resetPlanStoreAccessForTest(): void;
6
+ /**
7
+ * 按 planId 反查完整计划。
8
+ * 库不存在 / 打开失败 / 读取异常 → 返回 undefined 并记 warn 日志,绝不抛。
9
+ */
10
+ export declare function getPlanById(planId: string): Plan | undefined;
11
+ /**
12
+ * 列出全部计划摘要(重启恢复用)。
13
+ * 异常同上 → 返回空数组,绝不抛。
14
+ */
15
+ export declare function listPlanSummaries(): PlanSummary[];
16
+ //# sourceMappingURL=plan-store-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-store-access.d.ts","sourceRoot":"","sources":["../../src/plan-store-access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAWtE,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,4BAA4B;AAC5B,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD;AAyBD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAY5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,EAAE,CAYjD"}
@@ -0,0 +1,76 @@
1
+ import { openPlanStoreReadonly, resolvePlanDbPath } from "@xgjktech/xg-openclaw-shared";
2
+ const LOG_PREFIX = "[xg_cwork_im] [plan-store]";
3
+ let stateDir;
4
+ let handle;
5
+ let warnedNoStateDir = false;
6
+ /** 注入 stateDir(来自 api.runtime.state.resolveStateDir())。register(api) 时调用一次。 */
7
+ export function setPlanStateDir(dir) {
8
+ stateDir = dir;
9
+ handle = undefined;
10
+ warnedNoStateDir = false;
11
+ }
12
+ /** 测试用:重置模块级缓存与 stateDir */
13
+ export function resetPlanStoreAccessForTest() {
14
+ stateDir = undefined;
15
+ handle = undefined;
16
+ warnedNoStateDir = false;
17
+ }
18
+ function getHandle() {
19
+ if (handle) {
20
+ return handle;
21
+ }
22
+ if (!stateDir) {
23
+ if (!warnedNoStateDir) {
24
+ console.warn(`${LOG_PREFIX} stateDir 未设置,无法打开计划库`);
25
+ warnedNoStateDir = true;
26
+ }
27
+ return undefined;
28
+ }
29
+ let dbPath = "<unresolved>";
30
+ try {
31
+ dbPath = resolvePlanDbPath(stateDir);
32
+ handle = openPlanStoreReadonly(dbPath);
33
+ return handle;
34
+ }
35
+ catch (cause) {
36
+ console.warn(`${LOG_PREFIX} 打开计划库失败 dbPath=${dbPath} 原因=${String(cause)}`);
37
+ return undefined;
38
+ }
39
+ }
40
+ /**
41
+ * 按 planId 反查完整计划。
42
+ * 库不存在 / 打开失败 / 读取异常 → 返回 undefined 并记 warn 日志,绝不抛。
43
+ */
44
+ export function getPlanById(planId) {
45
+ const h = getHandle();
46
+ if (!h) {
47
+ return undefined;
48
+ }
49
+ try {
50
+ return h.get(planId);
51
+ }
52
+ catch (cause) {
53
+ console.warn(`${LOG_PREFIX} 读取 plan 失败 planId=${planId} 原因=${String(cause)}`);
54
+ handle = undefined;
55
+ return undefined;
56
+ }
57
+ }
58
+ /**
59
+ * 列出全部计划摘要(重启恢复用)。
60
+ * 异常同上 → 返回空数组,绝不抛。
61
+ */
62
+ export function listPlanSummaries() {
63
+ const h = getHandle();
64
+ if (!h) {
65
+ return [];
66
+ }
67
+ try {
68
+ return h.list();
69
+ }
70
+ catch (cause) {
71
+ console.warn(`${LOG_PREFIX} 列出 plan 列表失败 原因=${String(cause)}`);
72
+ handle = undefined;
73
+ return [];
74
+ }
75
+ }
76
+ //# sourceMappingURL=plan-store-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-store-access.js","sourceRoot":"","sources":["../../src/plan-store-access.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAIxF,MAAM,UAAU,GAAG,4BAA4B,CAAC;AAEhD,IAAI,QAA4B,CAAC;AACjC,IAAI,MAA2C,CAAC;AAChD,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,GAAW;IACvC,QAAQ,GAAG,GAAG,CAAC;IACf,MAAM,GAAG,SAAS,CAAC;IACnB,gBAAgB,GAAG,KAAK,CAAC;AAC7B,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,2BAA2B;IACvC,QAAQ,GAAG,SAAS,CAAC;IACrB,MAAM,GAAG,SAAS,CAAC;IACnB,gBAAgB,GAAG,KAAK,CAAC;AAC7B,CAAC;AAED,SAAS,SAAS;IACd,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,uBAAuB,CAAC,CAAC;YACnD,gBAAgB,GAAG,IAAI,CAAC;QAC5B,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,GAAG,cAAc,CAAC;IAC5B,IAAI,CAAC;QACD,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACvC,OAAO,MAAM,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,mBAAmB,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3E,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACtC,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,CAAC;QACD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,sBAAsB,MAAM,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9E,MAAM,GAAG,SAAS,CAAC;QACnB,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC7B,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;IACtB,IAAI,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,oBAAoB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/D,MAAM,GAAG,SAAS,CAAC;QACnB,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-store-access.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-store-access.test.d.ts","sourceRoot":"","sources":["../../src/plan-store-access.test.ts"],"names":[],"mappings":""}