@kafca/agentdock 0.1.56 → 0.1.58

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 (200) hide show
  1. package/README.md +7 -0
  2. package/dist/renderer/assets/{Badge-DjcoXx2J.js → Badge-BfY1VaHS.js} +1 -1
  3. package/dist/renderer/assets/Card-DWA_Tww_.js +1 -0
  4. package/dist/renderer/assets/Config-nHj3g1U5.js +21 -0
  5. package/dist/renderer/assets/CronList-BwkA_I7v.js +1 -0
  6. package/dist/renderer/assets/Dashboard-D0_A7k02.js +41 -0
  7. package/dist/renderer/assets/{EmptyState-DIZLiccW.js → EmptyState-zatDjLj_.js} +1 -1
  8. package/dist/renderer/assets/HighlightedMarkdown-CsM5n70d.js +12 -0
  9. package/dist/renderer/assets/Input-R1XdFK1K.js +1 -0
  10. package/dist/renderer/assets/{KnowledgeDetail-CJ9IYOsa.js → KnowledgeDetail-Co5sxeGd.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-BLGPwnBO.js → KnowledgeHome-DwziPw5m.js} +3 -3
  12. package/dist/renderer/assets/Logs-NwZUtR_G.js +6 -0
  13. package/dist/renderer/assets/{Modal-CQiUpfl4.js → Modal-CrcIwIFL.js} +3 -3
  14. package/dist/renderer/assets/MonitorList-CS1uLS5A.js +1 -0
  15. package/dist/renderer/assets/Page-Dp0obeSw.js +1 -0
  16. package/dist/renderer/assets/{Select-D6z65IT3.js → Select-6mVQaf84.js} +2 -2
  17. package/dist/renderer/assets/ThreadChat-BFzbn3L6.js +86 -0
  18. package/dist/renderer/assets/Workspace-DCmo8BMm.js +19 -0
  19. package/dist/renderer/assets/{arrow-left-CV5cL3f4.js → arrow-left-9rjg_Hp4.js} +1 -1
  20. package/dist/renderer/assets/{book-open-DThvB7pj.js → book-open-Bu8GCHnG.js} +1 -1
  21. package/dist/renderer/assets/channels-BxVbG-6j.js +6 -0
  22. package/dist/renderer/assets/chevron-down-BE8uQmWM.js +11 -0
  23. package/dist/renderer/assets/index-B7TeF6Es.js +41 -0
  24. package/dist/renderer/assets/index-BIKL3fTP.css +11 -0
  25. package/dist/renderer/assets/index-BkI9POxj.js +167 -0
  26. package/dist/renderer/assets/knowledge-Kl19SqGS.js +1 -0
  27. package/dist/renderer/assets/{pencil-Dv5WxhdC.js → pencil-CPB7SK1m.js} +1 -1
  28. package/dist/renderer/assets/{play-DnCnft83.js → play-DGAO4OCu.js} +1 -1
  29. package/dist/renderer/assets/{plus-DsxIagzS.js → plus-Bt26z-4q.js} +1 -1
  30. package/dist/renderer/assets/{save-CST01lIc.js → save-Une7GMxT.js} +1 -1
  31. package/dist/renderer/assets/{search-B_bqy6Wd.js → search-DE0agJjJ.js} +1 -1
  32. package/dist/renderer/assets/{shield-check-D6lG5Aoc.js → shield-check-De7xaXZh.js} +1 -1
  33. package/dist/renderer/assets/threads-BnsNL5ei.js +1 -0
  34. package/dist/renderer/assets/{trash-2-Cefngb6Q.js → trash-2-6iGF59Ac.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/automation/automation-conversation-executor.js +6 -47
  80. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +2 -5
  81. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +33 -18
  82. package/dist-electron/services/local-ai-core/src/channel/lark/config.js +2 -2
  83. package/dist-electron/services/local-ai-core/src/channel/lark/gateway-utils.js +91 -0
  84. package/dist-electron/services/local-ai-core/src/channel/lark/inbound-handler.js +180 -0
  85. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +58 -539
  86. package/dist-electron/services/local-ai-core/src/channel/lark/outbound-transport.js +112 -0
  87. package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +5 -20
  88. package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +37 -0
  89. package/dist-electron/services/local-ai-core/src/channel/shared/bridge-event-helpers.js +23 -0
  90. package/dist-electron/services/local-ai-core/src/channel/shared/channel-keys.js +6 -0
  91. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
  92. package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
  93. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
  94. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
  95. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +55 -512
  96. package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +149 -0
  97. package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +92 -0
  98. package/dist-electron/services/local-ai-core/src/cli/lac.js +9 -11
  99. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
  100. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
  101. package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +8 -0
  102. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
  103. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
  104. package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
  105. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
  106. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
  107. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
  108. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
  109. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
  110. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
  111. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
  112. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
  113. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
  114. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
  115. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
  116. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
  117. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
  118. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
  119. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
  120. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
  121. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
  122. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
  123. package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
  124. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
  125. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
  126. package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
  127. package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
  128. package/dist-electron/services/local-ai-core/src/sandbox/opensandbox-client.js +3 -2
  129. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
  130. package/dist-electron/services/local-ai-core/src/scheduler/base-channel-schedule-adapter.js +77 -0
  131. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +13 -79
  132. package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +2 -10
  133. package/dist-electron/services/local-ai-core/src/scheduler/run-polling.js +19 -0
  134. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +3 -37
  135. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-route.js +20 -0
  136. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +15 -28
  137. package/dist-electron/services/local-ai-core/src/scheduler/thread-resolution.js +12 -0
  138. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +13 -79
  139. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
  140. package/dist-electron/shared/desktop.js +1 -64
  141. package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
  142. package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
  143. package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
  144. package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
  145. package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
  146. package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
  147. package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
  148. package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
  149. package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
  150. package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
  151. package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
  152. package/dist-electron/tests/electron/core-client.test.js +284 -0
  153. package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
  154. package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
  155. package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
  156. package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
  157. package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
  158. package/dist-electron/tests/integration/lark-gateway.test.js +4 -4
  159. package/dist-electron/tests/integration/local-core-refactor.test.js +15 -8
  160. package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
  161. package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
  162. package/package.json +9 -4
  163. package/dist/renderer/assets/Chat-C5Bkm9-M.js +0 -2
  164. package/dist/renderer/assets/ChatMarkdown-uc36EzyD.js +0 -45
  165. package/dist/renderer/assets/Config-DHtQuuLy.js +0 -21
  166. package/dist/renderer/assets/CronList-BYUnhzSC.js +0 -1
  167. package/dist/renderer/assets/Dashboard-BPnGMDg3.js +0 -26
  168. package/dist/renderer/assets/Logs-Dyd2Uwlt.js +0 -1
  169. package/dist/renderer/assets/MonitorList-Byg3E3Gt.js +0 -1
  170. package/dist/renderer/assets/Page-7DxXvTMm.js +0 -1
  171. package/dist/renderer/assets/ProjectDetail-Dfr5s0Ja.js +0 -11
  172. package/dist/renderer/assets/ProjectList-CDDQjAQ_.js +0 -1
  173. package/dist/renderer/assets/SessionChat-s7CAaCPL.js +0 -1
  174. package/dist/renderer/assets/SessionList-D-OycKKS.js +0 -1
  175. package/dist/renderer/assets/ThreadChat-CLdFynB5.js +0 -28
  176. package/dist/renderer/assets/Workspace-xfT5z4j_.js +0 -19
  177. package/dist/renderer/assets/bot-CWQ5-ovl.js +0 -6
  178. package/dist/renderer/assets/check-DKM7zfWG.js +0 -6
  179. package/dist/renderer/assets/chevron-down-Dfw2KU87.js +0 -6
  180. package/dist/renderer/assets/circle-CoP4RA4s.js +0 -6
  181. package/dist/renderer/assets/desktop-CsDYrOOU.js +0 -1
  182. package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
  183. package/dist/renderer/assets/funnel-DpVLlG3g.js +0 -6
  184. package/dist/renderer/assets/heart-BMD36ejP.js +0 -6
  185. package/dist/renderer/assets/index-COxSYBjE.js +0 -182
  186. package/dist/renderer/assets/index-CTGTI-cm.js +0 -41
  187. package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
  188. package/dist/renderer/assets/projects-DgjHcNgt.js +0 -1
  189. package/dist/renderer/assets/server-ecH4GNwa.js +0 -11
  190. package/dist/renderer/assets/session-utils-Dd_WKMYW.js +0 -6
  191. package/dist/renderer/assets/sessions-BQ33Mv4k.js +0 -1
  192. package/dist/renderer/assets/user-D_8RSH-T.js +0 -6
  193. package/dist/renderer/assets/wifi-off-DB9D-pOu.js +0 -11
  194. package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +0 -13
  195. package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +0 -13
  196. package/dist-electron/src/api/client.js +0 -73
  197. package/dist-electron/src/api/sessions.js +0 -21
  198. package/dist-electron/src/lib/session-utils.js +0 -51
  199. package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
  200. package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
@@ -3,28 +3,28 @@ 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");
19
+ const local_core_slash_commands_js_1 = require("../../acp/local-core-slash-commands.js");
21
20
  const config_js_1 = require("./config.js");
22
21
  const transport_js_1 = require("./transport.js");
22
+ const runtime_state_js_1 = require("./runtime-state.js");
23
+ const text_utils_js_1 = require("./text-utils.js");
24
+ const inbound_poller_js_1 = require("./inbound-poller.js");
25
+ var inbound_media_js_1 = require("./inbound-media.js");
26
+ Object.defineProperty(exports, "createWeixinAttachmentContentPart", { enumerable: true, get: function () { return inbound_media_js_1.createWeixinAttachmentContentPart; } });
23
27
  // ==================== 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
28
  const PROCESSED_MESSAGE_TTL_MS = 10 * 60 * 1000;
29
29
  const WEIXIN_TEXT_MESSAGE_MAX_BYTES = 900;
30
30
  const WEIXIN_CONTEXT_REPLY_MAX_BYTES = 3500;
@@ -33,125 +33,9 @@ const WEIXIN_RESERVED_TERMINAL_SENDS = 1;
33
33
  const WEIXIN_PROGRESS_SEND_BUDGET = WEIXIN_CONTEXT_SEND_LIMIT - WEIXIN_RESERVED_TERMINAL_SENDS;
34
34
  const RESPONSE_TIMEOUT_MS = 5 * 60 * 1000;
35
35
  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
36
  // ==================== Gateway Class ====================
152
37
  class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGateway {
153
38
  processedInboundMessages = new Map();
154
- pollErrorLogWindows = new Map();
155
39
  inboundAttachmentStore = new inbound_attachment_store_js_1.FileSystemInboundAttachmentStore();
156
40
  platform = 'weixin';
157
41
  constructor(options) {
@@ -172,7 +56,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
172
56
  return (0, config_js_1.collectWeixinWorkspaceBindings)(config);
173
57
  }
174
58
  buildStatusObject(state, resolved) {
175
- this.options.store.expirePendingPairings();
176
59
  const platformKey = state.platformKey || (0, channel_keys_js_1.channelPlatformKey)('weixin', resolved.instanceId);
177
60
  const pairings = this.options.store.listPendingPairings(state.workspaceId)
178
61
  .filter((row) => row.platform === platformKey && row.expires_at >= new Date().toISOString());
@@ -319,29 +202,26 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
319
202
  && event.type !== 'status') {
320
203
  return;
321
204
  }
322
- const previous = this.outboundEventChains.get(sessionKey) || Promise.resolve();
323
- const current = previous
324
- .catch(() => undefined)
325
- .then(async () => {
205
+ const current = this.scheduleOutboundChain(sessionKey, async () => {
326
206
  const binding = this.options.store.getPlatformThreadBinding(route.workspaceId, route.chatId, route.platformUserId, routePlatformKey);
327
207
  if (!binding)
328
208
  return;
329
209
  const bridgeThreadId = route.threadId || binding.thread_id;
330
210
  if (this.mutedThreadBridgeCounts.has(bridgeThreadId))
331
211
  return;
332
- const turn = this.getOrCreateTurnState(sessionKey);
212
+ const turn = (0, runtime_state_js_1.getOrCreateWeixinTurnState)(this.outboundTurns, sessionKey);
333
213
  if (event.replyCtx) {
334
214
  // WeChat doesn't support reply context; ignore
335
215
  }
336
- this.consumeBridgeEvent(turn, event);
216
+ (0, runtime_state_js_1.consumeWeixinBridgeEvent)(turn, event);
337
217
  if (event.type !== 'reply' && event.type !== 'buttons' && event.type !== 'status')
338
218
  return;
339
- const rendered = this.renderTurnText(turn);
219
+ const rendered = (0, runtime_state_js_1.renderWeixinTurnText)(turn);
340
220
  if (!rendered)
341
221
  return;
342
222
  if (rendered === turn.lastSentText)
343
223
  return;
344
- const terminalMessage = this.isTerminalBridgeMessage(event, rendered);
224
+ const terminalMessage = (0, runtime_state_js_1.isTerminalWeixinBridgeMessage)(event, rendered);
345
225
  if (binding.last_platform_message_id && !terminalMessage && turn.sentCount >= WEIXIN_PROGRESS_SEND_BUDGET) {
346
226
  turn.foldedProgressCount += 1;
347
227
  this.options.log?.(`localcore-weixin folded progress for sessionKey=${sessionKey}: sent=${turn.sentCount} folded=${turn.foldedProgressCount}`);
@@ -364,19 +244,13 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
364
244
  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
245
  }
366
246
  catch (error) {
367
- this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${formatError(error)}`);
368
- }
369
- })
370
- .finally(() => {
371
- if (this.outboundEventChains.get(sessionKey) === current) {
372
- this.outboundEventChains.delete(sessionKey);
247
+ this.options.log?.(`localcore-weixin send failed for sessionKey=${sessionKey}: ${(0, local_core_errors_js_1.formatSafeError)(error)}`);
373
248
  }
374
249
  });
375
- this.outboundEventChains.set(sessionKey, current);
376
250
  await current;
377
251
  }
378
252
  registerScheduledThreadBridge(input) {
379
- const instanceId = input.route.instanceId || getWeixinInstanceId(input.platform) || 'default';
253
+ const instanceId = input.route.instanceId || (0, channel_keys_js_1.extractChannelInstanceId)(input.platform, 'weixin') || 'default';
380
254
  const platformKey = (0, channel_keys_js_1.channelPlatformKey)('weixin', instanceId);
381
255
  const route = {
382
256
  workspaceId: input.workspaceId,
@@ -389,7 +263,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
389
263
  const previousRoute = this.threadRouting.get(input.sessionKey);
390
264
  this.threadRouting.set(input.sessionKey, route);
391
265
  if (!this.outboundTurns.has(input.sessionKey)) {
392
- this.createTurnState(input.sessionKey);
266
+ this.outboundTurns.set(input.sessionKey, (0, runtime_state_js_1.createWeixinTurnState)(input.sessionKey));
393
267
  }
394
268
  return () => {
395
269
  if (previousRoute) {
@@ -492,52 +366,32 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
492
366
  messageId: msg.messageId,
493
367
  },
494
368
  });
495
- this.options.store.expirePendingPairings();
496
369
  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
- }
370
+ const authorization = (0, inbound_authorization_js_1.resolveInboundChannelAuthorization)({
371
+ store: this.options.store,
372
+ identity: {
373
+ workspaceId: msg.workspaceId,
374
+ platformKey,
375
+ platformUserId: msg.platformUserId,
376
+ chatId: msg.chatId,
377
+ displayName: msg.displayName,
378
+ },
379
+ autoApprove: binding.allowFrom === '*',
380
+ authorizedUserIdPrefix: 'wx-user',
381
+ generatePairingCode: () => String((0, node_crypto_2.randomInt)(100000, 1000000)),
382
+ onStateChanged: () => this.notifyRuntimeStateChanged(),
383
+ });
384
+ if (authorization.status === 'pending') {
535
385
  const state = this.runtime.get((0, channel_keys_js_1.runtimeKey)(msg.workspaceId, instanceId));
536
386
  if (state?.connected) {
537
- await this.sendTextMessage(state, msg.chatId, `**已收到消息**\n\n当前账号还未授权接入这个工作区。\n请在桌面端完成审批后再次发送消息。\n\n配对码:\`${pairingCode}\``, msg.contextToken);
387
+ await this.sendTextMessage(state, msg.chatId, `**已收到消息**\n\n当前账号还未授权接入这个工作区。\n请在桌面端完成审批后再次发送消息。\n\n配对码:\`${authorization.pairingCode}\``, msg.contextToken);
538
388
  }
539
389
  return;
540
390
  }
391
+ if (authorization.autoApproved) {
392
+ this.options.log?.(`localcore-weixin auto-approved user for ${msg.workspaceId}: ${msg.platformUserId}`);
393
+ }
394
+ const authorized = authorization.authorized;
541
395
  const router = this.options.getWorkspaceRouter();
542
396
  let { threadId } = await (0, thread_routing_js_1.resolveChannelThreadRoute)({
543
397
  store: this.options.store,
@@ -551,7 +405,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
551
405
  authorized,
552
406
  });
553
407
  const normalizedText = String(msg.text || '').trim().toLowerCase();
554
- const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(msg.workspaceId, msg.chatId, msg.platformUserId, msg.platformKey) : '';
408
+ const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(msg.workspaceId, msg.chatId, msg.platformUserId, msg.platformKey || 'weixin') : '';
555
409
  if (permissionThreadId && permissionThreadId !== threadId) {
556
410
  threadId = permissionThreadId;
557
411
  }
@@ -565,7 +419,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
565
419
  threadId,
566
420
  });
567
421
  // Handle slash commands
568
- const slashCommand = this.parseSlashCommand(msg.text);
422
+ const slashCommand = (0, local_core_slash_commands_js_1.parseSlashCommand)(msg.text);
569
423
  const sessionCommand = await this.executeSessionCommand({
570
424
  workspaceId: msg.workspaceId,
571
425
  currentThreadId: threadId,
@@ -588,19 +442,9 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
588
442
  return;
589
443
  }
590
444
  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));
445
+ await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(msg.text, msg.contentParts));
595
446
  return;
596
447
  }
597
- async resolveDefaultAgentType(workspaceId, threadId) {
598
- const router = this.options.getWorkspaceRouter();
599
- if (typeof router.getWorkspaceDefaultAgentType === 'function') {
600
- return router.getWorkspaceDefaultAgentType(workspaceId);
601
- }
602
- return this.options.store.getThreadRow(threadId)?.agent_type || 'codex';
603
- }
604
448
  // ==================== Private: Bindings ====================
605
449
  // ==================== Private: Workspace Lifecycle ====================
606
450
  async startWorkspace(binding) {
@@ -638,7 +482,18 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
638
482
  status.connectedAt = new Date().toISOString();
639
483
  this.clearRuntimeError(status);
640
484
  // Start long-poll loop in background
641
- this.runMonitorLoop(binding, abortController.signal).catch((err) => {
485
+ (0, inbound_poller_js_1.runWeixinInboundPoller)({
486
+ binding,
487
+ signal: abortController.signal,
488
+ getRuntimeState: () => this.runtime.get((0, channel_keys_js_1.runtimeKey)(binding.workspaceId, binding.instanceId)),
489
+ getAuthorizedUser: (workspaceId, platformUserId, platformKey) => this.options.store.getAuthorizedUser(workspaceId, platformUserId, platformKey),
490
+ clearRuntimeError: (runtimeState) => this.clearRuntimeError(runtimeState),
491
+ setRuntimeError: (runtimeState, errorInfo) => this.setRuntimeError(runtimeState, errorInfo),
492
+ notifyRuntimeStateChanged: () => this.notifyRuntimeStateChanged(),
493
+ downloadMediaItem: (item, messageId, index, uploadsDir, workspaceBinding) => this.downloadMediaItem(item, messageId, index, uploadsDir, workspaceBinding),
494
+ handleInboundMessage: (message) => this.handleInboundMessage(message),
495
+ log: this.options.log,
496
+ }).catch((err) => {
642
497
  if (!abortController.signal.aborted) {
643
498
  status.status = 'error';
644
499
  status.connected = false;
@@ -665,136 +520,13 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
665
520
  return 'expired';
666
521
  return 'wait';
667
522
  }
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
523
  // ==================== Private: HTTP API ====================
792
524
  async sendTextMessage(state, toUserId, text, contextToken, options = {}) {
793
525
  const binding = await this.getBinding(state.workspaceId);
794
- const stripped = stripHtml(text);
526
+ const stripped = (0, text_utils_js_1.stripWeixinHtml)(text);
795
527
  const chunks = contextToken
796
- ? [truncateTextByUtf8Bytes(stripped, WEIXIN_CONTEXT_REPLY_MAX_BYTES)].filter(Boolean)
797
- : splitTextByUtf8Bytes(stripped, WEIXIN_TEXT_MESSAGE_MAX_BYTES);
528
+ ? [(0, text_utils_js_1.truncateTextByUtf8Bytes)(stripped, WEIXIN_CONTEXT_REPLY_MAX_BYTES)].filter(Boolean)
529
+ : (0, text_utils_js_1.splitTextByUtf8Bytes)(stripped, WEIXIN_TEXT_MESSAGE_MAX_BYTES);
798
530
  for (const [index, chunk] of chunks.entries()) {
799
531
  const finalChunk = options.final && index === chunks.length - 1;
800
532
  const resp = await (0, transport_js_1.sendWeixinTextMessageChunk)(binding, toUserId, chunk, contextToken, {
@@ -802,7 +534,7 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
802
534
  final: finalChunk,
803
535
  });
804
536
  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}`);
537
+ 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
538
  }
807
539
  }
808
540
  this.options.log?.(`localcore-weixin sent message to ${toUserId} for workspace ${state.workspaceId}${chunks.length > 1 ? ` chunks=${chunks.length}` : ''}`);
@@ -961,149 +693,6 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
961
693
  return 'image/gif';
962
694
  return 'application/octet-stream';
963
695
  }
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
696
  isDuplicateInboundMessage(input) {
1108
697
  const messageKey = input.contextToken || input.messageId;
1109
698
  if (!messageKey)
@@ -1119,51 +708,5 @@ class LocalCoreWeixinGateway extends base_channel_gateway_js_1.BaseChannelGatewa
1119
708
  this.processedInboundMessages.set(key, now + PROCESSED_MESSAGE_TTL_MS);
1120
709
  return false;
1121
710
  }
1122
- findAwaitingPermissionThreadId(workspaceId, chatId, platformUserId, platformKey = 'weixin') {
1123
- for (const [sessionKey, route] of this.threadRouting.entries()) {
1124
- if (route.workspaceId !== workspaceId || route.platformKey !== platformKey || route.chatId !== chatId || route.platformUserId !== platformUserId)
1125
- continue;
1126
- const turn = this.outboundTurns.get(sessionKey);
1127
- if (turn?.awaitingPermission && route.threadId)
1128
- return route.threadId;
1129
- }
1130
- return '';
1131
- }
1132
- parseSlashCommand(text) {
1133
- const normalized = String(text || '').trim();
1134
- if (!normalized.startsWith('/'))
1135
- return null;
1136
- const [name = '', ...args] = normalized.slice(1).split(/\s+/);
1137
- if (!name)
1138
- return null;
1139
- return { name: name.trim().toLowerCase(), args };
1140
- }
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
711
  }
1165
712
  exports.LocalCoreWeixinGateway = LocalCoreWeixinGateway;
1166
- function getWeixinInstanceId(platform) {
1167
- const normalized = String(platform || '').trim();
1168
- return normalized.startsWith('weixin:') ? normalized.slice('weixin:'.length).trim() : '';
1169
- }