@kafca/agentdock 0.1.55 → 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 (185) hide show
  1. package/README.md +14 -0
  2. package/dist/renderer/assets/{Badge-Bg_nNvBL.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-C60g3RMj.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-CC5C7JYe.js → KnowledgeDetail-CbUb2tG7.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-3rlvxgWf.js → KnowledgeHome-BWV1gz4f.js} +3 -3
  12. package/dist/renderer/assets/Logs-DqnanQTc.js +6 -0
  13. package/dist/renderer/assets/{Modal-BQUW9LSf.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-CfRkos3z.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-D1DbXrLA.js → arrow-left-C8HfBt2K.js} +1 -1
  20. package/dist/renderer/assets/{book-open-BxC1z1C1.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-X44UaxwR.js → pencil-CB1SWZ9A.js} +1 -1
  28. package/dist/renderer/assets/{play-ujo-De38.js → play-BvsoXUrM.js} +1 -1
  29. package/dist/renderer/assets/{plus-BHgVdG_A.js → plus-CokBDnaL.js} +1 -1
  30. package/dist/renderer/assets/{save-Cz6giKrE.js → save-D-w4kATO.js} +1 -1
  31. package/dist/renderer/assets/{search-DKWvTqi5.js → search-Cnsn6i4Q.js} +1 -1
  32. package/dist/renderer/assets/{shield-check-V82O8AC1.js → shield-check-Cjja2Gh6.js} +1 -1
  33. package/dist/renderer/assets/threads-BCm6j4eI.js +1 -0
  34. package/dist/renderer/assets/{trash-2-_Fgwk8mc.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 +6 -9
  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 -456
  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-attachment-store.js +93 -0
  86. package/dist-electron/services/local-ai-core/src/channel/shared/inbound-authorization.js +54 -0
  87. package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +2 -2
  88. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-media.js +21 -0
  89. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +167 -0
  90. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +98 -483
  91. package/dist-electron/services/local-ai-core/src/channel/weixin/runtime-state.js +156 -0
  92. package/dist-electron/services/local-ai-core/src/channel/weixin/text-utils.js +100 -0
  93. package/dist-electron/services/local-ai-core/src/cli/lac.js +6 -6
  94. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +2 -2
  95. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +28 -70
  96. package/dist-electron/services/local-ai-core/src/kernel/local-core-errors.js +33 -5
  97. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +2 -2
  98. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +2 -2
  99. package/dist-electron/services/local-ai-core/src/router/workspace-bridge-event-stream.js +29 -0
  100. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +5 -5
  101. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +47 -60
  102. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +5 -5
  103. package/dist-electron/services/local-ai-core/src/runtime/config-migration.js +6 -6
  104. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +3 -3
  105. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +3 -1
  106. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +11 -2
  107. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +12 -6
  108. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +10 -2
  109. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +18 -6
  110. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +7 -2
  111. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +28 -3
  112. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +10 -2
  113. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +18 -5
  114. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +14 -2
  115. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +18 -15
  116. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +13 -2
  117. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +35 -8
  118. package/dist-electron/services/local-ai-core/src/runtime/request-validation.js +79 -0
  119. package/dist-electron/services/local-ai-core/src/runtime/runtime-detection-service.js +9 -9
  120. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +10 -1
  121. package/dist-electron/services/local-ai-core/src/runtime/server.js +2 -1
  122. package/dist-electron/services/local-ai-core/src/runtime/workspace-project-registry.js +76 -0
  123. package/dist-electron/services/local-ai-core/src/sandbox/sandbox-config.js +8 -8
  124. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +75 -0
  125. package/dist-electron/shared/desktop.js +1 -64
  126. package/dist-electron/src/components/chat/chat-controller-state.js +60 -0
  127. package/dist-electron/src/components/chat/chat-event-gate.js +146 -0
  128. package/dist-electron/src/components/chat/markdown-code-block.js +8 -0
  129. package/dist-electron/src/pages/Desktop/workspace-model.js +212 -0
  130. package/dist-electron/src/pages/Threads/thread-chat-model.js +50 -51
  131. package/dist-electron/tests/contracts/agent-message-policy.test.js +21 -0
  132. package/dist-electron/tests/contracts/architecture-docs.test.js +56 -33
  133. package/dist-electron/tests/contracts/chat-event-gate.test.js +114 -0
  134. package/dist-electron/tests/contracts/chat-markdown.test.js +16 -0
  135. package/dist-electron/tests/contracts/thread-task-state.test.js +32 -0
  136. package/dist-electron/tests/contracts/workspace-identity.test.js +23 -0
  137. package/dist-electron/tests/electron/core-client.test.js +284 -0
  138. package/dist-electron/tests/electron/plugin-kernel.test.js +54 -0
  139. package/dist-electron/tests/electron/renderer-packaging.test.js +9 -0
  140. package/dist-electron/tests/electron/workspace-task-store.test.js +31 -0
  141. package/dist-electron/tests/integration/channel-inbound-attachment-store.test.js +117 -0
  142. package/dist-electron/tests/integration/channel-inbound-authorization.test.js +80 -0
  143. package/dist-electron/tests/integration/lark-gateway-utils.test.js +13 -0
  144. package/dist-electron/tests/integration/lark-gateway.test.js +58 -4
  145. package/dist-electron/tests/integration/local-core-errors.test.js +41 -0
  146. package/dist-electron/tests/integration/weixin-gateway.test.js +36 -0
  147. package/dist-electron/tests/integration/weixin-runtime-state.test.js +32 -0
  148. package/dist-electron/tests/integration/weixin-text-utils.test.js +15 -0
  149. package/package.json +9 -4
  150. package/dist/renderer/assets/Chat-BJveQQKu.js +0 -2
  151. package/dist/renderer/assets/ChatMarkdown-Bqn2HJ6f.js +0 -45
  152. package/dist/renderer/assets/Config-CMtZDRAE.js +0 -21
  153. package/dist/renderer/assets/CronList-C-ILB_Ae.js +0 -1
  154. package/dist/renderer/assets/Dashboard-CsKBSQIe.js +0 -26
  155. package/dist/renderer/assets/Logs-CktemGN0.js +0 -1
  156. package/dist/renderer/assets/MonitorList-B0hxjuOZ.js +0 -1
  157. package/dist/renderer/assets/Page-DL_Nv2i5.js +0 -1
  158. package/dist/renderer/assets/ProjectDetail-Djr9-MyT.js +0 -11
  159. package/dist/renderer/assets/ProjectList-BKl4eW7q.js +0 -1
  160. package/dist/renderer/assets/SessionChat-Dxv8D5DW.js +0 -1
  161. package/dist/renderer/assets/SessionList-BJ2GjXvR.js +0 -1
  162. package/dist/renderer/assets/ThreadChat-CAsIl9qf.js +0 -28
  163. package/dist/renderer/assets/Workspace-CaUhiGBX.js +0 -19
  164. package/dist/renderer/assets/bot-Fw3IzhJA.js +0 -6
  165. package/dist/renderer/assets/check-5zCTgp3A.js +0 -6
  166. package/dist/renderer/assets/chevron-down-N3PxTNxH.js +0 -6
  167. package/dist/renderer/assets/circle-C_chUflo.js +0 -6
  168. package/dist/renderer/assets/desktop-DkQTZNhe.js +0 -1
  169. package/dist/renderer/assets/desktop-JQkhNOF4.js +0 -5
  170. package/dist/renderer/assets/funnel-B8ZAv6I7.js +0 -6
  171. package/dist/renderer/assets/heart-M9A3E4Ed.js +0 -6
  172. package/dist/renderer/assets/index-Bwv855ID.js +0 -41
  173. package/dist/renderer/assets/index-CjCuR6DI.css +0 -11
  174. package/dist/renderer/assets/index-DJ8w4e0l.js +0 -182
  175. package/dist/renderer/assets/projects-DB1FLZ3A.js +0 -1
  176. package/dist/renderer/assets/server-BsuHcYl4.js +0 -11
  177. package/dist/renderer/assets/session-utils-DnAWL3eo.js +0 -6
  178. package/dist/renderer/assets/sessions-DptxO_BE.js +0 -1
  179. package/dist/renderer/assets/user-DQKTaUcR.js +0 -6
  180. package/dist/renderer/assets/wifi-off-vjH-MD2w.js +0 -11
  181. package/dist-electron/src/api/client.js +0 -73
  182. package/dist-electron/src/api/sessions.js +0 -21
  183. package/dist-electron/src/lib/session-utils.js +0 -51
  184. package/dist-electron/src/pages/Projects/project-provider-config.js +0 -75
  185. package/dist-electron/tests/electron/project-provider-config.test.js +0 -71
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LarkOutboundTransport = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const file_utils_js_1 = require("../shared/file-utils.js");
7
+ const cards_js_1 = require("./cards.js");
8
+ const messages_js_1 = require("./rendering/messages.js");
9
+ const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
10
+ class LarkOutboundTransport {
11
+ log;
12
+ constructor(log) {
13
+ this.log = log;
14
+ }
15
+ async sendFilePart(state, channelId, part) {
16
+ const file = await (0, file_utils_js_1.prepareChannelFile)({
17
+ path: part.path,
18
+ fileName: part.fileName,
19
+ workspacePath: typeof part.metadata?.workspacePath === 'string' ? part.metadata.workspacePath : undefined,
20
+ maxBytes: LARK_MAX_UPLOAD_FILE_SIZE,
21
+ platformLabel: 'Lark',
22
+ });
23
+ const upload = await state.client.im.file.create({
24
+ data: {
25
+ file_type: resolveLarkUploadFileType(file.fileName),
26
+ file_name: file.fileName,
27
+ file: (0, node_fs_1.createReadStream)(file.path),
28
+ },
29
+ });
30
+ const fileKey = String(upload?.file_key || upload?.data?.file_key || '').trim();
31
+ if (!fileKey) {
32
+ throw new Error('Lark file upload did not return a file key');
33
+ }
34
+ const response = await state.client.im.message.create({
35
+ params: {
36
+ receive_id_type: resolveReceiveIdType(channelId),
37
+ },
38
+ data: {
39
+ receive_id: channelId,
40
+ msg_type: 'file',
41
+ content: JSON.stringify({ file_key: fileKey }),
42
+ },
43
+ });
44
+ const messageId = String(response?.data?.message_id || '').trim();
45
+ if (!messageId) {
46
+ throw new Error('Lark file message did not return a message id');
47
+ }
48
+ this.log?.(`localcore-lark sent file ${file.fileName} (${file.fileSize} bytes) to ${channelId}`);
49
+ return { messageId, fileKey, file };
50
+ }
51
+ async sendTextAsCard(state, chatId, text, buttonRows = [], sessionKey, threadId) {
52
+ const startedAt = Date.now();
53
+ const response = await state.client.im.message.create({
54
+ params: { receive_id_type: resolveReceiveIdType(chatId) },
55
+ data: {
56
+ receive_id: chatId,
57
+ msg_type: 'interactive',
58
+ content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)),
59
+ },
60
+ });
61
+ this.log?.(`localcore-lark card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
62
+ return String(response?.data?.message_id || '').trim();
63
+ }
64
+ async sendSessionCommandCard(state, chatId, text, actionRows, sessionKey, threadId) {
65
+ const startedAt = Date.now();
66
+ const response = await state.client.im.message.create({
67
+ params: { receive_id_type: resolveReceiveIdType(chatId) },
68
+ data: {
69
+ receive_id: chatId,
70
+ msg_type: 'interactive',
71
+ content: JSON.stringify((0, cards_js_1.buildSessionCommandCard)(text, actionRows, sessionKey, threadId)),
72
+ },
73
+ });
74
+ this.log?.(`localcore-lark session card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
75
+ return String(response?.data?.message_id || '').trim();
76
+ }
77
+ async sendTextAsMessage(state, chatId, text) {
78
+ const startedAt = Date.now();
79
+ const rendered = (0, messages_js_1.renderLarkTextMessage)(text);
80
+ const response = await state.client.im.message.create({
81
+ params: { receive_id_type: resolveReceiveIdType(chatId) },
82
+ data: {
83
+ receive_id: chatId,
84
+ msg_type: rendered.msgType,
85
+ content: JSON.stringify(rendered.content),
86
+ },
87
+ });
88
+ this.log?.(`localcore-lark ${rendered.renderKind} create took ${Date.now() - startedAt}ms msgType=${rendered.msgType} reason=${rendered.reason} tableCount=${rendered.tableCount} textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
89
+ return {
90
+ messageId: String(response?.data?.message_id || '').trim(),
91
+ renderKind: rendered.renderKind,
92
+ msgType: rendered.msgType,
93
+ };
94
+ }
95
+ async patchTextCard(state, messageId, text, buttonRows = [], sessionKey, threadId) {
96
+ const startedAt = Date.now();
97
+ await state.client.im.message.patch({
98
+ path: { message_id: messageId },
99
+ data: { content: JSON.stringify((0, cards_js_1.buildInteractiveCard)(text, buttonRows, sessionKey, threadId)) },
100
+ });
101
+ this.log?.(`localcore-lark card patch took ${Date.now() - startedAt}ms message=${messageId} textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
102
+ }
103
+ }
104
+ exports.LarkOutboundTransport = LarkOutboundTransport;
105
+ function resolveReceiveIdType(receiveId) {
106
+ return receiveId.startsWith('oc_') ? 'chat_id' : receiveId.startsWith('ou_') ? 'open_id' : 'user_id';
107
+ }
108
+ function resolveLarkUploadFileType(fileName) {
109
+ switch ((0, node_path_1.extname)(fileName).toLowerCase()) {
110
+ case '.opus': return 'opus';
111
+ case '.mp4':
112
+ case '.mov':
113
+ case '.m4v': return 'mp4';
114
+ case '.pdf': return 'pdf';
115
+ case '.doc':
116
+ case '.docx': return 'doc';
117
+ case '.xls':
118
+ case '.xlsx':
119
+ case '.csv': return 'xls';
120
+ case '.ppt':
121
+ case '.pptx': return 'ppt';
122
+ default: return 'stream';
123
+ }
124
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileSystemInboundAttachmentStore = void 0;
4
+ exports.sanitizeInboundFilePart = sanitizeInboundFilePart;
5
+ exports.resolveInboundAttachmentUri = resolveInboundAttachmentUri;
6
+ const node_crypto_1 = require("node:crypto");
7
+ const node_fs_1 = require("node:fs");
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = require("node:path");
10
+ const node_stream_1 = require("node:stream");
11
+ const promises_2 = require("node:stream/promises");
12
+ const node_url_1 = require("node:url");
13
+ class FileSystemInboundAttachmentStore {
14
+ async save(input) {
15
+ const storedFileName = sanitizeInboundFilePart(input.storedFileName, 'file');
16
+ const temporaryPath = (0, node_path_1.join)(input.directory, `.${storedFileName}.${(0, node_crypto_1.randomUUID)()}.part`);
17
+ await (0, promises_1.mkdir)(input.directory, { recursive: true });
18
+ const opened = await input.source.open();
19
+ let size = 0;
20
+ let prefix = Buffer.alloc(0);
21
+ const sizeLimiter = new node_stream_1.Transform({
22
+ transform(chunk, _encoding, callback) {
23
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
24
+ if (prefix.length < 16) {
25
+ prefix = Buffer.concat([prefix, buffer.subarray(0, 16 - prefix.length)]);
26
+ }
27
+ size += buffer.length;
28
+ if (input.maxBytes && size > input.maxBytes) {
29
+ callback(new Error(`Inbound attachment exceeds ${input.maxBytes} bytes`));
30
+ return;
31
+ }
32
+ callback(null, buffer);
33
+ },
34
+ });
35
+ let filePath = '';
36
+ try {
37
+ await (0, promises_2.pipeline)(opened.stream, sizeLimiter, (0, node_fs_1.createWriteStream)(temporaryPath, { flags: 'wx' }));
38
+ if (size === 0) {
39
+ throw new Error('Inbound attachment is empty');
40
+ }
41
+ const finalizedName = input.finalizeStoredFileName
42
+ ? input.finalizeStoredFileName({ storedFileName, prefix })
43
+ : storedFileName;
44
+ filePath = (0, node_path_1.join)(input.directory, sanitizeInboundFilePart(finalizedName, storedFileName));
45
+ await (0, promises_1.rename)(temporaryPath, filePath);
46
+ const includeBase64 = typeof input.includeBase64 === 'function'
47
+ ? input.includeBase64({ prefix })
48
+ : input.includeBase64;
49
+ const data = includeBase64
50
+ ? (await (0, promises_1.readFile)(filePath)).toString('base64')
51
+ : undefined;
52
+ const fileStat = await (0, promises_1.stat)(filePath);
53
+ return {
54
+ path: filePath,
55
+ fileName: input.displayFileName,
56
+ mimeType: opened.mimeType,
57
+ size: fileStat.size,
58
+ data,
59
+ prefix,
60
+ };
61
+ }
62
+ catch (error) {
63
+ await (0, promises_1.rm)(temporaryPath, { force: true }).catch(() => undefined);
64
+ if (filePath) {
65
+ await (0, promises_1.rm)(filePath, { force: true }).catch(() => undefined);
66
+ }
67
+ throw error;
68
+ }
69
+ }
70
+ }
71
+ exports.FileSystemInboundAttachmentStore = FileSystemInboundAttachmentStore;
72
+ function sanitizeInboundFilePart(value, fallback) {
73
+ return String(value || fallback)
74
+ .replace(/[^a-zA-Z0-9._-]/g, '_')
75
+ .slice(0, 240) || fallback;
76
+ }
77
+ function resolveInboundAttachmentUri(input) {
78
+ if (!input.sandboxEnabled) {
79
+ return (0, node_url_1.pathToFileURL)(input.filePath).href;
80
+ }
81
+ const workspacePath = String(input.workspacePath || '').trim();
82
+ if (!workspacePath) {
83
+ return undefined;
84
+ }
85
+ const relativePath = (0, node_path_1.relative)((0, node_path_1.resolve)(workspacePath), (0, node_path_1.resolve)(input.filePath));
86
+ if (!relativePath || relativePath.startsWith('..') || (0, node_path_1.isAbsolute)(relativePath)) {
87
+ return relativePath === ''
88
+ ? new URL(node_path_1.posix.resolve(input.sandboxWorkspacePath || '/workspace'), 'file:///').href
89
+ : undefined;
90
+ }
91
+ const sandboxRelativePath = relativePath.split(node_path_1.sep).join('/');
92
+ return new URL(node_path_1.posix.resolve(input.sandboxWorkspacePath || '/workspace', sandboxRelativePath), 'file:///').href;
93
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveInboundChannelAuthorization = resolveInboundChannelAuthorization;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const DEFAULT_PAIRING_EXPIRY_MS = 10 * 60 * 1000;
6
+ function resolveInboundChannelAuthorization(input) {
7
+ const { store, identity } = input;
8
+ store.expirePendingPairings();
9
+ let authorized = store.getAuthorizedUser(identity.workspaceId, identity.platformUserId, identity.platformKey);
10
+ let autoApproved = false;
11
+ if (!authorized && input.autoApprove) {
12
+ const authorizedAt = (input.now?.() || new Date()).toISOString();
13
+ store.createAuthorizedUser({
14
+ id: `${input.authorizedUserIdPrefix}-${(0, node_crypto_1.randomUUID)()}`,
15
+ workspace_id: identity.workspaceId,
16
+ platform: identity.platformKey,
17
+ platform_user_id: identity.platformUserId,
18
+ chat_id: identity.chatId,
19
+ display_name: identity.displayName,
20
+ thread_id: null,
21
+ authorized_at: authorizedAt,
22
+ });
23
+ authorized = store.getAuthorizedUser(identity.workspaceId, identity.platformUserId, identity.platformKey);
24
+ autoApproved = Boolean(authorized);
25
+ if (autoApproved) {
26
+ input.onStateChanged?.();
27
+ }
28
+ }
29
+ if (authorized) {
30
+ return { status: 'authorized', authorized, autoApproved };
31
+ }
32
+ const existingPending = store.listPendingPairings(identity.workspaceId).find((item) => item.platform === identity.platformKey &&
33
+ item.platform_user_id === identity.platformUserId &&
34
+ item.chat_id === identity.chatId &&
35
+ item.status === 'pending');
36
+ if (existingPending) {
37
+ return { status: 'pending', pairingCode: existingPending.code };
38
+ }
39
+ const now = input.now?.() || new Date();
40
+ const pairingCode = input.generatePairingCode();
41
+ store.createPairingRequest({
42
+ code: pairingCode,
43
+ workspace_id: identity.workspaceId,
44
+ platform: identity.platformKey,
45
+ platform_user_id: identity.platformUserId,
46
+ chat_id: identity.chatId,
47
+ display_name: identity.displayName,
48
+ requested_at: now.toISOString(),
49
+ expires_at: new Date(now.getTime() + (input.pairingExpiryMs || DEFAULT_PAIRING_EXPIRY_MS)).toISOString(),
50
+ status: 'pending',
51
+ });
52
+ input.onStateChanged?.();
53
+ return { status: 'pending', pairingCode };
54
+ }
@@ -15,7 +15,7 @@ exports.saveWeixinBuf = saveWeixinBuf;
15
15
  exports.collectWeixinWorkspaceBindings = collectWeixinWorkspaceBindings;
16
16
  const node_fs_1 = __importDefault(require("node:fs"));
17
17
  const node_path_1 = __importDefault(require("node:path"));
18
- const desktop_js_1 = require("../../../../../shared/desktop.js");
18
+ const superai_contracts_1 = require("../../../../../packages/contracts/src/index.js");
19
19
  const channel_keys_js_1 = require("../shared/channel-keys.js");
20
20
  exports.DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
21
21
  exports.DEFAULT_CDN_BASE_URL = 'https://novac2c.cdn.weixin.qq.com/c2c';
@@ -75,7 +75,7 @@ function collectWeixinWorkspaceBindings(config) {
75
75
  const platforms = Array.isArray(project.platforms) ? project.platforms : [];
76
76
  return platforms
77
77
  .map((platform) => ({
78
- platformType: (0, desktop_js_1.normalizeDesktopPlatformType)(platform?.type),
78
+ platformType: (0, superai_contracts_1.normalizeDesktopPlatformType)(platform?.type),
79
79
  options: platform?.options && typeof platform.options === 'object'
80
80
  ? platform.options
81
81
  : {},
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWeixinAttachmentContentPart = createWeixinAttachmentContentPart;
4
+ function createWeixinAttachmentContentPart(att) {
5
+ if (att.kind === 'image') {
6
+ if (!att.data)
7
+ return null;
8
+ return {
9
+ type: 'image',
10
+ data: att.data,
11
+ ...(att.uri ? { uri: att.uri } : {}),
12
+ mimeType: att.mimeType,
13
+ fileName: att.name,
14
+ };
15
+ }
16
+ return {
17
+ type: 'file',
18
+ path: att.path,
19
+ fileName: att.name,
20
+ };
21
+ }
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runWeixinInboundPoller = runWeixinInboundPoller;
4
+ const node_path_1 = require("node:path");
5
+ const local_core_errors_js_1 = require("../../kernel/local-core-errors.js");
6
+ const config_js_1 = require("./config.js");
7
+ const transport_js_1 = require("./transport.js");
8
+ const text_utils_js_1 = require("./text-utils.js");
9
+ const inbound_media_js_1 = require("./inbound-media.js");
10
+ const RETRY_DELAY_MS = 2_000;
11
+ const MAX_CONSECUTIVE_FAILURES = 3;
12
+ const ERROR_LOG_WINDOW_MS = 5 * 60 * 1000;
13
+ function computeRetryDelay(failures) {
14
+ if (failures <= 1)
15
+ return RETRY_DELAY_MS;
16
+ if (failures === 2)
17
+ return 5_000;
18
+ if (failures === 3)
19
+ return 15_000;
20
+ if (failures === 4)
21
+ return 30_000;
22
+ return 60_000;
23
+ }
24
+ async function runWeixinInboundPoller(input) {
25
+ const { binding, signal } = input;
26
+ const errorLogWindows = new Map();
27
+ let buf = (0, config_js_1.loadWeixinBuf)(binding);
28
+ let consecutiveFailures = 0;
29
+ const logPollError = (errorKey, message) => {
30
+ const key = `${binding.workspaceId}:${binding.instanceId}`;
31
+ const now = Date.now();
32
+ const current = errorLogWindows.get(key);
33
+ if (!current || current.errorKey !== errorKey || now - current.at >= ERROR_LOG_WINDOW_MS) {
34
+ input.log?.(current?.count && current.count > 1 ? `${message} (repeated ${current.count} times)` : message);
35
+ errorLogWindows.set(key, { at: now, count: 1, errorKey });
36
+ return;
37
+ }
38
+ current.count += 1;
39
+ errorLogWindows.set(key, current);
40
+ };
41
+ while (!signal.aborted) {
42
+ try {
43
+ const resp = await (0, transport_js_1.getWeixinUpdates)(binding, buf, signal);
44
+ const isApiError = (resp.ret !== undefined && resp.ret !== 0) || (resp.errcode !== undefined && resp.errcode !== 0);
45
+ if (isApiError) {
46
+ consecutiveFailures += 1;
47
+ const state = input.getRuntimeState();
48
+ const retryDelayMs = computeRetryDelay(consecutiveFailures);
49
+ if (resp.errcode === -14 || resp.ret === -14) {
50
+ if (state) {
51
+ state.status = 'error';
52
+ state.connected = false;
53
+ state.consecutiveFailures = consecutiveFailures;
54
+ state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
55
+ input.setRuntimeError(state, (0, local_core_errors_js_1.toLocalCoreErrorInfo)(new local_core_errors_js_1.LocalCoreError('channel_session_expired', 'WeChat login expired.')));
56
+ input.notifyRuntimeStateChanged();
57
+ }
58
+ }
59
+ logPollError(`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})`);
60
+ if (state && resp.errcode !== -14 && resp.ret !== -14) {
61
+ state.consecutiveFailures = consecutiveFailures;
62
+ state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
63
+ }
64
+ await (0, text_utils_js_1.waitForWeixinRetry)(retryDelayMs, signal);
65
+ if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
66
+ consecutiveFailures = MAX_CONSECUTIVE_FAILURES;
67
+ }
68
+ continue;
69
+ }
70
+ consecutiveFailures = 0;
71
+ const state = input.getRuntimeState();
72
+ if (state) {
73
+ input.clearRuntimeError(state);
74
+ state.status = 'running';
75
+ state.connected = true;
76
+ input.notifyRuntimeStateChanged();
77
+ }
78
+ if (resp.get_updates_buf) {
79
+ buf = resp.get_updates_buf;
80
+ (0, config_js_1.saveWeixinBuf)(binding, buf);
81
+ }
82
+ for (const msg of resp.msgs ?? []) {
83
+ const items = msg.item_list ?? [];
84
+ const textItem = items.find((item) => item.type === transport_js_1.TEXT_ITEM_TYPE);
85
+ const voiceTextItems = items.filter((item) => item.type === transport_js_1.VOICE_ITEM_TYPE && item.voice_item?.text);
86
+ const mediaItems = items.filter((item) => item.type === transport_js_1.IMAGE_ITEM_TYPE || item.type === transport_js_1.FILE_ITEM_TYPE);
87
+ if (!textItem && voiceTextItems.length === 0 && mediaItems.length === 0)
88
+ continue;
89
+ const conversationId = msg.from_user_id ?? '';
90
+ const text = [textItem?.text_item?.text?.trim(), ...voiceTextItems.map((item) => item.voice_item?.text?.trim())]
91
+ .filter((part) => Boolean(part))
92
+ .join('\n\n');
93
+ const msgId = msg.msg_id ?? String(Date.now());
94
+ let attachmentText = '';
95
+ const attachmentParts = [];
96
+ if (mediaItems.length > 0) {
97
+ const uploadsDir = (0, node_path_1.join)(binding.stateDir, 'weixin-uploads');
98
+ const mayMaterializeAttachments = binding.allowFrom === '*' || Boolean(input.getAuthorizedUser(binding.workspaceId, conversationId, binding.platformKey));
99
+ if (!mayMaterializeAttachments) {
100
+ for (const item of mediaItems) {
101
+ const itemData = item.image_item ?? item.file_item ?? null;
102
+ const declaredName = String(itemData?.file_name ?? (item.type === transport_js_1.IMAGE_ITEM_TYPE ? 'image' : 'file'));
103
+ attachmentText += attachmentText ? '\n' : '';
104
+ attachmentText += item.type === transport_js_1.IMAGE_ITEM_TYPE ? '[Image]' : `[File: ${declaredName}]`;
105
+ }
106
+ }
107
+ else {
108
+ const downloads = await Promise.all(mediaItems.map(async (item, index) => {
109
+ try {
110
+ return await input.downloadMediaItem(item, msgId, index, uploadsDir, binding);
111
+ }
112
+ catch (error) {
113
+ input.log?.(`localcore-weixin attachment download failed (${conversationId}#${index}): ${(0, text_utils_js_1.formatWeixinError)(error)}`);
114
+ return null;
115
+ }
116
+ }));
117
+ for (const attachment of downloads) {
118
+ if (!attachment) {
119
+ continue;
120
+ }
121
+ attachmentText += attachmentText ? '\n' : '';
122
+ attachmentText += attachment.kind === 'image'
123
+ ? `[Image: ${attachment.path}]`
124
+ : `[File "${attachment.name}": ${attachment.path}]`;
125
+ const part = (0, inbound_media_js_1.createWeixinAttachmentContentPart)(attachment);
126
+ if (part)
127
+ attachmentParts.push(part);
128
+ }
129
+ }
130
+ }
131
+ const fullText = [text, attachmentText].filter(Boolean).join('\n\n');
132
+ if (!fullText)
133
+ continue;
134
+ await input.handleInboundMessage({
135
+ workspaceId: binding.workspaceId,
136
+ instanceId: binding.instanceId,
137
+ platformKey: binding.platformKey,
138
+ platformUserId: conversationId,
139
+ chatId: conversationId,
140
+ displayName: conversationId.slice(-6),
141
+ text: fullText,
142
+ messageId: msgId,
143
+ contextToken: msg.context_token,
144
+ contentParts: [
145
+ ...(text ? [{ type: 'text', text }] : []),
146
+ ...attachmentParts,
147
+ ],
148
+ });
149
+ }
150
+ }
151
+ catch (error) {
152
+ if (signal.aborted)
153
+ return;
154
+ consecutiveFailures += 1;
155
+ const retryDelayMs = computeRetryDelay(consecutiveFailures);
156
+ const state = input.getRuntimeState();
157
+ if (state) {
158
+ state.consecutiveFailures = consecutiveFailures;
159
+ state.nextRetryAt = new Date(Date.now() + retryDelayMs).toISOString();
160
+ input.setRuntimeError(state, (0, local_core_errors_js_1.toLocalCoreErrorInfo)(error));
161
+ input.notifyRuntimeStateChanged();
162
+ }
163
+ logPollError((0, text_utils_js_1.formatWeixinError)(error), `localcore-weixin getUpdates error for ${binding.workspaceId} (${consecutiveFailures}): ${(0, text_utils_js_1.formatWeixinError)(error)}`);
164
+ await (0, text_utils_js_1.waitForWeixinRetry)(retryDelayMs, signal);
165
+ }
166
+ }
167
+ }