@kafca/agentdock 0.1.56 → 0.1.57

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 (180) hide show
  1. package/README.md +7 -0
  2. package/dist/renderer/assets/{Badge-DjcoXx2J.js → Badge-CDTbmw1h.js} +1 -1
  3. package/dist/renderer/assets/Card-DayUo35w.js +1 -0
  4. package/dist/renderer/assets/Config-ByGMQuzR.js +21 -0
  5. package/dist/renderer/assets/CronList-XqHdVlgu.js +1 -0
  6. package/dist/renderer/assets/Dashboard-CZj-oANw.js +41 -0
  7. package/dist/renderer/assets/{EmptyState-DIZLiccW.js → EmptyState-EFMkOjZO.js} +1 -1
  8. package/dist/renderer/assets/HighlightedMarkdown-DyvF3DHK.js +12 -0
  9. package/dist/renderer/assets/Input-DxoWVc9d.js +1 -0
  10. package/dist/renderer/assets/{KnowledgeDetail-CJ9IYOsa.js → KnowledgeDetail-CbUb2tG7.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-BLGPwnBO.js → KnowledgeHome-BWV1gz4f.js} +3 -3
  12. package/dist/renderer/assets/Logs-DqnanQTc.js +6 -0
  13. package/dist/renderer/assets/{Modal-CQiUpfl4.js → Modal-yY7TzR0x.js} +3 -3
  14. package/dist/renderer/assets/MonitorList-CIjGQkFs.js +1 -0
  15. package/dist/renderer/assets/Page-vwHNUdoj.js +1 -0
  16. package/dist/renderer/assets/{Select-D6z65IT3.js → Select-CmbK36pN.js} +2 -2
  17. package/dist/renderer/assets/ThreadChat-4OceMgM4.js +86 -0
  18. package/dist/renderer/assets/Workspace-DplPJOjJ.js +19 -0
  19. package/dist/renderer/assets/{arrow-left-CV5cL3f4.js → arrow-left-C8HfBt2K.js} +1 -1
  20. package/dist/renderer/assets/{book-open-DThvB7pj.js → book-open-BCdZWncQ.js} +1 -1
  21. package/dist/renderer/assets/channels-hgO3cAIx.js +6 -0
  22. package/dist/renderer/assets/chevron-down-BPk77tqY.js +11 -0
  23. package/dist/renderer/assets/index-BIKL3fTP.css +11 -0
  24. package/dist/renderer/assets/index-BlA4xPdd.js +41 -0
  25. package/dist/renderer/assets/index-wYpjqVqC.js +167 -0
  26. package/dist/renderer/assets/knowledge-7pl06KuH.js +1 -0
  27. package/dist/renderer/assets/{pencil-Dv5WxhdC.js → pencil-CB1SWZ9A.js} +1 -1
  28. package/dist/renderer/assets/{play-DnCnft83.js → play-BvsoXUrM.js} +1 -1
  29. package/dist/renderer/assets/{plus-DsxIagzS.js → plus-CokBDnaL.js} +1 -1
  30. package/dist/renderer/assets/{save-CST01lIc.js → save-D-w4kATO.js} +1 -1
  31. package/dist/renderer/assets/{search-B_bqy6Wd.js → search-Cnsn6i4Q.js} +1 -1
  32. package/dist/renderer/assets/{shield-check-D6lG5Aoc.js → shield-check-Cjja2Gh6.js} +1 -1
  33. package/dist/renderer/assets/threads-BCm6j4eI.js +1 -0
  34. package/dist/renderer/assets/{trash-2-Cefngb6Q.js → trash-2-CIxz9qYY.js} +1 -1
  35. package/dist/renderer/index.html +2 -2
  36. package/dist-electron/packages/contracts/src/automation.js +2 -0
  37. package/dist-electron/packages/contracts/src/channels.js +2 -0
  38. package/dist-electron/packages/contracts/src/knowledge.js +2 -0
  39. package/dist-electron/packages/contracts/src/local-core.js +15 -0
  40. package/dist-electron/packages/contracts/src/runtime.js +2 -0
  41. package/dist-electron/packages/contracts/src/scheduler.js +2 -0
  42. package/dist-electron/packages/contracts/src/threads.js +2 -0
  43. package/dist-electron/packages/core-sdk/src/automation.js +32 -0
  44. package/dist-electron/packages/core-sdk/src/channels.js +121 -0
  45. package/dist-electron/packages/core-sdk/src/client.js +455 -0
  46. package/dist-electron/packages/core-sdk/src/index.js +43 -607
  47. package/dist-electron/packages/core-sdk/src/knowledge.js +85 -0
  48. package/dist-electron/packages/core-sdk/src/request.js +22 -0
  49. package/dist-electron/packages/core-sdk/src/runtime.js +214 -0
  50. package/dist-electron/packages/core-sdk/src/scheduler.js +32 -0
  51. package/dist-electron/packages/core-sdk/src/threads.js +67 -0
  52. package/dist-electron/packages/plugin-sdk/src/agents.js +2 -0
  53. package/dist-electron/packages/plugin-sdk/src/automation.js +2 -0
  54. package/dist-electron/packages/plugin-sdk/src/channels.js +2 -0
  55. package/dist-electron/packages/plugin-sdk/src/index.js +21 -0
  56. package/dist-electron/packages/plugin-sdk/src/knowledge.js +2 -0
  57. package/dist-electron/packages/plugin-sdk/src/runtime.js +2 -0
  58. package/dist-electron/packages/plugin-sdk/src/scheduler.js +2 -0
  59. package/dist-electron/packages/plugin-sdk/src/threads.js +2 -0
  60. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +5 -8
  61. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +2 -2
  62. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +3 -3
  63. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +5 -5
  64. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +12 -12
  65. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +2 -2
  66. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +11 -11
  67. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +3 -3
  68. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +7 -7
  69. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +2 -2
  70. package/dist-electron/services/local-ai-core/src/agents/claudecode/definition.js +3 -3
  71. package/dist-electron/services/local-ai-core/src/agents/codex/definition.js +3 -3
  72. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/definition.js +2 -2
  73. package/dist-electron/services/local-ai-core/src/agents/localcore-acp/index.js +4 -4
  74. package/dist-electron/services/local-ai-core/src/agents/opencode/launch.js +2 -2
  75. package/dist-electron/services/local-ai-core/src/agents/pi/definition.js +2 -2
  76. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +3 -3
  77. package/dist-electron/services/local-ai-core/src/agents/pi/provider-materializer.js +1 -1
  78. package/dist-electron/services/local-ai-core/src/agents/shared/agent-plugin.js +4 -4
  79. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +33 -18
  80. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -2
  81. package/dist-electron/services/local-ai-core/src/channel/lark/gateway-utils.js +91 -0
  82. package/dist-electron/services/local-ai-core/src/channel/lark/inbound-handler.js +180 -0
  83. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +52 -486
  84. package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +124 -0
  85. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
  86. package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
  87. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
  88. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
  89. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +50 -469
  90. package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +156 -0
  91. package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +100 -0
  92. package/dist-electron/services/local-ai-core/src/cli/lac.js +6 -6
  93. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
  94. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
  95. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
  96. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
  97. package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
  98. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
  99. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
  100. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
  101. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
  102. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
  103. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
  104. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
  105. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
  106. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
  107. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
  108. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
  109. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
  110. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
  111. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
  112. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
  113. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
  114. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
  115. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
  116. package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
  117. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
  118. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
  119. package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
  120. package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
  121. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
  122. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
  123. package/dist-electron/shared/desktop.js +1 -64
  124. package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
  125. package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
  126. package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
  127. package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
  128. package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
  129. package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
  130. package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
  131. package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
  132. package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
  133. package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
  134. package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
  135. package/dist-electron/tests/electron/core-client.test.js +284 -0
  136. package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
  137. package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
  138. package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
  139. package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
  140. package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
  141. package/dist-electron/tests/integration/lark-gateway.test.js +4 -4
  142. package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
  143. package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
  144. package/package.json +9 -4
  145. package/dist/renderer/assets/Chat-C5Bkm9-M.js +0 -2
  146. package/dist/renderer/assets/ChatMarkdown-uc36EzyD.js +0 -45
  147. package/dist/renderer/assets/Config-DHtQuuLy.js +0 -21
  148. package/dist/renderer/assets/CronList-BYUnhzSC.js +0 -1
  149. package/dist/renderer/assets/Dashboard-BPnGMDg3.js +0 -26
  150. package/dist/renderer/assets/Logs-Dyd2Uwlt.js +0 -1
  151. package/dist/renderer/assets/MonitorList-Byg3E3Gt.js +0 -1
  152. package/dist/renderer/assets/Page-7DxXvTMm.js +0 -1
  153. package/dist/renderer/assets/ProjectDetail-Dfr5s0Ja.js +0 -11
  154. package/dist/renderer/assets/ProjectList-CDDQjAQ_.js +0 -1
  155. package/dist/renderer/assets/SessionChat-s7CAaCPL.js +0 -1
  156. package/dist/renderer/assets/SessionList-D-OycKKS.js +0 -1
  157. package/dist/renderer/assets/ThreadChat-CLdFynB5.js +0 -28
  158. package/dist/renderer/assets/Workspace-xfT5z4j_.js +0 -19
  159. package/dist/renderer/assets/bot-CWQ5-ovl.js +0 -6
  160. package/dist/renderer/assets/check-DKM7zfWG.js +0 -6
  161. package/dist/renderer/assets/chevron-down-Dfw2KU87.js +0 -6
  162. package/dist/renderer/assets/circle-CoP4RA4s.js +0 -6
  163. package/dist/renderer/assets/desktop-CsDYrOOU.js +0 -1
  164. package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
  165. package/dist/renderer/assets/funnel-DpVLlG3g.js +0 -6
  166. package/dist/renderer/assets/heart-BMD36ejP.js +0 -6
  167. package/dist/renderer/assets/index-COxSYBjE.js +0 -182
  168. package/dist/renderer/assets/index-CTGTI-cm.js +0 -41
  169. package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
  170. package/dist/renderer/assets/projects-DgjHcNgt.js +0 -1
  171. package/dist/renderer/assets/server-ecH4GNwa.js +0 -11
  172. package/dist/renderer/assets/session-utils-Dd_WKMYW.js +0 -6
  173. package/dist/renderer/assets/sessions-BQ33Mv4k.js +0 -1
  174. package/dist/renderer/assets/user-D_8RSH-T.js +0 -6
  175. package/dist/renderer/assets/wifi-off-DB9D-pOu.js +0 -11
  176. package/dist-electron/src/api/client.js +0 -73
  177. package/dist-electron/src/api/sessions.js +0 -21
  178. package/dist-electron/src/lib/session-utils.js +0 -51
  179. package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
  180. package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
@@ -3,28 +3,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.LocalCoreWeixinGateway = void 0;
7
- exports.createWeixinAttachmentContentPart = createWeixinAttachmentContentPart;
6
+ exports.LocalCoreWeixinGateway = exports.createWeixinAttachmentContentPart = void 0;
8
7
  const node_crypto_1 = __importDefault(require("node:crypto"));
9
8
  const node_fs_1 = __importDefault(require("node:fs"));
10
- const node_path_1 = __importDefault(require("node:path"));
11
9
  const node_crypto_2 = require("node:crypto");
12
10
  const node_stream_1 = require("node:stream");
13
- const desktop_js_1 = require("../../../../../shared/desktop.js");
14
11
  const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
15
12
  const content_js_1 = require("../shared/content.js");
16
13
  const file_utils_js_1 = require("../shared/file-utils.js");
17
14
  const inbound_attachment_store_js_1 = require("../shared/inbound-attachment-store.js");
18
15
  const thread_routing_js_1 = require("../shared/thread-routing.js");
19
16
  const base_channel_gateway_js_1 = require("../shared/base-channel-gateway.js");
17
+ const inbound_authorization_js_1 = require("../shared/inbound-authorization.js");
20
18
  const channel_keys_js_1 = require("../shared/channel-keys.js");
21
19
  const config_js_1 = require("./config.js");
22
20
  const transport_js_1 = require("./transport.js");
21
+ const runtime_state_js_1 = require("./runtime-state.js");
22
+ const text_utils_js_1 = require("./text-utils.js");
23
+ const inbound_poller_js_1 = require("./inbound-poller.js");
24
+ var inbound_media_js_1 = require("./inbound-media.js");
25
+ Object.defineProperty(exports, "createWeixinAttachmentContentPart", { enumerable: true, get: function () { return inbound_media_js_1.createWeixinAttachmentContentPart; } });
23
26
  // ==================== Constants ====================
24
- const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
25
- const RETRY_DELAY_MS = 2_000;
26
- const BACKOFF_DELAY_MS = 30_000;
27
- const MAX_CONSECUTIVE_FAILURES = 3;
28
27
  const PROCESSED_MESSAGE_TTL_MS = 10 * 60 * 1000;
29
28
  const WEIXIN_TEXT_MESSAGE_MAX_BYTES = 900;
30
29
  const WEIXIN_CONTEXT_REPLY_MAX_BYTES = 3500;
@@ -33,125 +32,9 @@ const WEIXIN_RESERVED_TERMINAL_SENDS = 1;
33
32
  const WEIXIN_PROGRESS_SEND_BUDGET = WEIXIN_CONTEXT_SEND_LIMIT - WEIXIN_RESERVED_TERMINAL_SENDS;
34
33
  const RESPONSE_TIMEOUT_MS = 5 * 60 * 1000;
35
34
  const WEIXIN_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
36
- const ERROR_LOG_WINDOW_MS = 5 * 60 * 1000;
37
- // ==================== Utilities ====================
38
- function stripHtml(html) {
39
- let result = html;
40
- let prev;
41
- do {
42
- prev = result;
43
- result = result.replace(/<[^>]*>/g, '');
44
- } while (result !== prev);
45
- return result.replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, ' ');
46
- }
47
- function formatError(err) {
48
- if (err instanceof Error) {
49
- const cause = err.cause;
50
- return cause !== undefined ? `${err.message}: ${String(cause)}` : err.message;
51
- }
52
- return String(err);
53
- }
54
- function sleep(ms, signal) {
55
- return new Promise((resolve, reject) => {
56
- const t = setTimeout(resolve, ms);
57
- const onAbort = () => { clearTimeout(t); reject(new Error('aborted')); };
58
- signal?.addEventListener('abort', onAbort, { once: true });
59
- });
60
- }
61
- function utf8ByteLength(value) {
62
- return Buffer.byteLength(value, 'utf-8');
63
- }
64
- function splitTextByUtf8Bytes(text, maxBytes) {
65
- const normalized = String(text || '').replace(/\r\n/g, '\n').trim();
66
- if (!normalized)
67
- return [];
68
- if (utf8ByteLength(normalized) <= maxBytes)
69
- return [normalized];
70
- const chunks = [];
71
- let current = '';
72
- const pushCurrent = () => {
73
- const trimmed = current.trim();
74
- if (trimmed)
75
- chunks.push(trimmed);
76
- current = '';
77
- };
78
- const appendPart = (part) => {
79
- if (!part.trim())
80
- return;
81
- const separator = current ? '\n\n' : '';
82
- if (current && utf8ByteLength(`${current}${separator}${part}`) <= maxBytes) {
83
- current = `${current}${separator}${part}`;
84
- return;
85
- }
86
- if (current)
87
- pushCurrent();
88
- if (utf8ByteLength(part) <= maxBytes) {
89
- current = part;
90
- return;
91
- }
92
- let segment = '';
93
- for (const char of Array.from(part)) {
94
- if (segment && utf8ByteLength(`${segment}${char}`) > maxBytes) {
95
- chunks.push(segment);
96
- segment = '';
97
- }
98
- segment += char;
99
- }
100
- current = segment;
101
- };
102
- for (const part of normalized.split(/\n{2,}/)) {
103
- appendPart(part);
104
- }
105
- pushCurrent();
106
- return chunks;
107
- }
108
- function createWeixinAttachmentContentPart(att) {
109
- if (att.kind === 'image') {
110
- if (!att.data)
111
- return null;
112
- return {
113
- type: 'image',
114
- data: att.data,
115
- ...(att.uri ? { uri: att.uri } : {}),
116
- mimeType: att.mimeType,
117
- fileName: att.name,
118
- };
119
- }
120
- return {
121
- type: 'file',
122
- path: att.path,
123
- fileName: att.name,
124
- };
125
- }
126
- function truncateTextByUtf8Bytes(text, maxBytes) {
127
- const normalized = String(text || '').replace(/\r\n/g, '\n').trim();
128
- if (utf8ByteLength(normalized) <= maxBytes)
129
- return normalized;
130
- const suffix = '\n\n(内容过长,已截断以保证微信送达)';
131
- const budget = Math.max(0, maxBytes - utf8ByteLength(suffix));
132
- let result = '';
133
- for (const char of Array.from(normalized)) {
134
- if (utf8ByteLength(`${result}${char}`) > budget)
135
- break;
136
- result += char;
137
- }
138
- return `${result.trim()}${suffix}`;
139
- }
140
- function renderBridgeContentForWeixin(event) {
141
- const toolCall = event.toolCall;
142
- if (!toolCall) {
143
- return String(event.content || '').trim();
144
- }
145
- const name = String(toolCall.name || '').trim() || 'Tool update';
146
- const status = String(toolCall.status || '').trim();
147
- if (name === 'Tool update' && status === 'completed')
148
- return '';
149
- return [name, status].filter(Boolean).join(' - ');
150
- }
151
35
  // ==================== Gateway Class ====================
152
36
  class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGateway {
153
37
  processedInboundMessages = new Map();
154
- pollErrorLogWindows = new Map();
155
38
  inboundAttachmentStore = new inbound_attachment_store_js_1.FileSystemInboundAttachmentStore();
156
39
  platform = 'weixin';
157
40
  constructor(options) {
@@ -172,7 +55,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
172
55
  return (0, config_js_1.collectWeixinWorkspaceBindings)(config);
173
56
  }
174
57
  buildStatusObject(state, resolved) {
175
- this.options.store.expirePendingPairings();
176
58
  const platformKey = state.platformKey || (0, channel_keys_js_1.channelPlatformKey)('weixin', resolved.instanceId);
177
59
  const pairings = this.options.store.listPendingPairings(state.workspaceId)
178
60
  .filter((row) => row.platform === platformKey && row.expires_at >= new Date().toISOString());
@@ -329,19 +211,19 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
329
211
  const bridgeThreadId = route.threadId || binding.thread_id;
330
212
  if (this.mutedThreadBridgeCounts.has(bridgeThreadId))
331
213
  return;
332
- const turn = this.getOrCreateTurnState(sessionKey);
214
+ const turn = (0, runtime_state_js_1.getOrCreateWeixinTurnState)(this.outboundTurns, sessionKey);
333
215
  if (event.replyCtx) {
334
216
  // WeChat doesn't support reply context; ignore
335
217
  }
336
- this.consumeBridgeEvent(turn, event);
218
+ (0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, event);
337
219
  if (event.type !== 'reply' && event.type !== 'buttons' && event.type !== 'status')
338
220
  return;
339
- const rendered = this.renderTurnText(turn);
221
+ const rendered = (0, runtime_state_js_1.renderWeixinTurnText)(turn);
340
222
  if (!rendered)
341
223
  return;
342
224
  if (rendered === turn.lastSentText)
343
225
  return;
344
- const terminalMessage = this.isTerminalBridgeMessage(event, rendered);
226
+ const terminalMessage = (0, runtime_state_js_1.isTerminalWeixinBridgeMessage)(event, rendered);
345
227
  if (binding.last_platform_message_id && !terminalMessage && turn.sentCount >= WEIXIN_PROGRESS_SEND_BUDGET) {
346
228
  turn.foldedProgressCount += 1;
347
229
  this.options.log?.(`localcore-weixin folded progress for sessionKey=${sessionKey}: sent=${turn.sentCount} folded=${turn.foldedProgressCount}`);
@@ -364,7 +246,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
364
246
  this.options.log?.(`localcore-weixin sent message for sessionKey=${sessionKey} type=${event.type} sent=${turn.sentCount}/${binding.last_platform_message_id ? WEIXIN_CONTEXT_SEND_LIMIT : 'unlimited'}`);
365
247
  }
366
248
  catch (error) {
367
- this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${formatError(error)}`);
249
+ this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${(0, text_utils_js_1.formatWeixinError)(error)}`);
368
250
  }
369
251
  })
370
252
  .finally(() => {
@@ -389,7 +271,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
389
271
  const previousRoute = this.threadRouting.get(input.sessionKey);
390
272
  this.threadRouting.set(input.sessionKey, route);
391
273
  if (!this.outboundTurns.has(input.sessionKey)) {
392
- this.createTurnState(input.sessionKey);
274
+ this.outboundTurns.set(input.sessionKey, (0, runtime_state_js_1.createWeixinTurnState)(input.sessionKey));
393
275
  }
394
276
  return () => {
395
277
  if (previousRoute) {
@@ -492,52 +374,32 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
492
374
  messageId: msg.messageId,
493
375
  },
494
376
  });
495
- this.options.store.expirePendingPairings();
496
377
  const binding = await this.getBinding(msg.workspaceId, instanceId);
497
- let authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
498
- if (!authorized) {
499
- if (binding.allowFrom === '*') {
500
- const authorizedAt = new Date().toISOString();
501
- this.options.store.createAuthorizedUser({
502
- id: `wx-user-${(0, node_crypto_2.randomUUID)()}`,
503
- workspace_id: msg.workspaceId,
504
- platform: platformKey,
505
- platform_user_id: msg.platformUserId,
506
- chat_id: msg.chatId,
507
- display_name: msg.displayName,
508
- thread_id: null,
509
- authorized_at: authorizedAt,
510
- });
511
- authorized = this.options.store.getAuthorizedUser(msg.workspaceId, msg.platformUserId, platformKey);
512
- this.options.log?.(`localcore-weixin auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
513
- this.notifyRuntimeStateChanged();
514
- }
515
- }
516
- if (!authorized) {
517
- const existingPending = this.options.store.listPendingPairings(msg.workspaceId).find((item) => item.platform === platformKey && item.platform_user_id === msg.platformUserId && item.chat_id === msg.chatId && item.status === 'pending');
518
- let pairingCode = existingPending?.code || '';
519
- if (!existingPending) {
520
- const now = new Date();
521
- pairingCode = String((0, node_crypto_2.randomInt)(100000, 1000000));
522
- this.options.store.createPairingRequest({
523
- code: pairingCode,
524
- workspace_id: msg.workspaceId,
525
- platform: platformKey,
526
- platform_user_id: msg.platformUserId,
527
- chat_id: msg.chatId,
528
- display_name: msg.displayName,
529
- requested_at: now.toISOString(),
530
- expires_at: new Date(now.getTime() + PAIRING_EXPIRY_MS).toISOString(),
531
- status: 'pending',
532
- });
533
- this.notifyRuntimeStateChanged();
534
- }
378
+ const authorization = (0, inbound_authorization_js_1.resolveInboundChannelAuthorization)({
379
+ store: this.options.store,
380
+ identity: {
381
+ workspaceId: msg.workspaceId,
382
+ platformKey,
383
+ platformUserId: msg.platformUserId,
384
+ chatId: msg.chatId,
385
+ displayName: msg.displayName,
386
+ },
387
+ autoApprove: binding.allowFrom === '*',
388
+ authorizedUserIdPrefix: 'wx-user',
389
+ generatePairingCode: () => String((0, node_crypto_2.randomInt)(100000, 1000000)),
390
+ onStateChanged: () => this.notifyRuntimeStateChanged(),
391
+ });
392
+ if (authorization.status === 'pending') {
535
393
  const state = this.runtime.get((0, channel_keys_js_1.runtimeKey)(msg.workspaceId, instanceId));
536
394
  if (state?.connected) {
537
- await this.sendTextMessage(state, msg.chatId, `**已收到消息**\n\n当前账号还未授权接入这个工作区。\n请在桌面端完成审批后再次发送消息。\n\n配对码:\`${pairingCode}\``, msg.contextToken);
395
+ await this.sendTextMessage(state, msg.chatId, `**已收到消息**\n\n当前账号还未授权接入这个工作区。\n请在桌面端完成审批后再次发送消息。\n\n配对码:\`${authorization.pairingCode}\``, msg.contextToken);
538
396
  }
539
397
  return;
540
398
  }
399
+ if (authorization.autoApproved) {
400
+ this.options.log?.(`localcore-weixin auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
401
+ }
402
+ const authorized = authorization.authorized;
541
403
  const router = this.options.getWorkspaceRouter();
542
404
  let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
543
405
  store: this.options.store,
@@ -588,10 +450,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
588
450
  return;
589
451
  }
590
452
  this.options.store.updatePlatformThreadMessageId(msg.workspaceId, msg.chatId, msg.platformUserId, msg.contextToken || msg.messageId, platformKey);
591
- const wrappedText = slashCommand
592
- ? msg.text
593
- : (0, desktop_js_1.wrapUserMessageWithSchedulerProtocol)(msg.text);
594
- await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, msg.contentParts));
453
+ await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(msg.text, msg.contentParts));
595
454
  return;
596
455
  }
597
456
  async resolveDefaultAgentType(workspaceId, threadId) {
@@ -638,7 +497,18 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
638
497
  status.connectedAt = new Date().toISOString();
639
498
  this.clearRuntimeError(status);
640
499
  // Start long-poll loop in background
641
- this.runMonitorLoop(binding, abortController.signal).catch((err) => {
500
+ (0, inbound_poller_js_1.runWeixinInboundPoller)({
501
+ binding,
502
+ signal: abortController.signal,
503
+ getRuntimeState: () => this.runtime.get((0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId)),
504
+ getAuthorizedUser: (workspaceId, platformUserId, platformKey) => this.options.store.getAuthorizedUser(workspaceId, platformUserId, platformKey),
505
+ clearRuntimeError: (runtimeState) => this.clearRuntimeError(runtimeState),
506
+ setRuntimeError: (runtimeState, errorInfo) => this.setRuntimeError(runtimeState, errorInfo),
507
+ notifyRuntimeStateChanged: () => this.notifyRuntimeStateChanged(),
508
+ downloadMediaItem: (item, messageId, index, uploadsDir, workspaceBinding) => this.downloadMediaItem(item, messageId, index, uploadsDir, workspaceBinding),
509
+ handleInboundMessage: (message) => this.handleInboundMessage(message),
510
+ log: this.options.log,
511
+ }).catch((err) => {
642
512
  if (!abortController.signal.aborted) {
643
513
  status.status = 'error';
644
514
  status.connected = false;
@@ -665,136 +535,13 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
665
535
  return 'expired';
666
536
  return 'wait';
667
537
  }
668
- async runMonitorLoop(binding, signal) {
669
- let buf = (0, config_js_1.loadWeixinBuf)(binding);
670
- let consecutiveFailures = 0;
671
- while (!signal.aborted) {
672
- try {
673
- const resp = await (0, transport_js_1.getWeixinUpdates)(binding, buf, signal);
674
- const isApiError = (resp.ret !== undefined && resp.ret !== 0) || (resp.errcode !== undefined && resp.errcode !== 0);
675
- if (isApiError) {
676
- consecutiveFailures++;
677
- const state = this.runtime.get((0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId));
678
- const retryDelayMs = this.computeRetryDelay(consecutiveFailures);
679
- if (resp.errcode === -14 || resp.ret === -14) {
680
- if (state) {
681
- state.status = 'error';
682
- state.connected = false;
683
- state.consecutiveFailures = consecutiveFailures;
684
- state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
685
- this.setRuntimeError(state, (0, local_core_errors_js_1.toLocalCoreErrorInfo)(new local_core_errors_js_1.LocalCoreError('channel_session_expired', 'WeChat login expired.')));
686
- this.notifyRuntimeStateChanged();
687
- }
688
- }
689
- this.logPollError(binding, `ret=${resp.ret} errcode=${resp.errcode} errmsg=${resp.errmsg || ''}`, `localcore-weixin getUpdates failed for ${binding.workspaceId}: ret=${resp.ret} errcode=${resp.errcode}${resp.errmsg ? ` errmsg=${resp.errmsg}` : ''} (${consecutiveFailures})`);
690
- if (state && resp.errcode !== -14 && resp.ret !== -14) {
691
- state.consecutiveFailures = consecutiveFailures;
692
- state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
693
- }
694
- await sleep(retryDelayMs, signal);
695
- if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
696
- consecutiveFailures = MAX_CONSECUTIVE_FAILURES;
697
- }
698
- continue;
699
- }
700
- consecutiveFailures = 0;
701
- const state = this.runtime.get((0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId));
702
- if (state) {
703
- this.clearRuntimeError(state);
704
- state.status = 'running';
705
- state.connected = true;
706
- this.notifyRuntimeStateChanged();
707
- }
708
- if (resp.get_updates_buf) {
709
- buf = resp.get_updates_buf;
710
- (0, config_js_1.saveWeixinBuf)(binding, buf);
711
- }
712
- for (const msg of resp.msgs ?? []) {
713
- const items = msg.item_list ?? [];
714
- const textItem = items.find((i) => i.type === transport_js_1.TEXT_ITEM_TYPE);
715
- const voiceTextItems = items.filter((i) => i.type === transport_js_1.VOICE_ITEM_TYPE && i.voice_item?.text);
716
- const mediaItems = items.filter((i) => i.type === transport_js_1.IMAGE_ITEM_TYPE || i.type === transport_js_1.FILE_ITEM_TYPE);
717
- if (!textItem && voiceTextItems.length === 0 && mediaItems.length === 0)
718
- continue;
719
- const conversationId = msg.from_user_id ?? '';
720
- const text = [textItem?.text_item?.text?.trim(), ...voiceTextItems.map((i) => i.voice_item?.text?.trim())]
721
- .filter((part) => Boolean(part))
722
- .join('\n\n');
723
- const msgId = msg.msg_id ?? String(Date.now());
724
- // Handle attachments
725
- let attachmentText = '';
726
- const attachmentParts = [];
727
- if (mediaItems.length > 0) {
728
- const uploadsDir = node_path_1.default.join(binding.stateDir, 'weixin-uploads');
729
- const mayMaterializeAttachments = binding.allowFrom === '*'
730
- || Boolean(this.options.store.getAuthorizedUser(binding.workspaceId, conversationId, binding.platformKey));
731
- for (const [idx, item] of mediaItems.entries()) {
732
- const itemData = item.image_item ?? item.file_item ?? null;
733
- const declaredName = String(itemData?.file_name ?? (item.type === transport_js_1.IMAGE_ITEM_TYPE ? 'image' : 'file'));
734
- if (!mayMaterializeAttachments) {
735
- attachmentText += attachmentText ? '\n' : '';
736
- attachmentText += item.type === transport_js_1.IMAGE_ITEM_TYPE ? '[Image]' : `[File: ${declaredName}]`;
737
- continue;
738
- }
739
- try {
740
- const att = await this.downloadMediaItem(item, msgId, idx, uploadsDir, binding);
741
- if (att) {
742
- attachmentText += attachmentText ? '\n' : '';
743
- attachmentText += att.kind === 'image' ? `[Image: ${att.path}]` : `[File "${att.name}": ${att.path}]`;
744
- const part = createWeixinAttachmentContentPart(att);
745
- if (part)
746
- attachmentParts.push(part);
747
- }
748
- }
749
- catch (dlErr) {
750
- this.options.log?.(`localcore-weixin attachment download failed (${conversationId}#${idx}): ${formatError(dlErr)}`);
751
- }
752
- }
753
- }
754
- const fullText = [text, attachmentText].filter(Boolean).join('\n\n');
755
- if (!fullText)
756
- continue;
757
- await this.handleInboundMessage({
758
- workspaceId: binding.workspaceId,
759
- instanceId: binding.instanceId,
760
- platformKey: binding.platformKey,
761
- platformUserId: conversationId,
762
- chatId: conversationId,
763
- displayName: conversationId.slice(-6),
764
- text: fullText,
765
- messageId: msgId,
766
- contextToken: msg.context_token,
767
- contentParts: [
768
- ...(text ? [{ type: 'text', text }] : []),
769
- ...attachmentParts,
770
- ],
771
- });
772
- }
773
- }
774
- catch (err) {
775
- if (signal.aborted)
776
- return;
777
- consecutiveFailures++;
778
- const retryDelayMs = this.computeRetryDelay(consecutiveFailures);
779
- const state = this.runtime.get((0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId));
780
- if (state) {
781
- state.consecutiveFailures = consecutiveFailures;
782
- state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
783
- this.setRuntimeError(state, (0, local_core_errors_js_1.toLocalCoreErrorInfo)(err));
784
- this.notifyRuntimeStateChanged();
785
- }
786
- this.logPollError(binding, formatError(err), `localcore-weixin getUpdates error for ${binding.workspaceId} (${consecutiveFailures}): ${formatError(err)}`);
787
- await sleep(retryDelayMs, signal);
788
- }
789
- }
790
- }
791
538
  // ==================== Private: HTTP API ====================
792
539
  async sendTextMessage(state, toUserId, text, contextToken, options = {}) {
793
540
  const binding = await this.getBinding(state.workspaceId);
794
- const stripped = stripHtml(text);
541
+ const stripped = (0, text_utils_js_1.stripWeixinHtml)(text);
795
542
  const chunks = contextToken
796
- ? [truncateTextByUtf8Bytes(stripped, WEIXIN_CONTEXT_REPLY_MAX_BYTES)].filter(Boolean)
797
- : splitTextByUtf8Bytes(stripped, WEIXIN_TEXT_MESSAGE_MAX_BYTES);
543
+ ? [(0, text_utils_js_1.truncateTextByUtf8Bytes)(stripped, WEIXIN_CONTEXT_REPLY_MAX_BYTES)].filter(Boolean)
544
+ : (0, text_utils_js_1.splitTextByUtf8Bytes)(stripped, WEIXIN_TEXT_MESSAGE_MAX_BYTES);
798
545
  for (const [index, chunk] of chunks.entries()) {
799
546
  const finalChunk = options.final && index === chunks.length - 1;
800
547
  const resp = await (0, transport_js_1.sendWeixinTextMessageChunk)(binding, toUserId, chunk, contextToken, {
@@ -802,7 +549,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
802
549
  final: finalChunk,
803
550
  });
804
551
  if ((0, transport_js_1.isWeixinApiError)(resp)) {
805
- throw new Error(`WeChat sendmessage failed: ret=${resp.ret} errcode=${resp.errcode}${resp.errmsg ? ` errmsg=${resp.errmsg}` : ''} chunk=${index + 1}/${chunks.length} bytes=${utf8ByteLength(chunk)} context=${contextToken ? 'yes' : 'no'} message_state=${finalChunk ? 2 : 1}`);
552
+ throw new Error(`WeChat sendmessage failed: ret=${resp.ret} errcode=${resp.errcode}${resp.errmsg ? ` errmsg=${resp.errmsg}` : ''} chunk=${index + 1}/${chunks.length} bytes=${(0, text_utils_js_1.utf8ByteLength)(chunk)} context=${contextToken ? 'yes' : 'no'} message_state=${finalChunk ? 2 : 1}`);
806
553
  }
807
554
  }
808
555
  this.options.log?.(`localcore-weixin sent message to ${toUserId} for workspace ${state.workspaceId}${chunks.length > 1 ? ` chunks=${chunks.length}` : ''}`);
@@ -961,149 +708,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
961
708
  return 'image/gif';
962
709
  return 'application/octet-stream';
963
710
  }
964
- // ==================== Private: Turn State ====================
965
- createTurnState(sessionKey) {
966
- const turn = {
967
- sessionKey,
968
- sentCount: 0,
969
- foldedProgressCount: 0,
970
- awaitingPermission: false,
971
- processing: false,
972
- previewText: '',
973
- finalText: '',
974
- thinkingSteps: [],
975
- pendingThoughtText: undefined,
976
- statusLines: [],
977
- buttonRows: [],
978
- lastSentAt: 0,
979
- lastSentText: '',
980
- };
981
- this.outboundTurns.set(sessionKey, turn);
982
- return turn;
983
- }
984
- getOrCreateTurnState(sessionKey) {
985
- return this.outboundTurns.get(sessionKey) || this.createTurnState(sessionKey);
986
- }
987
- consumeBridgeEvent(turn, event) {
988
- const content = renderBridgeContentForWeixin(event);
989
- const bridgeKind = this.resolveBridgeEventKind(event);
990
- if (event.type === 'typing_start') {
991
- turn.processing = true;
992
- turn.previewText = '';
993
- turn.finalText = '';
994
- turn.thinkingSteps = [];
995
- turn.pendingThoughtText = undefined;
996
- turn.statusLines = [];
997
- turn.buttonRows = [];
998
- return;
999
- }
1000
- if (event.type === 'typing_stop') {
1001
- turn.processing = false;
1002
- return;
1003
- }
1004
- if (event.type === 'preview_start' || event.type === 'update_message') {
1005
- if (bridgeKind === 'thought') {
1006
- turn.pendingThoughtText = content;
1007
- return;
1008
- }
1009
- turn.previewText = content;
1010
- return;
1011
- }
1012
- if (bridgeKind !== 'thought') {
1013
- this.flushPendingThought(turn);
1014
- }
1015
- if (event.type === 'status') {
1016
- if (content) {
1017
- this.pushUnique(turn.statusLines, content);
1018
- turn.finalText = content;
1019
- turn.previewText = content;
1020
- }
1021
- return;
1022
- }
1023
- if (event.type === 'buttons') {
1024
- turn.awaitingPermission = true;
1025
- turn.buttonRows = Array.isArray(event.buttonRows)
1026
- ? event.buttonRows
1027
- .map((row) => Array.isArray(row)
1028
- ? row.filter((b) => Boolean(b?.text && b?.data))
1029
- .map((b) => ({ text: b.text, data: b.data }))
1030
- : [])
1031
- .filter((row) => row.length > 0)
1032
- : [];
1033
- return;
1034
- }
1035
- if (!content)
1036
- return;
1037
- if (bridgeKind === 'thought' || bridgeKind === 'plan') {
1038
- this.pushUnique(turn.thinkingSteps, content);
1039
- return;
1040
- }
1041
- if (bridgeKind === 'tool' || bridgeKind === 'status') {
1042
- this.pushUnique(turn.statusLines, content);
1043
- return;
1044
- }
1045
- turn.finalText = content;
1046
- turn.previewText = content;
1047
- }
1048
- renderTurnText(turn) {
1049
- const sections = [];
1050
- if (turn.thinkingSteps.length > 0) {
1051
- sections.push(`**中间过程**\n${turn.thinkingSteps.map((step) => `• ${step.replace(/\s+/g, ' ').trim()}`).join('\n')}`);
1052
- }
1053
- if (turn.finalText) {
1054
- sections.push(turn.finalText);
1055
- }
1056
- else if (turn.previewText) {
1057
- sections.push(turn.previewText);
1058
- }
1059
- else if (turn.statusLines.length > 0) {
1060
- sections.push(`**处理中**\n${turn.statusLines.slice(-3).map((l) => `• ${l.replace(/\s+/g, ' ').trim()}`).join('\n')}`);
1061
- }
1062
- else if (turn.processing) {
1063
- sections.push('**处理中**\n正在思考...');
1064
- }
1065
- if (turn.awaitingPermission) {
1066
- sections.push('\n回复:`allow` / `allow all` / `deny`');
1067
- }
1068
- return sections.join('\n\n').trim();
1069
- }
1070
- flushPendingThought(turn) {
1071
- const text = String(turn.pendingThoughtText || '').trim();
1072
- if (!text)
1073
- return;
1074
- this.pushUnique(turn.thinkingSteps, text);
1075
- turn.pendingThoughtText = undefined;
1076
- }
1077
- isTerminalBridgeMessage(event, rendered) {
1078
- if (event.type === 'buttons')
1079
- return true;
1080
- if (event.type !== 'reply')
1081
- return false;
1082
- const bridgeKind = this.resolveBridgeEventKind(event);
1083
- if (bridgeKind === 'tool' || bridgeKind === 'thought' || bridgeKind === 'plan' || bridgeKind === 'status')
1084
- return false;
1085
- const normalized = rendered.trim();
1086
- if (!normalized)
1087
- return false;
1088
- return true;
1089
- }
1090
- resolveBridgeEventKind(event) {
1091
- if (event.bridgeKind) {
1092
- return event.bridgeKind;
1093
- }
1094
- return event.type === 'status' ? 'status' : 'assistant';
1095
- }
1096
- // ==================== Private: Helpers ====================
1097
- pushUnique(target, value) {
1098
- const normalized = value.trim();
1099
- if (!normalized)
1100
- return;
1101
- if (target[target.length - 1] === normalized)
1102
- return;
1103
- target.push(normalized);
1104
- if (target.length > 8)
1105
- target.splice(0, target.length - 8);
1106
- }
1107
711
  isDuplicateInboundMessage(input) {
1108
712
  const messageKey = input.contextToken || input.messageId;
1109
713
  if (!messageKey)
@@ -1138,29 +742,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
1138
742
  return null;
1139
743
  return { name: name.trim().toLowerCase(), args };
1140
744
  }
1141
- computeRetryDelay(failures) {
1142
- if (failures <= 1)
1143
- return RETRY_DELAY_MS;
1144
- if (failures === 2)
1145
- return 5_000;
1146
- if (failures === 3)
1147
- return 15_000;
1148
- if (failures === 4)
1149
- return 30_000;
1150
- return 60_000;
1151
- }
1152
- logPollError(binding, errorKey, message) {
1153
- const key = (0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId);
1154
- const current = this.pollErrorLogWindows.get(key);
1155
- const now = Date.now();
1156
- if (!current || current.errorKey !== errorKey || now - current.at >= ERROR_LOG_WINDOW_MS) {
1157
- this.pollErrorLogWindows.set(key, { at: now, count: 1, errorKey });
1158
- this.options.log?.(message);
1159
- return;
1160
- }
1161
- current.count += 1;
1162
- this.pollErrorLogWindows.set(key, current);
1163
- }
1164
745
  }
1165
746
  exports.LocalCoreWeixinGateway = LocalCoreWeixinGateway;
1166
747
  function getWeixinInstanceId(platform) {