@kafca/agentdock 0.1.42 → 0.1.43

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 (98) hide show
  1. package/README.md +4 -0
  2. package/dist/renderer/assets/{Badge-D-WU4kUV.js → Badge-CbG6yRSm.js} +1 -1
  3. package/dist/renderer/assets/{Chat-BGkC5tAe.js → Chat-BvNNWGGX.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-CfbC1jRd.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
  5. package/dist/renderer/assets/{Config-qQb4bX5D.js → Config-lQX2qVVV.js} +2 -2
  6. package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
  7. package/dist/renderer/assets/{Dashboard-xn6cUy_n.js → Dashboard-eh_RhGYb.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-BdKBBUpr.js → EmptyState-Bn2Qh14U.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-Duk8IQP3.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
  10. package/dist/renderer/assets/{KnowledgeHome-BfjX_4Sv.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
  11. package/dist/renderer/assets/{Logs-Bfq61QMn.js → Logs-Dp-NF6GN.js} +1 -1
  12. package/dist/renderer/assets/{Modal-B3vlBmBr.js → Modal-B6YPPBN6.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
  14. package/dist/renderer/assets/{Page-CPsLOP3z.js → Page-Bn7RjGOS.js} +1 -1
  15. package/dist/renderer/assets/{ProjectDetail-D-g46wyF.js → ProjectDetail-Cv_jIE61.js} +2 -2
  16. package/dist/renderer/assets/{ProjectList-BrQEKDQ8.js → ProjectList-BDk5_gqY.js} +1 -1
  17. package/dist/renderer/assets/{Select-C4CFMQmF.js → Select-xshfMIEQ.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
  19. package/dist/renderer/assets/{SessionList-DPWIUbOg.js → SessionList-BZyXT92L.js} +1 -1
  20. package/dist/renderer/assets/{ThreadChat-BjtU-j9q.js → ThreadChat-DUOIyXrS.js} +7 -7
  21. package/dist/renderer/assets/{Workspace-BcNmHuJx.js → Workspace-Dl80fNEC.js} +1 -1
  22. package/dist/renderer/assets/{arrow-left-DPzSmidS.js → arrow-left-C54ZI-AS.js} +1 -1
  23. package/dist/renderer/assets/{book-open-B0xhoRqZ.js → book-open-Dl7GO0zn.js} +1 -1
  24. package/dist/renderer/assets/{check-BTJTyd0C.js → check-CiqgtrOL.js} +1 -1
  25. package/dist/renderer/assets/{chevron-down-B6jJXlhi.js → chevron-down-DTL2OuVh.js} +1 -1
  26. package/dist/renderer/assets/{circle-qRhJR9qR.js → circle-DaVKfa3P.js} +1 -1
  27. package/dist/renderer/assets/desktop-C6q6wBae.js +5 -0
  28. package/dist/renderer/assets/desktop-jaAiayNB.js +1 -0
  29. package/dist/renderer/assets/en-D2SkCrhG.js +1 -0
  30. package/dist/renderer/assets/{funnel-CbYKGTn8.js → funnel-CrmnLMJI.js} +1 -1
  31. package/dist/renderer/assets/{heart-DjwWJfkz.js → heart-BMfQI7y_.js} +1 -1
  32. package/dist/renderer/assets/{index-BWmHJRhe.js → index-HPNb1zfx.js} +39 -34
  33. package/dist/renderer/assets/{index-CyZs_2NJ.js → index-nreiKY1f.js} +3 -3
  34. package/dist/renderer/assets/{pencil-1dfAivmj.js → pencil-wTQ4l465.js} +1 -1
  35. package/dist/renderer/assets/{play-CB3w1G6S.js → play-BK--MXmw.js} +1 -1
  36. package/dist/renderer/assets/{plug-Bvep5o3r.js → plug-BIx9fjip.js} +1 -1
  37. package/dist/renderer/assets/{plus-DJVg9m09.js → plus-Dn7JFWQ8.js} +1 -1
  38. package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
  39. package/dist/renderer/assets/{save-xjJn3qf2.js → save-CC3zOSWb.js} +1 -1
  40. package/dist/renderer/assets/{search-BK3UrQxM.js → search-CDTy9Czu.js} +1 -1
  41. package/dist/renderer/assets/{server-Dyd2eXJu.js → server-DtQk3t2a.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-eXC0020s.js → session-utils-4ep5D66T.js} +1 -1
  43. package/dist/renderer/assets/{sessions-WLYpkyUt.js → sessions-Dor1LteH.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-C0N6aWzF.js → shield-check-Cz2LpU6r.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-BGMTNJA6.js → trash-2-C2EmWFZV.js} +1 -1
  46. package/dist/renderer/assets/{user-BcGMLyhu.js → user-I8B-cs5A.js} +1 -1
  47. package/dist/renderer/assets/{wifi-off-FhcQx0HK.js → wifi-off-CPevTQJn.js} +1 -1
  48. package/dist/renderer/assets/zh-DIcdHycM.js +1 -0
  49. package/dist/renderer/index.html +1 -1
  50. package/dist-electron/packages/contracts/src/local-core.js +28 -0
  51. package/dist-electron/packages/core-sdk/src/index.js +32 -0
  52. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +51 -0
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1364
  54. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
  55. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
  56. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
  57. package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
  58. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
  59. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
  63. package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
  64. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
  65. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
  66. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
  67. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
  68. package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
  69. package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
  70. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
  71. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +101 -29
  72. package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
  73. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +51 -33
  74. package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
  75. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
  76. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
  77. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
  78. package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
  79. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
  80. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
  81. package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
  82. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
  83. package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
  84. package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
  85. package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +15 -15
  86. package/dist-electron/shared/desktop.js +21 -1
  87. package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
  88. package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
  89. package/dist-electron/tests/electron/lac-cli.test.js +146 -0
  90. package/dist-electron/tests/integration/local-core-refactor.test.js +194 -0
  91. package/package.json +1 -1
  92. package/dist/renderer/assets/CronList-CKhggzYk.js +0 -1
  93. package/dist/renderer/assets/SessionChat-06Jny5_G.js +0 -1
  94. package/dist/renderer/assets/desktop-DXmXjjUR.js +0 -1
  95. package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
  96. package/dist/renderer/assets/en-CKhCF6St.js +0 -1
  97. package/dist/renderer/assets/projects-xnW0fTtq.js +0 -1
  98. package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildInteractiveCard = buildInteractiveCard;
4
4
  exports.renderPermissionCard = renderPermissionCard;
5
5
  exports.renderPendingPairingCard = renderPendingPairingCard;
6
+ exports.buildSessionCommandCard = buildSessionCommandCard;
6
7
  exports.extractCardActionMessageId = extractCardActionMessageId;
7
8
  exports.extractCardActionValue = extractCardActionValue;
9
+ exports.extractSessionCommandActionValue = extractSessionCommandActionValue;
8
10
  exports.formatPermissionButtonLabel = formatPermissionButtonLabel;
9
11
  exports.formatPermissionResponseLabel = formatPermissionResponseLabel;
10
12
  const desktop_js_1 = require("../../../../../shared/desktop.js");
@@ -80,6 +82,37 @@ function renderPendingPairingCard(code) {
80
82
  }
81
83
  return lines.join('\n\n');
82
84
  }
85
+ function buildSessionCommandCard(text, actionRows = [], sessionKey, threadId) {
86
+ const elements = [];
87
+ if (text) {
88
+ elements.push({ tag: 'markdown', content: text });
89
+ }
90
+ for (const row of actionRows) {
91
+ const actions = row
92
+ .filter((button) => button.label && button.command)
93
+ .map((button) => ({
94
+ tag: 'button',
95
+ text: {
96
+ tag: 'plain_text',
97
+ content: button.label,
98
+ },
99
+ type: button.type || 'default',
100
+ value: {
101
+ action: 'session_command',
102
+ command: button.command,
103
+ session_key: sessionKey || '',
104
+ thread_id: threadId || '',
105
+ },
106
+ }));
107
+ if (actions.length) {
108
+ elements.push({ tag: 'action', actions });
109
+ }
110
+ }
111
+ return {
112
+ config: { wide_screen_mode: true },
113
+ elements,
114
+ };
115
+ }
83
116
  function extractCardActionMessageId(...payloads) {
84
117
  for (const payload of payloads) {
85
118
  const messageId = extractKnownCardActionMessageId(payload);
@@ -117,6 +150,28 @@ function extractCardActionValue(payload) {
117
150
  sessionKey,
118
151
  };
119
152
  }
153
+ function extractSessionCommandActionValue(payload) {
154
+ const event = (payload?.event && typeof payload.event === 'object')
155
+ ? payload.event
156
+ : payload;
157
+ const value = event?.action?.value;
158
+ if (!value || value.action !== 'session_command') {
159
+ return null;
160
+ }
161
+ const command = String(value.command || '').trim();
162
+ const threadId = String(value.thread_id || '').trim();
163
+ const sessionKey = String(value.session_key || '').trim();
164
+ if (!command || !threadId) {
165
+ return null;
166
+ }
167
+ return {
168
+ event,
169
+ value: value,
170
+ command,
171
+ threadId,
172
+ sessionKey,
173
+ };
174
+ }
120
175
  function formatPermissionButtonLabel(button) {
121
176
  return formatPermissionResponseLabel(button.data || button.text);
122
177
  }
@@ -41,11 +41,13 @@ const node_path_1 = require("node:path");
41
41
  const desktop_js_1 = require("../../../../../shared/desktop.js");
42
42
  const content_js_1 = require("../shared/content.js");
43
43
  const file_utils_js_1 = require("../shared/file-utils.js");
44
+ const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
44
45
  const cards_js_1 = require("./cards.js");
45
46
  const config_js_1 = require("./config.js");
46
47
  const registration_js_1 = require("./registration.js");
47
48
  const messages_js_1 = require("./rendering/messages.js");
48
49
  const runtime_state_js_1 = require("./runtime-state.js");
50
+ const session_command_service_js_1 = require("../../thread/session-command-service.js");
49
51
  const PAIRING_EXPIRY_MS = 10 * 60 * 1000;
50
52
  const LARK_MAX_UPLOAD_FILE_SIZE = 30 * 1024 * 1024;
51
53
  const LARK_FINAL_PATCH_INTERVAL_MS = 900;
@@ -62,12 +64,37 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
62
64
  outboundEventChains = new Map();
63
65
  outboundTurns = new Map();
64
66
  mutedThreadBridgeCounts = new Map();
67
+ sessionCommandRuntime;
65
68
  larkModulePromise = null;
66
69
  platform = 'lark';
67
70
  routeType = 'channel.chat';
68
71
  constructor(options) {
69
72
  super();
70
73
  this.options = options;
74
+ const sessionCommandService = new session_command_service_js_1.SessionCommandService({
75
+ listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
76
+ getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
77
+ createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
78
+ renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
79
+ deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
80
+ });
81
+ this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
82
+ service: sessionCommandService,
83
+ store: this.options.store,
84
+ getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
85
+ setThreadRoute: (sessionKey, route) => {
86
+ this.threadRouting.set(sessionKey, route);
87
+ },
88
+ createRoute: (input, threadId) => ({
89
+ workspaceId: input.workspaceId,
90
+ instanceId: input.instanceId,
91
+ platformKey: input.platformKey,
92
+ platformUserId: input.platformUserId,
93
+ chatId: input.chatId,
94
+ threadId,
95
+ }),
96
+ sendResult: (input, result) => this.sendSessionCommandResult(input, result),
97
+ });
71
98
  }
72
99
  async refreshBindings() {
73
100
  const config = await this.options.readConfig();
@@ -204,6 +231,17 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
204
231
  }
205
232
  };
206
233
  }
234
+ async executeSessionCommand(input) {
235
+ return this.sessionCommandRuntime.execute(input);
236
+ }
237
+ async sendSessionCommandResult(input, result) {
238
+ const state = this.resolveRuntimeState(input.workspaceId, input.instanceId).state;
239
+ if (state?.client && state.connected && result.card?.actions?.length && state.cardActionsEnabled) {
240
+ await this.sendSessionCommandCard(state, input.chatId, result.displayText, result.card.actions, this.options.getWorkspaceRouter().getThreadSessionKey(input.currentThreadId), input.currentThreadId);
241
+ return;
242
+ }
243
+ await this.sendImmediateCard(input.workspaceId, input.chatId, result.displayText, input.instanceId);
244
+ }
207
245
  async sendOutboundMessage(workspaceId, input) {
208
246
  const state = this.resolveRuntimeState(workspaceId, input.route?.instanceId).state;
209
247
  if (!state?.client || !state.connected) {
@@ -659,35 +697,18 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
659
697
  const acknowledgement = this.createTurnState(effectiveSessionKey, input.messageId);
660
698
  await this.addAcknowledgementReaction(input.workspaceId, input.messageId, acknowledgement, instanceId);
661
699
  const slashCommand = this.parseSlashCommand(input.text);
662
- if (slashCommand?.name === 'new') {
663
- const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`;
664
- const nextThread = await router.createThread(input.workspaceId, title);
665
- const inheritedMode = this.options.store.getThreadRow?.(threadId)?.agent_mode || '';
666
- if (inheritedMode && inheritedMode !== 'default') {
667
- this.options.store.updateThreadAgentMode?.(nextThread.id, inheritedMode);
668
- }
669
- const now = new Date().toISOString();
670
- this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
671
- this.options.store.upsertPlatformThreadBinding({
672
- workspace_id: input.workspaceId,
673
- platform: platformKey,
674
- chat_id: input.chatId,
675
- platform_user_id: input.platformUserId,
676
- thread_id: nextThread.id,
677
- last_platform_message_id: null,
678
- created_at: now,
679
- updated_at: now,
680
- });
681
- this.threadRouting.set(this.options.getWorkspaceRouter().getThreadSessionKey(nextThread.id), {
682
- workspaceId: input.workspaceId,
683
- instanceId,
684
- platformKey,
685
- platformUserId: input.platformUserId,
686
- chatId: input.chatId,
687
- threadId: nextThread.id,
688
- });
689
- await this.sendImmediateCard(input.workspaceId, input.chatId, '**已开始新会话**', instanceId);
690
- return { paired: true, threadId: nextThread.id };
700
+ const sessionCommand = await this.executeSessionCommand({
701
+ workspaceId: input.workspaceId,
702
+ currentThreadId: threadId,
703
+ text: input.text,
704
+ defaultTitle: `${input.displayName || 'Lark'} ${new Date().toLocaleTimeString()}`,
705
+ chatId: input.chatId,
706
+ platformUserId: input.platformUserId,
707
+ platformKey,
708
+ instanceId,
709
+ });
710
+ if (sessionCommand.handled) {
711
+ return { paired: true, threadId: sessionCommand.threadId || threadId };
691
712
  }
692
713
  const latestRun = this.options.store.getLatestRunForThread(threadId);
693
714
  if ((normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
@@ -1157,6 +1178,21 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1157
1178
  this.options.log?.(`localcore-lark card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
1158
1179
  return String(response?.data?.message_id || '').trim();
1159
1180
  }
1181
+ async sendSessionCommandCard(state, chatId, text, actionRows, sessionKey, threadId) {
1182
+ const startedAt = Date.now();
1183
+ const response = await state.client.im.message.create({
1184
+ params: {
1185
+ receive_id_type: this.resolveReceiveIdType(chatId),
1186
+ },
1187
+ data: {
1188
+ receive_id: chatId,
1189
+ msg_type: 'interactive',
1190
+ content: JSON.stringify((0, cards_js_1.buildSessionCommandCard)(text, actionRows, sessionKey, threadId)),
1191
+ },
1192
+ });
1193
+ this.options.log?.(`localcore-lark session card create took ${Date.now() - startedAt}ms textBytes=${Buffer.byteLength(text || '', 'utf8')}`);
1194
+ return String(response?.data?.message_id || '').trim();
1195
+ }
1160
1196
  async sendTextAsMessage(state, chatId, text) {
1161
1197
  const startedAt = Date.now();
1162
1198
  const rendered = (0, messages_js_1.renderLarkTextMessage)(text);
@@ -1272,6 +1308,27 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1272
1308
  const instanceId = legacyCall ? 'default' : instanceIdOrData;
1273
1309
  const data = (legacyCall ? instanceIdOrData : maybeData) || {};
1274
1310
  try {
1311
+ const sessionAction = (0, cards_js_1.extractSessionCommandActionValue)(data);
1312
+ if (sessionAction) {
1313
+ const route = this.threadRouting.get(sessionAction.sessionKey)
1314
+ || this.routeFromThreadBinding(sessionAction.threadId, instanceId);
1315
+ if (!route) {
1316
+ this.options.log?.(`localcore-lark session card action ignored without route for thread=${sessionAction.threadId}`);
1317
+ return;
1318
+ }
1319
+ await this.executeSessionCommand({
1320
+ workspaceId,
1321
+ currentThreadId: sessionAction.threadId,
1322
+ text: sessionAction.command,
1323
+ defaultTitle: `Lark ${new Date().toLocaleTimeString()}`,
1324
+ chatId: route.chatId,
1325
+ platformUserId: route.platformUserId,
1326
+ platformKey: route.platformKey,
1327
+ instanceId: route.instanceId,
1328
+ });
1329
+ this.options.log?.(`localcore-lark processed session card action for ${workspaceId}/${instanceId}: ${sessionAction.command}`);
1330
+ return;
1331
+ }
1275
1332
  const action = (0, cards_js_1.extractCardActionValue)(data);
1276
1333
  if (!action) {
1277
1334
  return;
@@ -1285,6 +1342,21 @@ class LocalCoreLarkGateway extends node_events_1.EventEmitter {
1285
1342
  this.options.log?.(`localcore-lark card action failed for ${workspaceId}/${instanceId}: ${error instanceof Error ? error.message : String(error)}`);
1286
1343
  }
1287
1344
  }
1345
+ routeFromThreadBinding(threadId, instanceId) {
1346
+ const binding = this.options.store.getPlatformThreadBindingByThreadId(threadId);
1347
+ if (!binding || (binding.platform !== 'lark' && !binding.platform.startsWith('lark:'))) {
1348
+ return undefined;
1349
+ }
1350
+ const bindingInstanceId = getLarkInstanceId(binding.platform) || instanceId || 'default';
1351
+ return {
1352
+ workspaceId: binding.workspace_id,
1353
+ instanceId: bindingInstanceId,
1354
+ platformKey: binding.platform,
1355
+ platformUserId: binding.platform_user_id,
1356
+ chatId: binding.chat_id,
1357
+ threadId: binding.thread_id,
1358
+ };
1359
+ }
1288
1360
  async markPermissionCardActionHandled(workspaceId, instanceId, rootPayload, payload, value, response, threadId) {
1289
1361
  const state = this.resolveRuntimeState(workspaceId, instanceId).state;
1290
1362
  if (!state?.client) {
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChannelSessionCommandRuntime = void 0;
4
+ class ChannelSessionCommandRuntime {
5
+ options;
6
+ constructor(options) {
7
+ this.options = options;
8
+ }
9
+ async execute(input) {
10
+ const result = await this.options.service.execute(input.text, {
11
+ workspaceId: input.workspaceId,
12
+ currentThreadId: input.currentThreadId,
13
+ defaultTitle: input.defaultTitle,
14
+ });
15
+ if (!result.handled) {
16
+ return { handled: false, threadId: input.currentThreadId };
17
+ }
18
+ let activeThreadId = input.currentThreadId;
19
+ for (const effect of result.effects || []) {
20
+ if (effect.type === 'created_thread') {
21
+ this.inheritAgentMode(input.currentThreadId, effect.threadId);
22
+ }
23
+ if (effect.type === 'activate_thread') {
24
+ activeThreadId = effect.threadId;
25
+ this.activateThread(input, effect.threadId);
26
+ }
27
+ }
28
+ await this.options.sendResult(input, result);
29
+ return { handled: true, threadId: activeThreadId, result };
30
+ }
31
+ inheritAgentMode(sourceThreadId, targetThreadId) {
32
+ const inheritedMode = this.options.store.getThreadRow?.(sourceThreadId)?.agent_mode || '';
33
+ if (inheritedMode && inheritedMode !== 'default') {
34
+ this.options.store.updateThreadAgentMode?.(targetThreadId, inheritedMode);
35
+ }
36
+ }
37
+ activateThread(input, threadId) {
38
+ const now = new Date().toISOString();
39
+ this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, threadId, input.platformKey);
40
+ this.options.store.upsertPlatformThreadBinding({
41
+ workspace_id: input.workspaceId,
42
+ platform: input.platformKey,
43
+ chat_id: input.chatId,
44
+ platform_user_id: input.platformUserId,
45
+ thread_id: threadId,
46
+ last_platform_message_id: null,
47
+ created_at: now,
48
+ updated_at: now,
49
+ });
50
+ this.options.setThreadRoute(this.options.getThreadSessionKey(threadId), this.options.createRoute(input, threadId));
51
+ }
52
+ }
53
+ exports.ChannelSessionCommandRuntime = ChannelSessionCommandRuntime;
@@ -13,6 +13,8 @@ const node_crypto_2 = require("node:crypto");
13
13
  const desktop_js_1 = require("../../../../../shared/desktop.js");
14
14
  const content_js_1 = require("../shared/content.js");
15
15
  const file_utils_js_1 = require("../shared/file-utils.js");
16
+ const session_command_runtime_js_1 = require("../shared/session-command-runtime.js");
17
+ const session_command_service_js_1 = require("../../thread/session-command-service.js");
16
18
  const config_js_1 = require("./config.js");
17
19
  const transport_js_1 = require("./transport.js");
18
20
  // ==================== Constants ====================
@@ -150,11 +152,36 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
150
152
  outboundTurns = new Map();
151
153
  processedInboundMessages = new Map();
152
154
  mutedThreadBridgeCounts = new Map();
155
+ sessionCommandRuntime;
153
156
  platform = 'weixin';
154
157
  routeType = 'channel.chat';
155
158
  constructor(options) {
156
159
  super();
157
160
  this.options = options;
161
+ const sessionCommandService = new session_command_service_js_1.SessionCommandService({
162
+ listThreads: (workspaceId) => this.options.getWorkspaceRouter().listThreads(workspaceId),
163
+ getThread: (threadId) => this.options.getWorkspaceRouter().getThread(threadId),
164
+ createThread: (workspaceId, title) => this.options.getWorkspaceRouter().createThread(workspaceId, title),
165
+ renameThread: (threadId, title) => this.options.getWorkspaceRouter().renameThread(threadId, title),
166
+ deleteThread: (threadId) => this.options.getWorkspaceRouter().deleteThread(threadId),
167
+ });
168
+ this.sessionCommandRuntime = new session_command_runtime_js_1.ChannelSessionCommandRuntime({
169
+ service: sessionCommandService,
170
+ store: this.options.store,
171
+ getThreadSessionKey: (threadId) => this.options.getWorkspaceRouter().getThreadSessionKey(threadId),
172
+ setThreadRoute: (sessionKey, route) => {
173
+ this.threadRouting.set(sessionKey, route);
174
+ },
175
+ createRoute: (input, threadId) => ({
176
+ workspaceId: input.workspaceId,
177
+ instanceId: input.instanceId,
178
+ platformKey: input.platformKey,
179
+ platformUserId: input.platformUserId,
180
+ chatId: input.chatId,
181
+ threadId,
182
+ }),
183
+ sendResult: (input, result) => this.sendSessionCommandResult(input, result),
184
+ });
158
185
  }
159
186
  // ==================== Lifecycle ====================
160
187
  async refreshBindings() {
@@ -648,7 +675,6 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
648
675
  updated_at: now,
649
676
  });
650
677
  }
651
- const sessionKey = router.getThreadSessionKey(threadId);
652
678
  const normalizedText = String(input.text || '').trim().toLowerCase();
653
679
  const permissionThreadId = (normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny') ? this.findAwaitingPermissionThreadId(input.workspaceId, input.chatId, input.platformUserId, input.platformKey) : '';
654
680
  if (permissionThreadId && permissionThreadId !== threadId) {
@@ -665,38 +691,19 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
665
691
  });
666
692
  // Handle slash commands
667
693
  const slashCommand = this.parseSlashCommand(input.text);
668
- if (slashCommand?.name === 'new') {
669
- const title = slashCommand.args.join(' ').trim() || `${input.displayName || 'WeChat'} ${new Date().toLocaleTimeString()}`;
670
- const nextThread = await router.createThread(input.workspaceId, title);
671
- const inheritedMode = this.options.store.getThreadRow?.(threadId)?.agent_mode || '';
672
- if (inheritedMode && inheritedMode !== 'default') {
673
- this.options.store.updateThreadAgentMode?.(nextThread.id, inheritedMode);
674
- }
675
- const now = new Date().toISOString();
676
- this.options.store.updateAuthorizedUserThread(input.workspaceId, input.platformUserId, nextThread.id, platformKey);
677
- this.options.store.upsertPlatformThreadBinding({
678
- workspace_id: input.workspaceId,
679
- platform: platformKey,
680
- chat_id: input.chatId,
681
- platform_user_id: input.platformUserId,
682
- thread_id: nextThread.id,
683
- last_platform_message_id: null,
684
- created_at: now,
685
- updated_at: now,
686
- });
687
- this.threadRouting.set(router.getThreadSessionKey(nextThread.id), {
688
- workspaceId: input.workspaceId,
689
- instanceId,
690
- platformKey,
691
- platformUserId: input.platformUserId,
692
- chatId: input.chatId,
693
- threadId: nextThread.id,
694
- });
695
- const st = this.runtime.get((0, config_js_1.runtimeKey)(input.workspaceId, instanceId));
696
- if (st?.connected) {
697
- await this.sendTextMessage(st, input.chatId, '**已开始新会话**', input.contextToken);
698
- }
699
- return { paired: true, threadId: nextThread.id };
694
+ const sessionCommand = await this.executeSessionCommand({
695
+ workspaceId: input.workspaceId,
696
+ currentThreadId: threadId,
697
+ text: input.text,
698
+ defaultTitle: `${input.displayName || 'WeChat'} ${new Date().toLocaleTimeString()}`,
699
+ chatId: input.chatId,
700
+ platformUserId: input.platformUserId,
701
+ platformKey,
702
+ instanceId,
703
+ contextToken: input.contextToken,
704
+ });
705
+ if (sessionCommand.handled) {
706
+ return { paired: true, threadId: sessionCommand.threadId || threadId };
700
707
  }
701
708
  const latestRun = this.options.store.getLatestRunForThread(threadId);
702
709
  if ((normalizedText === 'allow' || normalizedText === 'allow all' || normalizedText === 'deny')
@@ -711,6 +718,17 @@ class LocalCoreWeixinGateway extends node_events_1.EventEmitter {
711
718
  await router.sendThreadMessage(threadId, (0, content_js_1.createChannelThreadMessageInput)(wrappedText, input.contentParts));
712
719
  return { paired: true, threadId };
713
720
  }
721
+ async executeSessionCommand(input) {
722
+ return this.sessionCommandRuntime.execute(input);
723
+ }
724
+ async sendSessionCommandResult(input, result) {
725
+ const state = this.resolveRuntimeState(input.workspaceId, input.instanceId).state;
726
+ if (!state?.connected) {
727
+ this.options.log?.(`localcore-weixin session command response skipped: workspace not connected: ${input.workspaceId}`);
728
+ return;
729
+ }
730
+ await this.sendTextMessage(state, input.chatId, result.displayText, input.contextToken);
731
+ }
714
732
  // ==================== Private: Bindings ====================
715
733
  resolveRuntimeState(workspaceId, instanceId) {
716
734
  if (instanceId) {