@xgjktech/xg_cwork_im 1.17.2 → 1.17.4

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 (80) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +28 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/src/agent-stream-client-registry.d.ts +4 -0
  5. package/dist/src/agent-stream-client-registry.d.ts.map +1 -0
  6. package/dist/src/agent-stream-client-registry.js +8 -0
  7. package/dist/src/agent-stream-client-registry.js.map +1 -0
  8. package/dist/src/channel.d.ts.map +1 -1
  9. package/dist/src/channel.js +2 -0
  10. package/dist/src/channel.js.map +1 -1
  11. package/dist/src/connection.d.ts +1 -1
  12. package/dist/src/connection.d.ts.map +1 -1
  13. package/dist/src/dispatch-mentioned-reply.d.ts +1 -0
  14. package/dist/src/dispatch-mentioned-reply.d.ts.map +1 -1
  15. package/dist/src/dispatch-mentioned-reply.js +5 -3
  16. package/dist/src/dispatch-mentioned-reply.js.map +1 -1
  17. package/dist/src/gateway-session-queue.d.ts +1 -0
  18. package/dist/src/gateway-session-queue.d.ts.map +1 -1
  19. package/dist/src/plan-blocked-notice.d.ts +14 -0
  20. package/dist/src/plan-blocked-notice.d.ts.map +1 -0
  21. package/dist/src/plan-blocked-notice.js +41 -0
  22. package/dist/src/plan-blocked-notice.js.map +1 -0
  23. package/dist/src/plan-blocked-notice.test.d.ts +2 -0
  24. package/dist/src/plan-blocked-notice.test.d.ts.map +1 -0
  25. package/dist/src/plan-blocked-notice.test.js +96 -0
  26. package/dist/src/plan-blocked-notice.test.js.map +1 -0
  27. package/dist/src/plan-event-subscription.d.ts +36 -0
  28. package/dist/src/plan-event-subscription.d.ts.map +1 -0
  29. package/dist/src/plan-event-subscription.js +57 -0
  30. package/dist/src/plan-event-subscription.js.map +1 -0
  31. package/dist/src/plan-event-subscription.test.d.ts +2 -0
  32. package/dist/src/plan-event-subscription.test.d.ts.map +1 -0
  33. package/dist/src/plan-event-subscription.test.js +167 -0
  34. package/dist/src/plan-event-subscription.test.js.map +1 -0
  35. package/dist/src/plan-stat-event.d.ts +28 -0
  36. package/dist/src/plan-stat-event.d.ts.map +1 -0
  37. package/dist/src/plan-stat-event.js +68 -0
  38. package/dist/src/plan-stat-event.js.map +1 -0
  39. package/dist/src/plan-stat-event.test.d.ts +2 -0
  40. package/dist/src/plan-stat-event.test.d.ts.map +1 -0
  41. package/dist/src/plan-stat-event.test.js +167 -0
  42. package/dist/src/plan-stat-event.test.js.map +1 -0
  43. package/dist/src/plan-store-access.d.ts +23 -0
  44. package/dist/src/plan-store-access.d.ts.map +1 -0
  45. package/dist/src/plan-store-access.js +96 -0
  46. package/dist/src/plan-store-access.js.map +1 -0
  47. package/dist/src/plan-store-access.test.d.ts +2 -0
  48. package/dist/src/plan-store-access.test.d.ts.map +1 -0
  49. package/dist/src/plan-store-access.test.js +207 -0
  50. package/dist/src/plan-store-access.test.js.map +1 -0
  51. package/dist/src/plan-tool-middleware.d.ts +22 -0
  52. package/dist/src/plan-tool-middleware.d.ts.map +1 -0
  53. package/dist/src/plan-tool-middleware.js +85 -0
  54. package/dist/src/plan-tool-middleware.js.map +1 -0
  55. package/dist/src/plan-tool-middleware.test.d.ts +2 -0
  56. package/dist/src/plan-tool-middleware.test.d.ts.map +1 -0
  57. package/dist/src/plan-tool-middleware.test.js +488 -0
  58. package/dist/src/plan-tool-middleware.test.js.map +1 -0
  59. package/dist/src/plan-tool-result.d.ts +20 -0
  60. package/dist/src/plan-tool-result.d.ts.map +1 -0
  61. package/dist/src/plan-tool-result.js +78 -0
  62. package/dist/src/plan-tool-result.js.map +1 -0
  63. package/dist/src/plan-tool-result.test.d.ts +2 -0
  64. package/dist/src/plan-tool-result.test.d.ts.map +1 -0
  65. package/dist/src/plan-tool-result.test.js +107 -0
  66. package/dist/src/plan-tool-result.test.js.map +1 -0
  67. package/dist/src/plan-ws-registry.d.ts +11 -0
  68. package/dist/src/plan-ws-registry.d.ts.map +1 -0
  69. package/dist/src/plan-ws-registry.js +27 -0
  70. package/dist/src/plan-ws-registry.js.map +1 -0
  71. package/dist/src/plan-ws-registry.test.d.ts +2 -0
  72. package/dist/src/plan-ws-registry.test.d.ts.map +1 -0
  73. package/dist/src/plan-ws-registry.test.js +43 -0
  74. package/dist/src/plan-ws-registry.test.js.map +1 -0
  75. package/dist/src/subagent-monitor.d.ts +3 -14
  76. package/dist/src/subagent-monitor.d.ts.map +1 -1
  77. package/dist/src/subagent-monitor.js +34 -35
  78. package/dist/src/subagent-monitor.js.map +1 -1
  79. package/openclaw.plugin.json +2 -1
  80. package/package.json +7 -3
@@ -0,0 +1,488 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { createPlanToolResultMiddleware } from "./plan-tool-middleware.js";
4
+ const FAKE_CTX = { runtime: "openclaw" };
5
+ function makePlan(overrides = {}) {
6
+ return {
7
+ planId: "plan-1",
8
+ goal: "迁移配置到新版本",
9
+ createdAt: "2026-07-27T00:00:00.000Z",
10
+ updatedAt: "2026-07-27T00:00:00.000Z",
11
+ tasks: [],
12
+ ...overrides,
13
+ };
14
+ }
15
+ function makeEvent(overrides) {
16
+ const content = overrides.text !== undefined
17
+ ? [{ type: "text", text: overrides.text }]
18
+ : [];
19
+ return {
20
+ toolCallId: overrides.toolCallId ?? "call-1",
21
+ toolName: overrides.toolName ?? "xg_plan_write",
22
+ args: {},
23
+ result: {
24
+ details: overrides.details,
25
+ content,
26
+ },
27
+ };
28
+ }
29
+ function makeSuccessPayload(plan, withEvent = false) {
30
+ return {
31
+ ok: true,
32
+ planId: plan.planId,
33
+ plan,
34
+ ...(withEvent ? { event: { emitted: false, reason: "no runId" } } : {}),
35
+ };
36
+ }
37
+ class RecordingDeps {
38
+ planById = new Map();
39
+ planStatCalls = [];
40
+ sendPlanStatImpl = (params) => {
41
+ this.planStatCalls.push(params);
42
+ };
43
+ getPlanById = (planId) => {
44
+ return this.planById.get(planId);
45
+ };
46
+ sendPlanStat = (params) => {
47
+ this.sendPlanStatImpl(params);
48
+ };
49
+ }
50
+ /** 临时替换 console.warn 统计 [plan-telemetry] 行数,测试结束务必还原。 */
51
+ function captureTelemetryLines(fn) {
52
+ const original = console.warn;
53
+ const lines = [];
54
+ console.warn = (...args) => {
55
+ const line = args.map(String).join(" ");
56
+ if (line.includes("[plan-telemetry]")) {
57
+ lines.push(line);
58
+ }
59
+ };
60
+ try {
61
+ fn();
62
+ }
63
+ finally {
64
+ console.warn = original;
65
+ }
66
+ return lines;
67
+ }
68
+ describe("createPlanToolResultMiddleware: 非 plan 工具直接放行", () => {
69
+ it("does not touch getPlanById or emit telemetry for unrelated tools", () => {
70
+ const deps = new RecordingDeps();
71
+ let getPlanByIdCalled = false;
72
+ deps.getPlanById = (planId) => {
73
+ getPlanByIdCalled = true;
74
+ return deps.planById.get(planId);
75
+ };
76
+ const handler = createPlanToolResultMiddleware(deps);
77
+ const event = makeEvent({
78
+ toolName: "some_other_tool",
79
+ details: { ok: true, data: 123 },
80
+ });
81
+ const lines = captureTelemetryLines(() => {
82
+ const result = handler(event, FAKE_CTX);
83
+ assert.equal(result, undefined);
84
+ });
85
+ assert.equal(getPlanByIdCalled, false);
86
+ assert.equal(lines.length, 0);
87
+ });
88
+ it("does not emit telemetry even when a non-plan tool's details is a structurally valid plan payload (pins the name filter)", () => {
89
+ const deps = new RecordingDeps();
90
+ const handler = createPlanToolResultMiddleware(deps);
91
+ const plan = makePlan({ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }] });
92
+ const event = makeEvent({
93
+ toolCallId: "call-evil",
94
+ toolName: "some_evil_tool",
95
+ details: makeSuccessPayload(plan),
96
+ });
97
+ const lines = captureTelemetryLines(() => {
98
+ const result = handler(event, FAKE_CTX);
99
+ assert.equal(result, undefined);
100
+ });
101
+ assert.equal(lines.length, 0);
102
+ });
103
+ });
104
+ describe("createPlanToolResultMiddleware: details 路径", () => {
105
+ it("emits a telemetry line when details carries a valid plan with a blocked task", () => {
106
+ const deps = new RecordingDeps();
107
+ const handler = createPlanToolResultMiddleware(deps);
108
+ const plan = makePlan({
109
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
110
+ });
111
+ const event = makeEvent({
112
+ toolCallId: "call-1",
113
+ toolName: "xg_plan_write",
114
+ details: makeSuccessPayload(plan),
115
+ });
116
+ const lines = captureTelemetryLines(() => {
117
+ const result = handler(event, FAKE_CTX);
118
+ assert.equal(result, undefined);
119
+ });
120
+ assert.equal(lines.length, 1);
121
+ assert.ok(lines[0].includes("备份旧配置"));
122
+ assert.ok(lines[0].includes("缺少权限"));
123
+ });
124
+ });
125
+ describe("createPlanToolResultMiddleware: text 回退路径", () => {
126
+ it("falls back to content[0].text when details is undefined", () => {
127
+ const deps = new RecordingDeps();
128
+ const handler = createPlanToolResultMiddleware(deps);
129
+ const plan = makePlan({
130
+ planId: "plan-2",
131
+ tasks: [{ title: "校验数据", status: "blocked", note: "依赖未就绪" }],
132
+ });
133
+ const rawBody = JSON.stringify(makeSuccessPayload(plan, true), null, 2);
134
+ const event = makeEvent({
135
+ toolCallId: "call-2",
136
+ toolName: "xg_plan_execute",
137
+ details: undefined,
138
+ text: rawBody,
139
+ });
140
+ const lines = captureTelemetryLines(() => {
141
+ const result = handler(event, FAKE_CTX);
142
+ assert.equal(result, undefined);
143
+ });
144
+ assert.equal(lines.length, 1);
145
+ assert.ok(lines[0].includes("校验数据"));
146
+ });
147
+ it("uses getPlanById authoritative state when details is missing (D5/RULING-1 §3)", () => {
148
+ const deps = new RecordingDeps();
149
+ const handler = createPlanToolResultMiddleware(deps);
150
+ // text 路径拿到的 plan 里没有 blocked task,但权威反查里有
151
+ const textPlan = makePlan({ planId: "plan-3", tasks: [{ title: "t1", status: "pending" }] });
152
+ const authoritativePlan = makePlan({
153
+ planId: "plan-3",
154
+ tasks: [{ title: "t1", status: "blocked", note: "authoritative 才有的阻塞" }],
155
+ });
156
+ deps.planById.set("plan-3", authoritativePlan);
157
+ const rawBody = JSON.stringify(makeSuccessPayload(textPlan), null, 2);
158
+ const event = makeEvent({
159
+ toolCallId: "call-3",
160
+ toolName: "xg_plan_write",
161
+ details: undefined,
162
+ text: rawBody,
163
+ });
164
+ const lines = captureTelemetryLines(() => {
165
+ handler(event, FAKE_CTX);
166
+ });
167
+ assert.equal(lines.length, 1);
168
+ assert.ok(lines[0].includes("authoritative 才有的阻塞"));
169
+ });
170
+ });
171
+ describe("createPlanToolResultMiddleware: 守卫拒绝畸形 payload", () => {
172
+ it("does not emit telemetry for ok:false", () => {
173
+ const deps = new RecordingDeps();
174
+ const handler = createPlanToolResultMiddleware(deps);
175
+ const event = makeEvent({
176
+ toolCallId: "call-4",
177
+ toolName: "xg_plan_write",
178
+ details: { ok: false, error: { code: "PLAN_NOT_FOUND" } },
179
+ });
180
+ const lines = captureTelemetryLines(() => {
181
+ assert.equal(handler(event, FAKE_CTX), undefined);
182
+ });
183
+ assert.equal(lines.length, 0);
184
+ });
185
+ it("does not emit telemetry when planId is missing", () => {
186
+ const deps = new RecordingDeps();
187
+ const handler = createPlanToolResultMiddleware(deps);
188
+ const event = makeEvent({
189
+ toolCallId: "call-5",
190
+ toolName: "xg_plan_write",
191
+ details: { ok: true, plan: makePlan() },
192
+ });
193
+ const lines = captureTelemetryLines(() => {
194
+ assert.equal(handler(event, FAKE_CTX), undefined);
195
+ });
196
+ assert.equal(lines.length, 0);
197
+ });
198
+ it("does not emit telemetry when tasks is not an array", () => {
199
+ const deps = new RecordingDeps();
200
+ const handler = createPlanToolResultMiddleware(deps);
201
+ const event = makeEvent({
202
+ toolCallId: "call-6",
203
+ toolName: "xg_plan_write",
204
+ details: {
205
+ ok: true,
206
+ planId: "plan-6",
207
+ plan: { planId: "plan-6", goal: "g", createdAt: "t", updatedAt: "t", tasks: "not-an-array" },
208
+ },
209
+ });
210
+ const lines = captureTelemetryLines(() => {
211
+ assert.equal(handler(event, FAKE_CTX), undefined);
212
+ });
213
+ assert.equal(lines.length, 0);
214
+ });
215
+ });
216
+ describe("createPlanToolResultMiddleware: handler 内部出错不外抛", () => {
217
+ it("resolves normally even when getPlanById throws", () => {
218
+ const deps = new RecordingDeps();
219
+ deps.getPlanById = () => {
220
+ throw new Error("boom");
221
+ };
222
+ const handler = createPlanToolResultMiddleware(deps);
223
+ const plan = makePlan({ planId: "plan-8", tasks: [{ title: "t1", status: "blocked", note: "n" }] });
224
+ const rawBody = JSON.stringify(makeSuccessPayload(plan), null, 2);
225
+ const event = makeEvent({
226
+ toolCallId: "call-8",
227
+ toolName: "xg_plan_write",
228
+ details: undefined,
229
+ text: rawBody,
230
+ });
231
+ assert.doesNotThrow(() => handler(event, FAKE_CTX));
232
+ });
233
+ });
234
+ describe("createPlanToolResultMiddleware: 恒返回 void(同步性断言)", () => {
235
+ // 本任务 handler 已无异步出口(推群没了)。TASK-2x-4 引入 sendPlanStat 的
236
+ // fire-and-forget 之后,这条要恢复成"even when 内部 promise 永不 resolve 仍立即返回"的真实用例。
237
+ it("handler's return value is undefined and the call itself is synchronous", () => {
238
+ const deps = new RecordingDeps();
239
+ const handler = createPlanToolResultMiddleware(deps);
240
+ const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
241
+ const event = makeEvent({
242
+ toolCallId: "call-9",
243
+ toolName: "xg_plan_write",
244
+ details: makeSuccessPayload(plan),
245
+ });
246
+ const result = handler(event, FAKE_CTX);
247
+ assert.equal(result, undefined);
248
+ });
249
+ });
250
+ describe("createPlanToolResultMiddleware: [plan-telemetry] 遥测行为(D2)", () => {
251
+ it("plan 含 1 个 blocked task → 恰好打 1 行,内容含 planId/taskIndex/taskTitle/note/goal", () => {
252
+ const deps = new RecordingDeps();
253
+ const handler = createPlanToolResultMiddleware(deps);
254
+ const plan = makePlan({
255
+ planId: "plan-telemetry-1",
256
+ goal: "迁移配置到新版本",
257
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
258
+ });
259
+ const event = makeEvent({
260
+ toolCallId: "call-t1",
261
+ toolName: "xg_plan_execute",
262
+ details: makeSuccessPayload(plan),
263
+ });
264
+ const lines = captureTelemetryLines(() => {
265
+ handler(event, FAKE_CTX);
266
+ });
267
+ assert.equal(lines.length, 1);
268
+ const jsonPart = lines[0].slice(lines[0].indexOf("{"));
269
+ const parsed = JSON.parse(jsonPart);
270
+ assert.equal(parsed.planId, "plan-telemetry-1");
271
+ assert.equal(parsed.taskIndex, 0);
272
+ assert.equal(parsed.taskTitle, "备份旧配置");
273
+ assert.equal(parsed.note, "缺少权限");
274
+ assert.equal(parsed.goal, "迁移配置到新版本");
275
+ assert.equal(parsed.toolName, "xg_plan_execute");
276
+ });
277
+ it("plan 含 2 个 blocked task → 打 2 行,顺序与 tasks 下标一致", () => {
278
+ const deps = new RecordingDeps();
279
+ const handler = createPlanToolResultMiddleware(deps);
280
+ const plan = makePlan({
281
+ tasks: [
282
+ { title: "备份旧配置", status: "blocked", note: "缺少权限" },
283
+ { title: "校验数据", status: "pending" },
284
+ { title: "切换流量", status: "blocked", note: "依赖未就绪" },
285
+ ],
286
+ });
287
+ const event = makeEvent({
288
+ toolCallId: "call-t2",
289
+ toolName: "xg_plan_write",
290
+ details: makeSuccessPayload(plan),
291
+ });
292
+ const lines = captureTelemetryLines(() => {
293
+ handler(event, FAKE_CTX);
294
+ });
295
+ assert.equal(lines.length, 2);
296
+ const first = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
297
+ const second = JSON.parse(lines[1].slice(lines[1].indexOf("{")));
298
+ assert.equal(first.taskIndex, 0);
299
+ assert.equal(second.taskIndex, 2);
300
+ });
301
+ it("无 blocked task → 不打任何遥测行", () => {
302
+ const deps = new RecordingDeps();
303
+ const handler = createPlanToolResultMiddleware(deps);
304
+ const plan = makePlan({
305
+ tasks: [{ title: "t1", status: "pending" }, { title: "t2", status: "completed" }],
306
+ });
307
+ const event = makeEvent({
308
+ toolCallId: "call-t3",
309
+ toolName: "xg_plan_write",
310
+ details: makeSuccessPayload(plan),
311
+ });
312
+ const lines = captureTelemetryLines(() => {
313
+ handler(event, FAKE_CTX);
314
+ });
315
+ assert.equal(lines.length, 0);
316
+ });
317
+ it("🔴 同一 plan、同一 blocked、连续两次 middleware 事件 → 打 2 行(钉住不去重)", () => {
318
+ const deps = new RecordingDeps();
319
+ const handler = createPlanToolResultMiddleware(deps);
320
+ const plan = makePlan({
321
+ planId: "plan-no-dedup",
322
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
323
+ });
324
+ const event = makeEvent({
325
+ toolCallId: "call-t4",
326
+ toolName: "xg_plan_write",
327
+ details: makeSuccessPayload(plan),
328
+ });
329
+ const lines = captureTelemetryLines(() => {
330
+ handler(event, FAKE_CTX);
331
+ handler(event, FAKE_CTX);
332
+ });
333
+ assert.equal(lines.length, 2, "不去重:同一 blocked 连续两次事件应各打一行");
334
+ });
335
+ it("plan 带 origin → 日志行含 channel/to/sessionKey", () => {
336
+ const deps = new RecordingDeps();
337
+ const handler = createPlanToolResultMiddleware(deps);
338
+ const plan = makePlan({
339
+ tasks: [{ title: "t1", status: "blocked", note: "n" }],
340
+ origin: { channel: "xg_cwork_im", to: "g-123", sessionKey: "sess-1" },
341
+ });
342
+ const event = makeEvent({
343
+ toolCallId: "call-t5",
344
+ toolName: "xg_plan_write",
345
+ details: makeSuccessPayload(plan),
346
+ });
347
+ const lines = captureTelemetryLines(() => {
348
+ handler(event, FAKE_CTX);
349
+ });
350
+ assert.equal(lines.length, 1);
351
+ const parsed = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
352
+ assert.equal(parsed.channel, "xg_cwork_im");
353
+ assert.equal(parsed.to, "g-123");
354
+ assert.equal(parsed.sessionKey, "sess-1");
355
+ });
356
+ it("🔴 plan 无 origin(旧数据)→ 日志行不含这几个键,且照常打日志、不抛、不跳过", () => {
357
+ const deps = new RecordingDeps();
358
+ const handler = createPlanToolResultMiddleware(deps);
359
+ const plan = makePlan({
360
+ tasks: [{ title: "t1", status: "blocked", note: "n" }],
361
+ });
362
+ const event = makeEvent({
363
+ toolCallId: "call-t6",
364
+ toolName: "xg_plan_write",
365
+ details: makeSuccessPayload(plan),
366
+ });
367
+ const lines = captureTelemetryLines(() => {
368
+ assert.doesNotThrow(() => handler(event, FAKE_CTX));
369
+ });
370
+ assert.equal(lines.length, 1);
371
+ const parsed = JSON.parse(lines[0].slice(lines[0].indexOf("{")));
372
+ assert.equal("channel" in parsed, false);
373
+ assert.equal("to" in parsed, false);
374
+ assert.equal("sessionKey" in parsed, false);
375
+ });
376
+ it("blocked task 的 note 为空/空白 → 该条不产出遥测", () => {
377
+ const deps = new RecordingDeps();
378
+ const handler = createPlanToolResultMiddleware(deps);
379
+ const plan = makePlan({
380
+ tasks: [
381
+ { title: "无 note", status: "blocked" },
382
+ { title: "空白 note", status: "blocked", note: " " },
383
+ ],
384
+ });
385
+ const event = makeEvent({
386
+ toolCallId: "call-t7",
387
+ toolName: "xg_plan_write",
388
+ details: makeSuccessPayload(plan),
389
+ });
390
+ const lines = captureTelemetryLines(() => {
391
+ handler(event, FAKE_CTX);
392
+ });
393
+ assert.equal(lines.length, 0);
394
+ });
395
+ });
396
+ describe("createPlanToolResultMiddleware: PLAN_STAT 增量推送(D3)", () => {
397
+ it("plan_write 成功 → 发 1 条 PLAN_STAT,source === \"tool\"", () => {
398
+ const deps = new RecordingDeps();
399
+ const handler = createPlanToolResultMiddleware(deps);
400
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
401
+ const event = makeEvent({
402
+ toolCallId: "call-ps1",
403
+ toolName: "xg_plan_write",
404
+ details: makeSuccessPayload(plan),
405
+ });
406
+ handler(event, FAKE_CTX);
407
+ assert.equal(deps.planStatCalls.length, 1);
408
+ assert.equal(deps.planStatCalls[0].source, "tool");
409
+ assert.equal(deps.planStatCalls[0].plan.planId, plan.planId);
410
+ });
411
+ it("plan_execute 成功(start_task/block_task/complete_task)→ 各发 1 条", () => {
412
+ const actions = [
413
+ { toolCallId: "call-ps2", plan: makePlan({ tasks: [{ title: "t1", status: "in_progress" }] }) },
414
+ {
415
+ toolCallId: "call-ps3",
416
+ plan: makePlan({ tasks: [{ title: "t1", status: "blocked", note: "缺少权限" }] }),
417
+ },
418
+ { toolCallId: "call-ps4", plan: makePlan({ tasks: [{ title: "t1", status: "completed" }] }) },
419
+ ];
420
+ for (const { toolCallId, plan } of actions) {
421
+ const deps = new RecordingDeps();
422
+ const handler = createPlanToolResultMiddleware(deps);
423
+ const event = makeEvent({
424
+ toolCallId,
425
+ toolName: "xg_plan_execute",
426
+ details: makeSuccessPayload(plan),
427
+ });
428
+ handler(event, FAKE_CTX);
429
+ assert.equal(deps.planStatCalls.length, 1, `action status=${plan.tasks[0].status} 应发 1 条`);
430
+ assert.equal(deps.planStatCalls[0].source, "tool");
431
+ }
432
+ });
433
+ it("🔴 工具返回 ok:false → 不发 PLAN_STAT(失败不发)", () => {
434
+ const deps = new RecordingDeps();
435
+ const handler = createPlanToolResultMiddleware(deps);
436
+ const event = makeEvent({
437
+ toolCallId: "call-ps5",
438
+ toolName: "xg_plan_write",
439
+ details: { ok: false, error: { code: "PLAN_NOT_FOUND" } },
440
+ });
441
+ handler(event, FAKE_CTX);
442
+ assert.equal(deps.planStatCalls.length, 0);
443
+ });
444
+ it("🔴 非 plan 工具 → 不发 PLAN_STAT", () => {
445
+ const deps = new RecordingDeps();
446
+ const handler = createPlanToolResultMiddleware(deps);
447
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
448
+ const event = makeEvent({
449
+ toolCallId: "call-ps6",
450
+ toolName: "some_other_tool",
451
+ details: makeSuccessPayload(plan),
452
+ });
453
+ handler(event, FAKE_CTX);
454
+ assert.equal(deps.planStatCalls.length, 0);
455
+ });
456
+ it("🔴 sendPlanStat 内部抛异常 → handler 不外抛、仍返回 void(红线回归)", () => {
457
+ const deps = new RecordingDeps();
458
+ deps.sendPlanStatImpl = () => {
459
+ throw new Error("boom");
460
+ };
461
+ const handler = createPlanToolResultMiddleware(deps);
462
+ const plan = makePlan({ tasks: [{ title: "t1", status: "pending" }] });
463
+ const event = makeEvent({
464
+ toolCallId: "call-ps7",
465
+ toolName: "xg_plan_write",
466
+ details: makeSuccessPayload(plan),
467
+ });
468
+ assert.doesNotThrow(() => {
469
+ const result = handler(event, FAKE_CTX);
470
+ assert.equal(result, undefined);
471
+ });
472
+ });
473
+ it("🔴 跨调用序列:同一 plan 连续 3 次成功调用 → 发 3 条(全量幂等,不去重)", () => {
474
+ const deps = new RecordingDeps();
475
+ const handler = createPlanToolResultMiddleware(deps);
476
+ const plan = makePlan({ planId: "plan-stat-no-dedup", tasks: [{ title: "t1", status: "pending" }] });
477
+ const event = makeEvent({
478
+ toolCallId: "call-ps8",
479
+ toolName: "xg_plan_write",
480
+ details: makeSuccessPayload(plan),
481
+ });
482
+ handler(event, FAKE_CTX);
483
+ handler(event, FAKE_CTX);
484
+ handler(event, FAKE_CTX);
485
+ assert.equal(deps.planStatCalls.length, 3, "不去重:同一 plan 连续 3 次成功调用应各发一条");
486
+ });
487
+ });
488
+ //# sourceMappingURL=plan-tool-middleware.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-tool-middleware.test.js","sourceRoot":"","sources":["../../src/plan-tool-middleware.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Plan } from "@xgjktech/xg-openclaw-shared";
2
+ export interface ParsedPlanToolResult {
3
+ planId: string;
4
+ plan: Plan;
5
+ /** plan_execute 的返回带 event 字段,plan_write 没有——用于日志区分,不参与正确性判定 */
6
+ hasEventField: boolean;
7
+ }
8
+ /**
9
+ * 从已解析的值(如 JSON.parse 结果、middleware 的 `event.result.details`)中
10
+ * 结构校验并提取计划工具的成功返回。不是计划工具返回、ok:false 一律返回 undefined。
11
+ * 供 `parsePlanToolResult`(字符串输入)与 middleware(对象输入)共用同一份判定,
12
+ * 避免两份校验漂移。
13
+ */
14
+ export declare function parsePlanToolResultFromValue(value: unknown): ParsedPlanToolResult | undefined;
15
+ /**
16
+ * 从工具返回 JSON 文本中解析计划工具的成功返回。
17
+ * 不是计划工具返回、解析失败、ok:false 一律返回 undefined(绝不抛异常)。
18
+ */
19
+ export declare function parsePlanToolResult(rawBody: string): ParsedPlanToolResult | undefined;
20
+ //# sourceMappingURL=plan-tool-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-tool-result.d.ts","sourceRoot":"","sources":["../../src/plan-tool-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,8BAA8B,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,gEAAgE;IAChE,aAAa,EAAE,OAAO,CAAC;CAC1B;AA4CD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAmB7F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CASrF"}
@@ -0,0 +1,78 @@
1
+ const TASK_STATUSES = [
2
+ "pending",
3
+ "in_progress",
4
+ "completed",
5
+ "blocked",
6
+ ];
7
+ function isTaskStatus(value) {
8
+ return typeof value === "string" && TASK_STATUSES.includes(value);
9
+ }
10
+ function isPlainObject(value) {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+ function isValidPlan(value) {
14
+ if (!isPlainObject(value)) {
15
+ return false;
16
+ }
17
+ if (typeof value.planId !== "string" || value.planId === "") {
18
+ return false;
19
+ }
20
+ if (typeof value.goal !== "string") {
21
+ return false;
22
+ }
23
+ if (!Array.isArray(value.tasks)) {
24
+ return false;
25
+ }
26
+ for (const task of value.tasks) {
27
+ if (!isPlainObject(task)) {
28
+ return false;
29
+ }
30
+ if (typeof task.title !== "string") {
31
+ return false;
32
+ }
33
+ if (!isTaskStatus(task.status)) {
34
+ return false;
35
+ }
36
+ }
37
+ return true;
38
+ }
39
+ /**
40
+ * 从已解析的值(如 JSON.parse 结果、middleware 的 `event.result.details`)中
41
+ * 结构校验并提取计划工具的成功返回。不是计划工具返回、ok:false 一律返回 undefined。
42
+ * 供 `parsePlanToolResult`(字符串输入)与 middleware(对象输入)共用同一份判定,
43
+ * 避免两份校验漂移。
44
+ */
45
+ export function parsePlanToolResultFromValue(value) {
46
+ if (!isPlainObject(value)) {
47
+ return undefined;
48
+ }
49
+ if (value.ok !== true) {
50
+ return undefined;
51
+ }
52
+ if (typeof value.planId !== "string" || value.planId === "") {
53
+ return undefined;
54
+ }
55
+ if (!isValidPlan(value.plan)) {
56
+ return undefined;
57
+ }
58
+ return {
59
+ planId: value.planId,
60
+ plan: value.plan,
61
+ hasEventField: "event" in value,
62
+ };
63
+ }
64
+ /**
65
+ * 从工具返回 JSON 文本中解析计划工具的成功返回。
66
+ * 不是计划工具返回、解析失败、ok:false 一律返回 undefined(绝不抛异常)。
67
+ */
68
+ export function parsePlanToolResult(rawBody) {
69
+ let parsed;
70
+ try {
71
+ parsed = JSON.parse(rawBody);
72
+ }
73
+ catch {
74
+ return undefined;
75
+ }
76
+ return parsePlanToolResultFromValue(parsed);
77
+ }
78
+ //# sourceMappingURL=plan-tool-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-tool-result.js","sourceRoot":"","sources":["../../src/plan-tool-result.ts"],"names":[],"mappings":"AASA,MAAM,aAAa,GAA0B;IACzC,SAAS;IACT,aAAa;IACb,WAAW;IACX,SAAS;CACZ,CAAC;AAEF,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACvD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO;QACH,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,aAAa,EAAE,OAAO,IAAI,KAAK;KAClC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAC/C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO,4BAA4B,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-tool-result.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-tool-result.test.d.ts","sourceRoot":"","sources":["../../src/plan-tool-result.test.ts"],"names":[],"mappings":""}