@xgjktech/xg_cwork_im 1.17.51 → 1.17.52

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 (44) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/active-cron-context-store.d.ts +20 -0
  4. package/dist/src/active-cron-context-store.d.ts.map +1 -0
  5. package/dist/src/active-cron-context-store.js +73 -0
  6. package/dist/src/active-cron-context-store.js.map +1 -0
  7. package/dist/src/cron-appkey-binding-store.d.ts +2 -1
  8. package/dist/src/cron-appkey-binding-store.d.ts.map +1 -1
  9. package/dist/src/cron-appkey-binding-store.js +66 -31
  10. package/dist/src/cron-appkey-binding-store.js.map +1 -1
  11. package/dist/src/cron-appkey-binding-store.test.js +159 -1
  12. package/dist/src/cron-appkey-binding-store.test.js.map +1 -1
  13. package/dist/src/deliver-text.test.js +22 -22
  14. package/dist/src/gateway-session-queue.d.ts +11 -2
  15. package/dist/src/gateway-session-queue.d.ts.map +1 -1
  16. package/dist/src/gateway-session-queue.js +9 -6
  17. package/dist/src/gateway-session-queue.js.map +1 -1
  18. package/dist/src/plan-store-access.test.js +9 -9
  19. package/dist/src/plugin-dispose.d.ts.map +1 -1
  20. package/dist/src/plugin-dispose.js +3 -1
  21. package/dist/src/plugin-dispose.js.map +1 -1
  22. package/dist/src/register-exec-env-hook.d.ts +6 -0
  23. package/dist/src/register-exec-env-hook.d.ts.map +1 -1
  24. package/dist/src/register-exec-env-hook.js +99 -32
  25. package/dist/src/register-exec-env-hook.js.map +1 -1
  26. package/dist/src/single-chat-no-reply-fallback.d.ts +14 -0
  27. package/dist/src/single-chat-no-reply-fallback.d.ts.map +1 -0
  28. package/dist/src/single-chat-no-reply-fallback.js +20 -0
  29. package/dist/src/single-chat-no-reply-fallback.js.map +1 -0
  30. package/dist/src/subagent-progress-hooks.d.ts +11 -0
  31. package/dist/src/subagent-progress-hooks.d.ts.map +1 -0
  32. package/dist/src/subagent-progress-hooks.js +41 -0
  33. package/dist/src/subagent-progress-hooks.js.map +1 -0
  34. package/dist/src/turn-deliver-buffer.test.js +25 -25
  35. package/openclaw.plugin.json +30 -30
  36. package/package.json +78 -78
  37. package/dist/src/plan-session-registry.d.ts +0 -24
  38. package/dist/src/plan-session-registry.d.ts.map +0 -1
  39. package/dist/src/plan-session-registry.js +0 -84
  40. package/dist/src/plan-session-registry.js.map +0 -1
  41. package/dist/src/plan-session-registry.test.d.ts +0 -2
  42. package/dist/src/plan-session-registry.test.d.ts.map +0 -1
  43. package/dist/src/plan-session-registry.test.js +0 -109
  44. package/dist/src/plan-session-registry.test.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-chat-no-reply-fallback.d.ts","sourceRoot":"","sources":["../../src/single-chat-no-reply-fallback.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,mCAAmC,CAAC,IAAI,EAAE;IACtD,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,OAAO,CAMV;AAED,0BAA0B;AAC1B,wBAAgB,kCAAkC,IAAI,MAAM,CAE3D"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 单聊轮次结束但未向 IM 发出正文时的兜底话术(如模型输出 NO_REPLY、deliver 未被调用)。
3
+ */
4
+ import { isImSingleChat } from "./inbound-chat-type.js";
5
+ export function shouldSendSingleChatNoReplyFallback(args) {
6
+ if (args.hasFirstReply)
7
+ return false;
8
+ if (args.dispatchError !== undefined || args.lastDeliverError !== undefined)
9
+ return false;
10
+ if (!isImSingleChat(args.params))
11
+ return false;
12
+ if (args.deliverCallCount > 0)
13
+ return false;
14
+ return true;
15
+ }
16
+ /** 单聊静默轮次兜底:简短告知并引导重试。 */
17
+ export function buildSingleChatNoReplyFallbackText() {
18
+ return "消息已收到,但这一轮没有生成回复。请换个说法或把需求说具体一些后再试。";
19
+ }
20
+ //# sourceMappingURL=single-chat-no-reply-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single-chat-no-reply-fallback.js","sourceRoot":"","sources":["../../src/single-chat-no-reply-fallback.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD,MAAM,UAAU,mCAAmC,CAAC,IAMnD;IACG,IAAI,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC1F,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,IAAI,IAAI,CAAC,gBAAgB,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,kCAAkC;IAC9C,OAAO,qCAAqC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
2
+ import type { ImStreamClient } from "./connection.js";
3
+ interface SubagentWsTarget {
4
+ streamClient: ImStreamClient;
5
+ groupId: string;
6
+ replyToMsgId: string;
7
+ }
8
+ export declare function registerSubagentProgressHooks(api: OpenClawPluginApi): void;
9
+ export declare function setSubagentWsTarget(childSessionKey: string, target: SubagentWsTarget): void;
10
+ export {};
11
+ //# sourceMappingURL=subagent-progress-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-progress-hooks.d.ts","sourceRoot":"","sources":["../../src/subagent-progress-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,UAAU,gBAAgB;IACtB,YAAY,EAAE,cAAc,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACxB;AAYD,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAqC1E;AAED,wBAAgB,mBAAmB,CAC/B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,gBAAgB,GACzB,IAAI,CAEN"}
@@ -0,0 +1,41 @@
1
+ const subagentWsTargets = new Map();
2
+ export function registerSubagentProgressHooks(api) {
3
+ // subagent_progress is not in the installed SDK's PluginHookName type union,
4
+ // but the runtime supports it. Cast to bypass the type check.
5
+ api.on("subagent_progress", async (event) => {
6
+ const childSessionKey = event.childSessionKey;
7
+ if (!childSessionKey)
8
+ return;
9
+ const target = subagentWsTargets.get(childSessionKey);
10
+ if (!target)
11
+ return;
12
+ let displayText;
13
+ if (event.phase === "started") {
14
+ displayText = "子任务已启动";
15
+ }
16
+ else if (event.phase === "ended") {
17
+ displayText = event.outcome === "ok" ? "子任务已完成" : `子任务异常: ${event.outcome ?? "unknown"}`;
18
+ }
19
+ else {
20
+ displayText = "子任务状态更新";
21
+ }
22
+ try {
23
+ await target.streamClient.streamProgress({
24
+ groupId: target.groupId,
25
+ replyToMsgId: target.replyToMsgId,
26
+ event: "RUN_EVENT",
27
+ displayText,
28
+ });
29
+ }
30
+ catch {
31
+ // WS best-effort: don't propagate errors from progress events
32
+ }
33
+ if (event.phase === "ended") {
34
+ subagentWsTargets.delete(childSessionKey);
35
+ }
36
+ });
37
+ }
38
+ export function setSubagentWsTarget(childSessionKey, target) {
39
+ subagentWsTargets.set(childSessionKey, target);
40
+ }
41
+ //# sourceMappingURL=subagent-progress-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-progress-hooks.js","sourceRoot":"","sources":["../../src/subagent-progress-hooks.ts"],"names":[],"mappings":"AAiBA,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA4B,CAAC;AAE9D,MAAM,UAAU,6BAA6B,CAAC,GAAsB;IAChE,6EAA6E;IAC7E,8DAA8D;IAC7D,GAAG,CAAC,EAA8F,CAC/F,mBAAmB,EACnB,KAAK,EAAE,KAA4B,EAAE,EAAE;QACnC,MAAM,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;QAC9C,IAAI,CAAC,eAAe;YAAE,OAAO;QAE7B,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACtD,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,IAAI,WAAmB,CAAC;QACxB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC5B,WAAW,GAAG,QAAQ,CAAC;QAC3B,CAAC;aAAM,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YACjC,WAAW,GAAG,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;QAC7F,CAAC;aAAM,CAAC;YACJ,WAAW,GAAG,SAAS,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC;YACD,MAAM,MAAM,CAAC,YAAY,CAAC,cAAc,CAAC;gBACrC,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,KAAK,EAAE,WAAW;gBAClB,WAAW;aACd,CAAC,CAAC;QACP,CAAC;QAAC,MAAM,CAAC;YACL,8DAA8D;QAClE,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC1B,iBAAiB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC;AAED,MAAM,UAAU,mBAAmB,CAC/B,eAAuB,EACvB,MAAwB;IAExB,iBAAiB,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AACnD,CAAC"}
@@ -1,36 +1,36 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { describe, it } from "node:test";
3
3
  import { isDeliverPayloadSendable, isDeliverTextRevision, snapshotSupersedesBufferText, TurnDeliverBuffer, } from "./turn-deliver-buffer.js";
4
- const HOUTONG_BODY_LOOSE = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
5
-
6
- 我已经重新生成了一版**纯 Markdown 可读版**:
7
-
8
- - 不用 SVG
9
- 新文件:
10
-
4
+ const HOUTONG_BODY_LOOSE = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
5
+
6
+ 我已经重新生成了一版**纯 Markdown 可读版**:
7
+
8
+ - 不用 SVG
9
+ 新文件:
10
+
11
11
  -----`;
12
- const HOUTONG_BODY_TIGHT = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
13
- 我已经重新生成了一版**纯 Markdown 可读版**:
14
- - 不用 SVG
12
+ const HOUTONG_BODY_TIGHT = `确实是这个问题:昨天那版虽然用了内嵌 SVG,但你现在的文档预览器没有把 SVG 正常渲染出来,所以流程看不到。
13
+ 我已经重新生成了一版**纯 Markdown 可读版**:
14
+ - 不用 SVG
15
15
  新文件:`;
16
- const WORLD_CUP_PARTIAL = `| 场次 | 时间 |
17
- | --- | --- |
18
- | 1 | 21:00 |
16
+ const WORLD_CUP_PARTIAL = `| 场次 | 时间 |
17
+ | --- | --- |
18
+ | 1 | 21:00 |
19
19
  | 2 |`;
20
- const WORLD_CUP_FULL = `| 场次 | 时间 |
21
- | --- | --- |
22
- | 1 | 21:00 |
23
- | 2 | 00:00 |
20
+ const WORLD_CUP_FULL = `| 场次 | 时间 |
21
+ | --- | --- |
22
+ | 1 | 21:00 |
23
+ | 2 | 00:00 |
24
24
  | 3 | 03:00 |`;
25
- const RT002_PART1 = `BEGIN_123
26
-
27
- ## 一、背景
28
-
25
+ const RT002_PART1 = `BEGIN_123
26
+
27
+ ## 一、背景
28
+
29
29
  随着人工智能技术的快速发展,企业级AI助手在提升工作效率中发挥着日益重要的作用。`;
30
- const RT002_PART2 = `- 工具调用的完整日志必须被记录,包括调用时间、调用者、工具名称。
31
-
32
- ## 六、审计
33
-
30
+ const RT002_PART2 = `- 工具调用的完整日志必须被记录,包括调用时间、调用者、工具名称。
31
+
32
+ ## 六、审计
33
+
34
34
  审计是AI助手治理的监督机制。`;
35
35
  function entry(textPart, hasMedia = false) {
36
36
  return {
@@ -1,31 +1,31 @@
1
- {
2
- "id": "xg_cwork_im",
3
- "channels": [
4
- "xg_cwork_im"
5
- ],
6
- "channelConfigs": {
7
- "xg_cwork_im": {
8
- "schema": {
9
- "type": "object",
10
- "additionalProperties": true,
11
- "properties": {}
12
- }
13
- }
14
- },
15
- "configSchema": {
16
- "type": "object",
17
- "additionalProperties": true,
18
- "properties": {}
19
- },
20
- "contracts": {
21
- "tools": [
22
- "xg_cwork_im_get_group_chat_history",
23
- "xg_cwork_im_send_group_message",
24
- "xg_cwork_im_send_file"
25
- ],
26
- "agentToolResultMiddleware": [
27
- "openclaw",
28
- "codex"
29
- ]
30
- }
1
+ {
2
+ "id": "xg_cwork_im",
3
+ "channels": [
4
+ "xg_cwork_im"
5
+ ],
6
+ "channelConfigs": {
7
+ "xg_cwork_im": {
8
+ "schema": {
9
+ "type": "object",
10
+ "additionalProperties": true,
11
+ "properties": {}
12
+ }
13
+ }
14
+ },
15
+ "configSchema": {
16
+ "type": "object",
17
+ "additionalProperties": true,
18
+ "properties": {}
19
+ },
20
+ "contracts": {
21
+ "tools": [
22
+ "xg_cwork_im_get_group_chat_history",
23
+ "xg_cwork_im_send_group_message",
24
+ "xg_cwork_im_send_file"
25
+ ],
26
+ "agentToolResultMiddleware": [
27
+ "openclaw",
28
+ "codex"
29
+ ]
30
+ }
31
31
  }
package/package.json CHANGED
@@ -1,78 +1,78 @@
1
- {
2
- "name": "@xgjktech/xg_cwork_im",
3
- "version": "1.17.51",
4
- "description": "XG CWork IM channel plugin for OpenClaw",
5
- "keywords": [
6
- "bot",
7
- "channel",
8
- "openclaw",
9
- "xg_cwork_im",
10
- "im"
11
- ],
12
- "license": "MIT",
13
- "type": "module",
14
- "main": "dist/index.js",
15
- "types": "dist/index.d.ts",
16
- "engines": {
17
- "node": ">=22.19.0"
18
- },
19
- "files": [
20
- ".npmrc",
21
- "dist/**/*",
22
- "openclaw.plugin.json"
23
- ],
24
- "scripts": {
25
- "build": "tsc -p tsconfig.json",
26
- "type-check": "tsc -p tsconfig.json --noEmit",
27
- "lint": "tsc -p tsconfig.json --noEmit",
28
- "test": "npm run build && node --test dist/src/account-reconciler.test.js dist/src/inbound-terminal-state.test.js dist/src/user-facing-errors.test.js dist/src/deliver-text.test.js dist/src/agent-context-types.test.js dist/src/build-project-prompt.test.js dist/src/nas-volumes.test.js dist/src/workspace-event.test.js dist/src/workspace-event-scheduler.test.js dist/src/connection-workspace-event.test.js dist/src/block-streaming-config.test.js dist/src/channel-disabled-account.test.js dist/src/per-message-fallback-notice.test.js dist/src/thinking-ws-progress.test.js dist/src/resource-file.test.js dist/src/turn-deliver-buffer.test.js dist/src/run-usage.test.js dist/src/ws-run-event-unmapped.test.js dist/src/item-event-guard.test.js dist/src/inbound-model.test.js dist/src/auto-model-router.test.js dist/src/channel-config.test.js dist/src/send-service.test.js dist/src/send-file-tool.test.js dist/src/plan-tool-result.test.js dist/src/plan-blocked-notice.test.js dist/src/plan-store-access.test.js dist/src/plan-tool-middleware.test.js dist/src/plan-event-subscription.test.js dist/src/plan-ws-registry.test.js dist/src/plan-stat-event.test.js dist/src/active-round-registry.test.js dist/src/interrupt-round.test.js dist/src/subagent-monitor.test.js dist/src/session-env-store.test.js dist/src/register-exec-env-hook.test.js dist/src/cron-appkey-binding-store.test.js dist/src/ws-inbound-schema.test.js",
29
- "install:prod": "npm install --omit=dev",
30
- "prepublishOnly": "npm run build"
31
- },
32
- "dependencies": {
33
- "@sinclair/typebox": "^0.32.0",
34
- "@xgjktech/xg-openclaw-shared": "^0.2.2",
35
- "adm-zip": "^0.6.0",
36
- "axios": "^1.6.0",
37
- "tar": "^7.5.22",
38
- "ws": "^8.17.0",
39
- "zod": "^3.22.0"
40
- },
41
- "devDependencies": {
42
- "@types/node": "^22.19.0",
43
- "@types/ws": "^8.5.10",
44
- "openclaw": "^2026.6.10",
45
- "typescript": "^5.3.0"
46
- },
47
- "peerDependencies": {
48
- "openclaw": ">=2026.6.10"
49
- },
50
- "peerDependenciesMeta": {
51
- "openclaw": {
52
- "optional": true
53
- }
54
- },
55
- "openclaw": {
56
- "extensions": [
57
- "./dist/index.js"
58
- ],
59
- "channels": [
60
- "xg_cwork_im"
61
- ],
62
- "installDependencies": false,
63
- "channel": {
64
- "id": "xg_cwork_im",
65
- "label": "XG CWork IM",
66
- "selectionLabel": "XG CWork IM (工作说说)",
67
- "blurb": "工作说说 IM 机器人 Channel 插件,通过 WebSocket 长连接接收消息。",
68
- "aliases": [
69
- "xg_cwork_im",
70
- "im"
71
- ]
72
- },
73
- "install": {
74
- "localPath": ".",
75
- "defaultChoice": "local"
76
- }
77
- }
78
- }
1
+ {
2
+ "name": "@xgjktech/xg_cwork_im",
3
+ "version": "1.17.52",
4
+ "description": "XG CWork IM channel plugin for OpenClaw",
5
+ "keywords": [
6
+ "bot",
7
+ "channel",
8
+ "openclaw",
9
+ "xg_cwork_im",
10
+ "im"
11
+ ],
12
+ "license": "MIT",
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "engines": {
17
+ "node": ">=22.19.0"
18
+ },
19
+ "files": [
20
+ ".npmrc",
21
+ "dist/**/*",
22
+ "openclaw.plugin.json"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "type-check": "tsc -p tsconfig.json --noEmit",
27
+ "lint": "tsc -p tsconfig.json --noEmit",
28
+ "test": "npm run build && node --test dist/src/account-reconciler.test.js dist/src/inbound-terminal-state.test.js dist/src/user-facing-errors.test.js dist/src/deliver-text.test.js dist/src/agent-context-types.test.js dist/src/build-project-prompt.test.js dist/src/nas-volumes.test.js dist/src/workspace-event.test.js dist/src/workspace-event-scheduler.test.js dist/src/connection-workspace-event.test.js dist/src/block-streaming-config.test.js dist/src/channel-disabled-account.test.js dist/src/per-message-fallback-notice.test.js dist/src/thinking-ws-progress.test.js dist/src/resource-file.test.js dist/src/turn-deliver-buffer.test.js dist/src/run-usage.test.js dist/src/ws-run-event-unmapped.test.js dist/src/item-event-guard.test.js dist/src/inbound-model.test.js dist/src/auto-model-router.test.js dist/src/channel-config.test.js dist/src/send-service.test.js dist/src/send-file-tool.test.js dist/src/plan-tool-result.test.js dist/src/plan-blocked-notice.test.js dist/src/plan-store-access.test.js dist/src/plan-tool-middleware.test.js dist/src/plan-event-subscription.test.js dist/src/plan-ws-registry.test.js dist/src/plan-stat-event.test.js dist/src/active-round-registry.test.js dist/src/interrupt-round.test.js dist/src/subagent-monitor.test.js dist/src/session-env-store.test.js dist/src/register-exec-env-hook.test.js dist/src/cron-appkey-binding-store.test.js dist/src/ws-inbound-schema.test.js",
29
+ "install:prod": "npm install --omit=dev",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "dependencies": {
33
+ "@sinclair/typebox": "^0.32.0",
34
+ "@xgjktech/xg-openclaw-shared": "^0.2.2",
35
+ "adm-zip": "^0.6.0",
36
+ "axios": "^1.6.0",
37
+ "tar": "^7.5.22",
38
+ "ws": "^8.17.0",
39
+ "zod": "^3.22.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.19.0",
43
+ "@types/ws": "^8.5.10",
44
+ "openclaw": "^2026.6.10",
45
+ "typescript": "^5.3.0"
46
+ },
47
+ "peerDependencies": {
48
+ "openclaw": ">=2026.6.10"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "openclaw": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "openclaw": {
56
+ "extensions": [
57
+ "./dist/index.js"
58
+ ],
59
+ "channels": [
60
+ "xg_cwork_im"
61
+ ],
62
+ "installDependencies": false,
63
+ "channel": {
64
+ "id": "xg_cwork_im",
65
+ "label": "XG CWork IM",
66
+ "selectionLabel": "XG CWork IM (工作说说)",
67
+ "blurb": "工作说说 IM 机器人 Channel 插件,通过 WebSocket 长连接接收消息。",
68
+ "aliases": [
69
+ "xg_cwork_im",
70
+ "im"
71
+ ]
72
+ },
73
+ "install": {
74
+ "localPath": ".",
75
+ "defaultChoice": "local"
76
+ }
77
+ }
78
+ }
@@ -1,24 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,84 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"plan-session-registry.js","sourceRoot":"","sources":["../../src/plan-session-registry.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plan-session-registry.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plan-session-registry.test.d.ts","sourceRoot":"","sources":["../../src/plan-session-registry.test.ts"],"names":[],"mappings":""}
@@ -1,109 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"plan-session-registry.test.js","sourceRoot":"","sources":["../../src/plan-session-registry.test.ts"],"names":[],"mappings":"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"}