@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,36 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import type { Plan } from "@xgjktech/xg-openclaw-shared";
3
+ export interface PlanEventSubscriptionDeps {
4
+ /** 按 planId 反查权威 plan(注入 getPlanById) */
5
+ getPlanById: (planId: string) => Plan | undefined;
6
+ /** 发送 PLAN_STAT 增量事件(与 middleware 共用同一实现) */
7
+ sendPlanStat: (params: {
8
+ plan: Plan;
9
+ source: "tool" | "snapshot";
10
+ }) => void;
11
+ }
12
+ type SubscriptionHandle = Parameters<OpenClawPluginApi["agent"]["events"]["registerAgentEventSubscription"]>[0]["handle"];
13
+ /**
14
+ * 构造事件订阅的 `handle` 回调,可独立单测(不依赖真实 api/网络)。
15
+ *
16
+ * 降级纪律同 middleware:handle 内全身 try/catch,绝不外抛(与 middleware 同进程)。
17
+ *
18
+ * 保留理由(D6 二选一,已裁定保留 + 瘦身):① 它是唯一非 middleware 的触发面,
19
+ * middleware 注册受 trust 门控被拒时(docs/plan-integration-notes.md §4.1 的已知部署故障)
20
+ * 它不受影响,仍是一条独立兜底;② 瘦身后主体只剩"守卫 → 反查 → sendPlanStat"三行,
21
+ * 维护成本接近零;③ 删掉等于丢弃第一轮已投入的契约面,而 runId 限制解除是可预期的上游演进。
22
+ *
23
+ * ⚠️ 当前 OpenClaw 版本下 xg-harness-tools 恒因缺少 runId 而不发送此事件,
24
+ * 此 handle 不会被触发,保留以便未来该限制解除后零改动生效。
25
+ * 不得将其作为任何正确性判断依据——权威状态来自 SQLite 只读反查。
26
+ */
27
+ export declare function createPlanEventHandler(deps: PlanEventSubscriptionDeps): SubscriptionHandle;
28
+ /**
29
+ * 注册计划事件订阅(前瞻性预留)。
30
+ *
31
+ * ⚠️ 当前 OpenClaw 版本下 xg-harness-tools 恒因缺少 runId 而不发送此事件,
32
+ * 此订阅不会被触发,保留以便未来该限制解除后零改动生效。
33
+ */
34
+ export declare function registerPlanEventSubscription(api: OpenClawPluginApi, deps: PlanEventSubscriptionDeps): void;
35
+ export {};
36
+ //# sourceMappingURL=plan-event-subscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-event-subscription.d.ts","sourceRoot":"","sources":["../../src/plan-event-subscription.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AASzD,MAAM,WAAW,yBAAyB;IACtC,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;IAClD,6CAA6C;IAC7C,YAAY,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;CAC/E;AAED,KAAK,kBAAkB,GAAG,UAAU,CAChC,iBAAiB,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,gCAAgC,CAAC,CACzE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEf;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,yBAAyB,GAAG,kBAAkB,CAmB1F;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,yBAAyB,GAAG,IAAI,CAY3G"}
@@ -0,0 +1,57 @@
1
+ import { isPlanEventPayload, planEventStream } from "@xgjktech/xg-openclaw-shared";
2
+ /**
3
+ * xg-harness-tools 的 plugin id:streams 过滤需要与其 openclaw.plugin.json 的 id 一致。
4
+ */
5
+ const HARNESS_PLUGIN_ID = "xg-harness-tools";
6
+ const LOG_PREFIX = "[xg_cwork_im] [plan-event-subscription]";
7
+ /**
8
+ * 构造事件订阅的 `handle` 回调,可独立单测(不依赖真实 api/网络)。
9
+ *
10
+ * 降级纪律同 middleware:handle 内全身 try/catch,绝不外抛(与 middleware 同进程)。
11
+ *
12
+ * 保留理由(D6 二选一,已裁定保留 + 瘦身):① 它是唯一非 middleware 的触发面,
13
+ * middleware 注册受 trust 门控被拒时(docs/plan-integration-notes.md §4.1 的已知部署故障)
14
+ * 它不受影响,仍是一条独立兜底;② 瘦身后主体只剩"守卫 → 反查 → sendPlanStat"三行,
15
+ * 维护成本接近零;③ 删掉等于丢弃第一轮已投入的契约面,而 runId 限制解除是可预期的上游演进。
16
+ *
17
+ * ⚠️ 当前 OpenClaw 版本下 xg-harness-tools 恒因缺少 runId 而不发送此事件,
18
+ * 此 handle 不会被触发,保留以便未来该限制解除后零改动生效。
19
+ * 不得将其作为任何正确性判断依据——权威状态来自 SQLite 只读反查。
20
+ */
21
+ export function createPlanEventHandler(deps) {
22
+ return (event, _ctx) => {
23
+ try {
24
+ if (!isPlanEventPayload(event.data)) {
25
+ return;
26
+ }
27
+ const payload = event.data;
28
+ const plan = deps.getPlanById(payload.planId);
29
+ if (!plan) {
30
+ console.warn(`${LOG_PREFIX} 反查不到 plan,跳过 planId=${payload.planId}`);
31
+ return;
32
+ }
33
+ deps.sendPlanStat({ plan, source: "tool" });
34
+ }
35
+ catch (err) {
36
+ console.warn(`${LOG_PREFIX} handle 内部异常,已吞: ${String(err)}`);
37
+ }
38
+ };
39
+ }
40
+ /**
41
+ * 注册计划事件订阅(前瞻性预留)。
42
+ *
43
+ * ⚠️ 当前 OpenClaw 版本下 xg-harness-tools 恒因缺少 runId 而不发送此事件,
44
+ * 此订阅不会被触发,保留以便未来该限制解除后零改动生效。
45
+ */
46
+ export function registerPlanEventSubscription(api, deps) {
47
+ const handle = createPlanEventHandler(deps);
48
+ api.agent.events.registerAgentEventSubscription({
49
+ id: "xg-cwork-im-plan-progress",
50
+ description: "订阅 xg-harness-tools 计划进度事件,反查权威 plan 后发送 PLAN_STAT。前瞻性预留:" +
51
+ "当前 OpenClaw 版本下 xg-harness-tools 恒因缺少 runId 而不发送此事件," +
52
+ "此订阅暂不会被触发,保留以便未来该限制解除后零改动生效。",
53
+ streams: [planEventStream(HARNESS_PLUGIN_ID)],
54
+ handle,
55
+ });
56
+ }
57
+ //# sourceMappingURL=plan-event-subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-event-subscription.js","sourceRoot":"","sources":["../../src/plan-event-subscription.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGnF;;GAEG;AACH,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAE7C,MAAM,UAAU,GAAG,yCAAyC,CAAC;AAa7D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAA+B;IAClE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACnB,IAAI,CAAC;YACD,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,OAAO;YACX,CAAC;YACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC;YAE3B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACR,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,wBAAwB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBACpE,OAAO;YACX,CAAC;YAED,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,oBAAoB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjE,CAAC;IACL,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAsB,EAAE,IAA+B;IACjG,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAE5C,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,8BAA8B,CAAC;QAC5C,EAAE,EAAE,2BAA2B;QAC/B,WAAW,EACP,2DAA2D;YAC3D,sDAAsD;YACtD,8BAA8B;QAClC,OAAO,EAAE,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM;KACT,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-event-subscription.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-event-subscription.test.d.ts","sourceRoot":"","sources":["../../src/plan-event-subscription.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
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 makePlan(overrides = {}) {
10
+ return {
11
+ planId: "plan-1",
12
+ goal: "迁移配置到新版本",
13
+ createdAt: "2026-07-27T00:00:00.000Z",
14
+ updatedAt: "2026-07-27T00:00:00.000Z",
15
+ tasks: [],
16
+ ...overrides,
17
+ };
18
+ }
19
+ function makeBlockedPayload(overrides = {}) {
20
+ return {
21
+ kind: "plan_update",
22
+ planId: "plan-1",
23
+ goal: "迁移配置到新版本",
24
+ action: "advance",
25
+ taskIndex: 0,
26
+ taskTitle: "备份旧配置",
27
+ taskStatus: "blocked",
28
+ blockedNote: "缺少权限",
29
+ summary: { total: 3, completed: 1, blocked: 1, inProgress: 0 },
30
+ runId: "run-1",
31
+ ...overrides,
32
+ };
33
+ }
34
+ class RecordingDeps {
35
+ planById = new Map();
36
+ planStatCalls = [];
37
+ getPlanById = (planId) => this.planById.get(planId);
38
+ sendPlanStat = (params) => {
39
+ this.planStatCalls.push(params);
40
+ };
41
+ }
42
+ describe("createPlanEventHandler: isPlanEventPayload 守卫", () => {
43
+ it("rejects malformed data without pushing or throwing", async () => {
44
+ const deps = new RecordingDeps();
45
+ const handle = createPlanEventHandler(deps);
46
+ const event = {
47
+ runId: "run-1",
48
+ seq: 1,
49
+ stream: "xg-harness-tools.plan",
50
+ ts: Date.now(),
51
+ data: { kind: "not_plan_update" },
52
+ };
53
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
54
+ assert.equal(deps.planStatCalls.length, 0);
55
+ });
56
+ it("rejects when data is not an object at all", async () => {
57
+ const deps = new RecordingDeps();
58
+ const handle = createPlanEventHandler(deps);
59
+ const event = {
60
+ runId: "run-1",
61
+ seq: 1,
62
+ stream: "xg-harness-tools.plan",
63
+ ts: Date.now(),
64
+ data: null,
65
+ };
66
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
67
+ assert.equal(deps.planStatCalls.length, 0);
68
+ });
69
+ it("rejects a payload that violates kind only — everything else is valid (pins the guard)", async () => {
70
+ const deps = new RecordingDeps();
71
+ const handle = createPlanEventHandler(deps);
72
+ const event = {
73
+ runId: "run-1",
74
+ seq: 1,
75
+ stream: "xg-harness-tools.plan",
76
+ ts: Date.now(),
77
+ data: makeBlockedPayload({ kind: "some_other_plugin_event" }),
78
+ };
79
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
80
+ assert.equal(deps.planStatCalls.length, 0);
81
+ });
82
+ it("rejects a payload with a malformed summary — everything else is valid", async () => {
83
+ const deps = new RecordingDeps();
84
+ const handle = createPlanEventHandler(deps);
85
+ const event = {
86
+ runId: "run-1",
87
+ seq: 1,
88
+ stream: "xg-harness-tools.plan",
89
+ ts: Date.now(),
90
+ data: makeBlockedPayload({ summary: {} }),
91
+ };
92
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
93
+ assert.equal(deps.planStatCalls.length, 0);
94
+ });
95
+ });
96
+ describe("createPlanEventHandler: 反查到 plan → 发 PLAN_STAT", () => {
97
+ it("反查到全量 plan → 调用 sendPlanStat,source === \"tool\"", async () => {
98
+ const deps = new RecordingDeps();
99
+ const plan = makePlan({
100
+ tasks: [{ title: "备份旧配置", status: "blocked", note: "缺少权限" }],
101
+ });
102
+ deps.planById.set("plan-1", plan);
103
+ const handle = createPlanEventHandler(deps);
104
+ const event = {
105
+ runId: "run-1",
106
+ seq: 1,
107
+ stream: "xg-harness-tools.plan",
108
+ ts: Date.now(),
109
+ data: makeBlockedPayload(),
110
+ };
111
+ await handle(event, FAKE_CTX);
112
+ assert.equal(deps.planStatCalls.length, 1);
113
+ assert.equal(deps.planStatCalls[0].source, "tool");
114
+ assert.equal(deps.planStatCalls[0].plan.planId, "plan-1");
115
+ });
116
+ });
117
+ describe("createPlanEventHandler: 反查不到 → 不发不抛", () => {
118
+ it("getPlanById 返回 undefined → 不调用 sendPlanStat,不抛", async () => {
119
+ const deps = new RecordingDeps();
120
+ const handle = createPlanEventHandler(deps);
121
+ const event = {
122
+ runId: "run-1",
123
+ seq: 1,
124
+ stream: "xg-harness-tools.plan",
125
+ ts: Date.now(),
126
+ data: makeBlockedPayload({ planId: "plan-does-not-exist" }),
127
+ };
128
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
129
+ assert.equal(deps.planStatCalls.length, 0);
130
+ });
131
+ });
132
+ describe("createPlanEventHandler: handle 内部出错不外抛", () => {
133
+ it("resolves normally even when getPlanById throws", async () => {
134
+ const deps = new RecordingDeps();
135
+ deps.getPlanById = () => {
136
+ throw new Error("boom");
137
+ };
138
+ const handle = createPlanEventHandler(deps);
139
+ const event = {
140
+ runId: "run-1",
141
+ seq: 1,
142
+ stream: "xg-harness-tools.plan",
143
+ ts: Date.now(),
144
+ data: makeBlockedPayload(),
145
+ };
146
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
147
+ assert.equal(deps.planStatCalls.length, 0);
148
+ });
149
+ it("resolves normally even when sendPlanStat throws", async () => {
150
+ const deps = new RecordingDeps();
151
+ const plan = makePlan({ tasks: [{ title: "t1", status: "blocked", note: "n" }] });
152
+ deps.planById.set("plan-1", plan);
153
+ deps.sendPlanStat = () => {
154
+ throw new Error("boom");
155
+ };
156
+ const handle = createPlanEventHandler(deps);
157
+ const event = {
158
+ runId: "run-1",
159
+ seq: 1,
160
+ stream: "xg-harness-tools.plan",
161
+ ts: Date.now(),
162
+ data: makeBlockedPayload(),
163
+ };
164
+ await assert.doesNotReject(() => Promise.resolve(handle(event, FAKE_CTX)));
165
+ });
166
+ });
167
+ //# 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,28 @@
1
+ import type { Plan } from "@xgjktech/xg-openclaw-shared";
2
+ import type { ImStreamClient } from "./connection.js";
3
+ /**
4
+ * 组装发往前端的 plan:剥离 origin(内部路由信息,含 sessionKey,前端不需要也不该看到)。
5
+ * 返回浅拷贝,不 mutate 入参(middleware 拿到的 plan 引用可能别处还要用)。
6
+ */
7
+ export declare function toWirePlan(plan: Plan): Plan;
8
+ /**
9
+ * 发送一条 PLAN_STAT。绝不抛、绝不 await 调用方(内部自己 catch)。
10
+ */
11
+ export declare function sendPlanStat(params: {
12
+ plan: Plan;
13
+ source: "tool" | "snapshot";
14
+ }): void;
15
+ /**
16
+ * 登记 WS client(供后续 PLAN_STAT 增量路由),登记完立刻 fire-and-forget 触发一次快照:
17
+ * 反查该群未完成的计划,逐个发 PLAN_STAT(source: "snapshot")。
18
+ *
19
+ * dispatch 是热路径:整个快照过程包 try/catch、绝不 await、绝不抛——快照失败不能连累
20
+ * WS 绑定本身(登记必须先于快照执行、且不受快照结果影响)。
21
+ *
22
+ * `deps.listPlansByOrigin` 默认注入 plan-store-access 的实现;测试可传入假实现
23
+ * 模拟反查异常(红线防御性场景——即便被注入的反查实现意外抛出,本函数也绝不外抛)。
24
+ */
25
+ export declare function registerPlanWsClientAndSnapshot(groupId: string, client: ImStreamClient, replyToMsgId: string, deps?: {
26
+ listPlansByOrigin: (channel: string, to: string) => Plan[];
27
+ }): void;
28
+ //# sourceMappingURL=plan-stat-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-stat-event.d.ts","sourceRoot":"","sources":["../../src/plan-stat-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAMtD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAG3C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,GAAG,IAAI,CA4BtF;AAOD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE;IAAE,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,EAAE,CAAA;CAA0B,GAC7F,IAAI,CAcN"}
@@ -0,0 +1,68 @@
1
+ import { getPlanWsClient, setPlanWsClient } from "./plan-ws-registry.js";
2
+ import { listPlansByOrigin } from "./plan-store-access.js";
3
+ const LOG_PREFIX = "[xg_cwork_im] [plan-stat-event]";
4
+ /**
5
+ * 组装发往前端的 plan:剥离 origin(内部路由信息,含 sessionKey,前端不需要也不该看到)。
6
+ * 返回浅拷贝,不 mutate 入参(middleware 拿到的 plan 引用可能别处还要用)。
7
+ */
8
+ export function toWirePlan(plan) {
9
+ const { origin: _origin, ...wirePlan } = plan;
10
+ return wirePlan;
11
+ }
12
+ /**
13
+ * 发送一条 PLAN_STAT。绝不抛、绝不 await 调用方(内部自己 catch)。
14
+ */
15
+ export function sendPlanStat(params) {
16
+ const { plan, source } = params;
17
+ const channel = plan.origin?.channel;
18
+ const to = plan.origin?.to;
19
+ if (channel !== "xg_cwork_im" || !to) {
20
+ console.warn(`${LOG_PREFIX} plan.origin 缺失或非本通道,跳过 PLAN_STAT planId=${plan.planId} channel=${channel ?? "(none)"}`);
21
+ return;
22
+ }
23
+ const target = getPlanWsClient(to);
24
+ if (!target) {
25
+ console.warn(`${LOG_PREFIX} 未登记 WS client,跳过 PLAN_STAT planId=${plan.planId} groupId=${to}`);
26
+ return;
27
+ }
28
+ void target.client
29
+ .sendEvent({
30
+ groupId: to,
31
+ replyToMsgId: target.replyToMsgId,
32
+ event: "PLAN_STAT",
33
+ data: { source, plan: toWirePlan(plan) },
34
+ })
35
+ .catch((err) => {
36
+ console.warn(`${LOG_PREFIX} 发送失败 planId=${plan.planId} groupId=${to}: ${String(err)}`);
37
+ });
38
+ }
39
+ /** 「未完成」判定:plan 中存在 status !== "completed" 的 task。 */
40
+ function isUnfinished(plan) {
41
+ return plan.tasks.some((task) => task.status !== "completed");
42
+ }
43
+ /**
44
+ * 登记 WS client(供后续 PLAN_STAT 增量路由),登记完立刻 fire-and-forget 触发一次快照:
45
+ * 反查该群未完成的计划,逐个发 PLAN_STAT(source: "snapshot")。
46
+ *
47
+ * dispatch 是热路径:整个快照过程包 try/catch、绝不 await、绝不抛——快照失败不能连累
48
+ * WS 绑定本身(登记必须先于快照执行、且不受快照结果影响)。
49
+ *
50
+ * `deps.listPlansByOrigin` 默认注入 plan-store-access 的实现;测试可传入假实现
51
+ * 模拟反查异常(红线防御性场景——即便被注入的反查实现意外抛出,本函数也绝不外抛)。
52
+ */
53
+ export function registerPlanWsClientAndSnapshot(groupId, client, replyToMsgId, deps = { listPlansByOrigin }) {
54
+ setPlanWsClient(groupId, client, replyToMsgId);
55
+ try {
56
+ const plans = deps.listPlansByOrigin("xg_cwork_im", groupId);
57
+ for (const plan of plans) {
58
+ if (!isUnfinished(plan)) {
59
+ continue;
60
+ }
61
+ sendPlanStat({ plan, source: "snapshot" });
62
+ }
63
+ }
64
+ catch (err) {
65
+ console.warn(`${LOG_PREFIX} 会话快照失败,已吞 groupId=${groupId}: ${String(err)}`);
66
+ }
67
+ }
68
+ //# sourceMappingURL=plan-stat-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-stat-event.js","sourceRoot":"","sources":["../../src/plan-stat-event.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,UAAU,GAAG,iCAAiC,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAU;IACjC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC9C,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmD;IAC5E,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAEhC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;IACrC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IAC3B,IAAI,OAAO,KAAK,aAAa,IAAI,CAAC,EAAE,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CACR,GAAG,UAAU,4CAA4C,IAAI,CAAC,MAAM,YAAY,OAAO,IAAI,QAAQ,EAAE,CACxG,CAAC;QACF,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,sCAAsC,IAAI,CAAC,MAAM,YAAY,EAAE,EAAE,CAAC,CAAC;QAC7F,OAAO;IACX,CAAC;IAED,KAAK,MAAM,CAAC,MAAM;SACb,SAAS,CAAC;QACP,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,KAAK,EAAE,WAAW;QAClB,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE;KAC3C,CAAC;SACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACpB,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,gBAAgB,IAAI,CAAC,MAAM,YAAY,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;AACX,CAAC;AAED,sDAAsD;AACtD,SAAS,YAAY,CAAC,IAAU;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,+BAA+B,CAC3C,OAAe,EACf,MAAsB,EACtB,YAAoB,EACpB,OAAuE,EAAE,iBAAiB,EAAE;IAE5F,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IAE/C,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC7D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,SAAS;YACb,CAAC;YACD,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,sBAAsB,OAAO,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-stat-event.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-stat-event.test.d.ts","sourceRoot":"","sources":["../../src/plan-stat-event.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it, beforeEach } from "node:test";
3
+ import { resetPlanWsRegistryForTest, setPlanWsClient } from "./plan-ws-registry.js";
4
+ import { registerPlanWsClientAndSnapshot, sendPlanStat, toWirePlan } from "./plan-stat-event.js";
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: [{ title: "t1", status: "pending" }],
12
+ ...overrides,
13
+ };
14
+ }
15
+ function makeRecordingClient() {
16
+ const calls = [];
17
+ const client = {
18
+ start: async () => { },
19
+ streamProgress: async () => { },
20
+ streamUsage: async () => { },
21
+ sendEvent: async (opts) => {
22
+ calls.push(opts);
23
+ },
24
+ end: async () => { },
25
+ };
26
+ return { client, calls };
27
+ }
28
+ beforeEach(() => {
29
+ resetPlanWsRegistryForTest();
30
+ });
31
+ describe("sendPlanStat: 正常路径", () => {
32
+ it("plan 带 origin + WS 已登记 → sendEvent 被调用一次,event/source/planId 正确", () => {
33
+ const { client, calls } = makeRecordingClient();
34
+ setPlanWsClient("g-1", client, "msg-1");
35
+ const plan = makePlan({ origin: { channel: "xg_cwork_im", to: "g-1" } });
36
+ sendPlanStat({ plan, source: "tool" });
37
+ assert.equal(calls.length, 1);
38
+ assert.equal(calls[0].event, "PLAN_STAT");
39
+ assert.equal(calls[0].groupId, "g-1");
40
+ assert.equal(calls[0].replyToMsgId, "msg-1");
41
+ assert.equal(calls[0].data.source, "tool");
42
+ assert.equal(calls[0].data.plan.planId, plan.planId);
43
+ });
44
+ });
45
+ describe("sendPlanStat: 🔴 payload 不含 origin(防泄漏)", () => {
46
+ it("data.plan.origin 应为 undefined", () => {
47
+ const { client, calls } = makeRecordingClient();
48
+ setPlanWsClient("g-1", client, "msg-1");
49
+ const plan = makePlan({
50
+ origin: { channel: "xg_cwork_im", to: "g-1", sessionKey: "sess-secret" },
51
+ });
52
+ sendPlanStat({ plan, source: "tool" });
53
+ assert.equal(calls.length, 1);
54
+ assert.equal(calls[0].data.plan.origin, undefined);
55
+ });
56
+ });
57
+ describe("sendPlanStat: 🔴 不 mutate 入参", () => {
58
+ it("调用后原 plan 对象仍然带着 origin", () => {
59
+ const { client } = makeRecordingClient();
60
+ setPlanWsClient("g-1", client, "msg-1");
61
+ const origin = { channel: "xg_cwork_im", to: "g-1" };
62
+ const plan = makePlan({ origin });
63
+ sendPlanStat({ plan, source: "tool" });
64
+ assert.deepEqual(plan.origin, origin);
65
+ });
66
+ it("toWirePlan 本身不 mutate 入参,返回值不含 origin", () => {
67
+ const origin = { channel: "xg_cwork_im", to: "g-1" };
68
+ const plan = makePlan({ origin });
69
+ const wire = toWirePlan(plan);
70
+ assert.deepEqual(plan.origin, origin, "入参 plan 不受影响");
71
+ assert.equal(wire.origin, undefined, "返回值不含 origin");
72
+ assert.equal(wire.planId, plan.planId);
73
+ });
74
+ });
75
+ describe("sendPlanStat: 降级路径", () => {
76
+ it("plan 无 origin(旧数据)→ 不发、不抛", () => {
77
+ const { client, calls } = makeRecordingClient();
78
+ setPlanWsClient("g-1", client, "msg-1");
79
+ const plan = makePlan();
80
+ assert.doesNotThrow(() => sendPlanStat({ plan, source: "tool" }));
81
+ assert.equal(calls.length, 0);
82
+ });
83
+ it("plan.origin.channel 不是 xg_cwork_im → 不发、不抛", () => {
84
+ const { client, calls } = makeRecordingClient();
85
+ setPlanWsClient("g-1", client, "msg-1");
86
+ const plan = makePlan({ origin: { channel: "some_other_channel", to: "g-1" } });
87
+ assert.doesNotThrow(() => sendPlanStat({ plan, source: "tool" }));
88
+ assert.equal(calls.length, 0);
89
+ });
90
+ it("WS 未登记该 groupId → 不发、不抛", () => {
91
+ const plan = makePlan({ origin: { channel: "xg_cwork_im", to: "g-never-registered" } });
92
+ assert.doesNotThrow(() => sendPlanStat({ plan, source: "tool" }));
93
+ });
94
+ });
95
+ describe("sendPlanStat: 🔴 fire-and-forget 红线", () => {
96
+ it("sendEvent 返回 rejected Promise → 不抛出到调用方,函数同步返回", () => {
97
+ const client = {
98
+ start: async () => { },
99
+ streamProgress: async () => { },
100
+ streamUsage: async () => { },
101
+ sendEvent: async () => {
102
+ throw new Error("network down");
103
+ },
104
+ end: async () => { },
105
+ };
106
+ setPlanWsClient("g-1", client, "msg-1");
107
+ const plan = makePlan({ origin: { channel: "xg_cwork_im", to: "g-1" } });
108
+ assert.doesNotThrow(() => sendPlanStat({ plan, source: "tool" }));
109
+ });
110
+ it("sendEvent 返回永不 resolve 的 Promise → 函数仍立即返回", () => {
111
+ const client = {
112
+ start: async () => { },
113
+ streamProgress: async () => { },
114
+ streamUsage: async () => { },
115
+ sendEvent: () => new Promise(() => { }),
116
+ end: async () => { },
117
+ };
118
+ setPlanWsClient("g-1", client, "msg-1");
119
+ const plan = makePlan({ origin: { channel: "xg_cwork_im", to: "g-1" } });
120
+ // 若 sendPlanStat 内部 await 了 sendEvent,这行会挂起整个测试进程(超时失败)。
121
+ const result = sendPlanStat({ plan, source: "tool" });
122
+ assert.equal(result, undefined);
123
+ });
124
+ });
125
+ describe("registerPlanWsClientAndSnapshot: 快照路径", () => {
126
+ it("🔴 登记时存在 2 个未完成计划 + 1 个全完成计划 → 恰好发 2 条 source === \"snapshot\"", () => {
127
+ const { client, calls } = makeRecordingClient();
128
+ const unfinished1 = makePlan({
129
+ planId: "plan-a",
130
+ origin: { channel: "xg_cwork_im", to: "g-1" },
131
+ tasks: [{ title: "t1", status: "in_progress" }],
132
+ });
133
+ const unfinished2 = makePlan({
134
+ planId: "plan-b",
135
+ origin: { channel: "xg_cwork_im", to: "g-1" },
136
+ tasks: [{ title: "t1", status: "blocked", note: "n" }],
137
+ });
138
+ const finished = makePlan({
139
+ planId: "plan-c",
140
+ origin: { channel: "xg_cwork_im", to: "g-1" },
141
+ tasks: [{ title: "t1", status: "completed" }],
142
+ });
143
+ registerPlanWsClientAndSnapshot("g-1", client, "msg-1", {
144
+ listPlansByOrigin: () => [unfinished1, unfinished2, finished],
145
+ });
146
+ assert.equal(calls.length, 2);
147
+ assert.ok(calls.every((c) => c.data.source === "snapshot"));
148
+ const planIds = calls.map((c) => c.data.plan.planId).sort();
149
+ assert.deepEqual(planIds, ["plan-a", "plan-b"]);
150
+ });
151
+ it("🔴 反查抛异常 → registerPlanWsClientAndSnapshot 不抛,且登记本身仍然成功", () => {
152
+ const { client, calls } = makeRecordingClient();
153
+ assert.doesNotThrow(() => {
154
+ registerPlanWsClientAndSnapshot("g-1", client, "msg-1", {
155
+ listPlansByOrigin: () => {
156
+ throw new Error("db locked");
157
+ },
158
+ });
159
+ });
160
+ assert.equal(calls.length, 0, "反查失败不应发出任何 PLAN_STAT");
161
+ // 登记仍然成功:紧接着用同一 client 发一条正常的 PLAN_STAT 应该能路由到
162
+ const plan = makePlan({ origin: { channel: "xg_cwork_im", to: "g-1" } });
163
+ sendPlanStat({ plan, source: "tool" });
164
+ assert.equal(calls.length, 1, "快照失败不能连累 WS 绑定,后续增量应仍能发出");
165
+ });
166
+ });
167
+ //# sourceMappingURL=plan-stat-event.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-stat-event.test.js","sourceRoot":"","sources":["../../src/plan-stat-event.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
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
+ /**
17
+ * 按来源会话(channel + to)反查全量 plan(WS 快照用)。
18
+ * shared 侧只读实现已内置"旧库缺 origin 列 → 返回 []"的探测降级;
19
+ * 这里叠加本文件既有的句柄级降级纪律:拿不到句柄 / 查询异常 → 记 warn、返回 []、绝不抛、
20
+ * 失败时清空句柄缓存(与 getPlanById 同款,供后续调用重试恢复)。
21
+ */
22
+ export declare function listPlansByOrigin(channel: string, to: string): Plan[];
23
+ //# 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;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,CAYrE"}