@kafca/agentdock 0.1.7

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 (79) hide show
  1. package/README.md +70 -0
  2. package/bin/agentdock.mjs +275 -0
  3. package/build/icon.png +0 -0
  4. package/dist/renderer/assets/index-BaNpzC6d.js +482 -0
  5. package/dist/renderer/assets/index-CLWJyO0E.css +11 -0
  6. package/dist/renderer/favicon.svg +19 -0
  7. package/dist/renderer/index.html +14 -0
  8. package/dist/renderer/logo-options.svg +153 -0
  9. package/dist-electron/electron/knowledge-skill-script.test.js +125 -0
  10. package/dist-electron/electron/lac-cli.test.js +221 -0
  11. package/dist-electron/electron/local-core-refactor.test.js +1075 -0
  12. package/dist-electron/electron/main.js +163 -0
  13. package/dist-electron/electron/plugin-kernel.test.js +534 -0
  14. package/dist-electron/electron/preload.js +2 -0
  15. package/dist-electron/package.json +3 -0
  16. package/dist-electron/packages/contracts/src/index.js +18 -0
  17. package/dist-electron/packages/contracts/src/local-core.js +2 -0
  18. package/dist-electron/packages/core-sdk/src/index.js +406 -0
  19. package/dist-electron/packages/knowledge-api/src/ai-vector-provider.js +388 -0
  20. package/dist-electron/packages/knowledge-api/src/index.js +146 -0
  21. package/dist-electron/packages/knowledge-api/src/sqlite-store.js +467 -0
  22. package/dist-electron/packages/knowledge-api/src/thread-knowledge-store.js +21 -0
  23. package/dist-electron/packages/knowledge-api/test/ai-vector-provider.test.js +412 -0
  24. package/dist-electron/packages/plugin-sdk/src/index.js +2 -0
  25. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +369 -0
  26. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +110 -0
  27. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +171 -0
  28. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +635 -0
  29. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +190 -0
  30. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +244 -0
  31. package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +52 -0
  32. package/dist-electron/services/local-ai-core/src/cli/lac.js +290 -0
  33. package/dist-electron/services/local-ai-core/src/gateway/local-core-lark-gateway.js +976 -0
  34. package/dist-electron/services/local-ai-core/src/gateway/local-core-weixin-gateway.js +1143 -0
  35. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +291 -0
  36. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +67 -0
  37. package/dist-electron/services/local-ai-core/src/kernel/diagnostics.js +27 -0
  38. package/dist-electron/services/local-ai-core/src/kernel/event-bus.js +27 -0
  39. package/dist-electron/services/local-ai-core/src/kernel/lifecycle-manager.js +85 -0
  40. package/dist-electron/services/local-ai-core/src/kernel/plugin-registry.js +60 -0
  41. package/dist-electron/services/local-ai-core/src/plugins/builtin/agent-localcore-acp-plugin.js +114 -0
  42. package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +59 -0
  43. package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +56 -0
  44. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-ai-vector-plugin.js +7 -0
  45. package/dist-electron/services/local-ai-core/src/plugins/builtin/knowledge-noop-plugin.js +7 -0
  46. package/dist-electron/services/local-ai-core/src/plugins/builtin/runtime-capabilities-plugin.js +62 -0
  47. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-cron-plugin.js +49 -0
  48. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-lark-plugin.js +38 -0
  49. package/dist-electron/services/local-ai-core/src/plugins/builtin/scheduler-weixin-plugin.js +38 -0
  50. package/dist-electron/services/local-ai-core/src/router/workspace-route-config.js +230 -0
  51. package/dist-electron/services/local-ai-core/src/router/workspace-router-types.js +2 -0
  52. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +389 -0
  53. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +315 -0
  54. package/dist-electron/services/local-ai-core/src/runtime/local-core-runtime-state.js +282 -0
  55. package/dist-electron/services/local-ai-core/src/runtime/server.js +465 -0
  56. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +38 -0
  57. package/dist-electron/services/local-ai-core/src/scheduler/adapters.js +2 -0
  58. package/dist-electron/services/local-ai-core/src/scheduler/cron-command-detector.js +70 -0
  59. package/dist-electron/services/local-ai-core/src/scheduler/cron.js +53 -0
  60. package/dist-electron/services/local-ai-core/src/scheduler/execution-policy.js +2 -0
  61. package/dist-electron/services/local-ai-core/src/scheduler/lark-execution-policies.js +66 -0
  62. package/dist-electron/services/local-ai-core/src/scheduler/lark-schedule-adapter.js +77 -0
  63. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +46 -0
  64. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-run-lifecycle.js +64 -0
  65. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +133 -0
  66. package/dist-electron/services/local-ai-core/src/scheduler/weixin-execution-policies.js +66 -0
  67. package/dist-electron/services/local-ai-core/src/scheduler/weixin-schedule-adapter.js +78 -0
  68. package/dist-electron/services/local-ai-core/src/thread/workspace-thread-id.js +17 -0
  69. package/dist-electron/services/local-ai-core/src/thread/workspace-thread-mappers.js +43 -0
  70. package/dist-electron/shared/desktop.js +195 -0
  71. package/dist-electron/src/api/client.js +73 -0
  72. package/dist-electron/src/api/sessions.js +21 -0
  73. package/dist-electron/src/lib/session-utils.js +51 -0
  74. package/dist-electron/src/pages/Threads/thread-chat-model.js +246 -0
  75. package/dist-electron/src/pages/Threads/thread-chat-model.test.js +76 -0
  76. package/dist-electron/src/pages/Threads/thread-chat-permission.js +26 -0
  77. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +102 -0
  78. package/dist-electron/src/pages/Threads/thread-chat-task-state.js +65 -0
  79. package/package.json +146 -0
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceRouter = exports.encodeThreadId = exports.decodeThreadId = void 0;
4
+ exports.createWorkspaceRouter = createWorkspaceRouter;
5
+ const local_core_acp_backend_js_1 = require("../acp/local-core-acp-backend.js");
6
+ const workspace_thread_id_js_1 = require("../thread/workspace-thread-id.js");
7
+ const workspace_route_config_js_1 = require("./workspace-route-config.js");
8
+ var workspace_thread_id_js_2 = require("../thread/workspace-thread-id.js");
9
+ Object.defineProperty(exports, "decodeThreadId", { enumerable: true, get: function () { return workspace_thread_id_js_2.decodeThreadId; } });
10
+ Object.defineProperty(exports, "encodeThreadId", { enumerable: true, get: function () { return workspace_thread_id_js_2.encodeThreadId; } });
11
+ class WorkspaceRouter {
12
+ options;
13
+ store;
14
+ localCoreAcp;
15
+ runThreadMap = new Map();
16
+ bridgeSubscribers = new Set();
17
+ schedulerBridge = null;
18
+ constructor(options) {
19
+ this.options = options;
20
+ this.store = options.store;
21
+ this.localCoreAcp = new local_core_acp_backend_js_1.LocalCoreAcpBackend({
22
+ store: this.store,
23
+ runThreadMap: this.runThreadMap,
24
+ cliBinDir: options.cliBinDir,
25
+ localCoreBase: options.localCoreBase,
26
+ emitBridge: (event) => this.emitBridgeEvent(event),
27
+ eventBus: options.eventBus,
28
+ scheduler: {
29
+ createJob: async (input) => {
30
+ if (!this.schedulerBridge) {
31
+ throw new Error('Scheduler bridge is unavailable.');
32
+ }
33
+ return this.schedulerBridge.createJob(input);
34
+ },
35
+ listJobsForThread: async (threadId) => {
36
+ if (!this.schedulerBridge) {
37
+ throw new Error('Scheduler bridge is unavailable.');
38
+ }
39
+ return this.schedulerBridge.listJobsForThread(threadId);
40
+ },
41
+ deleteJob: async (jobId) => {
42
+ if (!this.schedulerBridge) {
43
+ throw new Error('Scheduler bridge is unavailable.');
44
+ }
45
+ return this.schedulerBridge.deleteJob(jobId);
46
+ },
47
+ },
48
+ log: options.log,
49
+ });
50
+ }
51
+ close() {
52
+ this.localCoreAcp.close();
53
+ this.bridgeSubscribers.clear();
54
+ this.store.close();
55
+ }
56
+ getThreadSessionKey(threadId) {
57
+ const row = this.store.getThreadRow(threadId);
58
+ return row?.bridge_session_key || '';
59
+ }
60
+ setSchedulerBridge(bridge) {
61
+ this.schedulerBridge = bridge;
62
+ }
63
+ async listWorkspaces() {
64
+ const localProjects = await this.listLocalCoreProjects();
65
+ const workspaceMap = new Map();
66
+ for (const project of localProjects) {
67
+ const route = this.resolveProjectRoute(await this.options.readConfigState(), project);
68
+ if (!route) {
69
+ continue;
70
+ }
71
+ workspaceMap.set(project.name, {
72
+ id: project.name,
73
+ name: project.name,
74
+ agentType: route.agentType,
75
+ platforms: (0, workspace_route_config_js_1.normalizePlatformTypes)(project),
76
+ sessionsCount: this.store.countThreads(project.name),
77
+ heartbeatEnabled: false,
78
+ });
79
+ }
80
+ return [...workspaceMap.values()].sort((a, b) => a.name.localeCompare(b.name));
81
+ }
82
+ async listThreads(workspaceId) {
83
+ await this.getWorkspaceRoute(workspaceId);
84
+ return this.localCoreAcp.listThreads(workspaceId);
85
+ }
86
+ async createThread(workspaceId, title) {
87
+ const route = await this.getWorkspaceRoute(workspaceId);
88
+ return this.withKnowledge(await this.localCoreAcp.createThread(workspaceId, title || `New thread ${new Date().toLocaleTimeString()}`, route.agentType));
89
+ }
90
+ async getThread(threadId) {
91
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
92
+ await this.getWorkspaceRoute(workspaceId);
93
+ return this.withKnowledge(await this.localCoreAcp.getThread(threadId));
94
+ }
95
+ async renameThread(threadId, title) {
96
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
97
+ await this.getWorkspaceRoute(workspaceId);
98
+ return this.withKnowledge(await this.localCoreAcp.renameThread(threadId, title));
99
+ }
100
+ async updateThreadKnowledgeBases(threadId, knowledgeBaseIds) {
101
+ return {
102
+ knowledgeBaseIds: await this.options.knowledgeAttachments.updateThreadKnowledgeBaseIds(threadId, knowledgeBaseIds),
103
+ };
104
+ }
105
+ async deleteThread(threadId) {
106
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
107
+ await this.getWorkspaceRoute(workspaceId);
108
+ await this.localCoreAcp.deleteThread(threadId);
109
+ await this.options.knowledgeAttachments.deleteThreadKnowledgeBaseLinks(threadId);
110
+ return { deleted: true };
111
+ }
112
+ async sendThreadMessage(threadId, content) {
113
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
114
+ const route = await this.getWorkspaceRoute(workspaceId);
115
+ return this.localCoreAcp.sendThreadMessage(threadId, content, route.config);
116
+ }
117
+ async sendThreadAction(threadId, content) {
118
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
119
+ const route = await this.getWorkspaceRoute(workspaceId);
120
+ return this.localCoreAcp.sendThreadAction(threadId, content, route.config);
121
+ }
122
+ async interruptRun(runId) {
123
+ const threadId = this.runThreadMap.get(runId);
124
+ if (!threadId) {
125
+ return { interrupted: false };
126
+ }
127
+ const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
128
+ await this.getWorkspaceRoute(workspaceId);
129
+ return this.localCoreAcp.interruptRun(runId);
130
+ }
131
+ getCapabilities() {
132
+ return this.options.getCapabilities();
133
+ }
134
+ async probeWorkspaceStreaming(workspaceId) {
135
+ const route = await this.getWorkspaceRoute(workspaceId);
136
+ if (!route.supportsStreamingProbe) {
137
+ throw new Error(`Workspace "${workspaceId}" does not expose a streaming probe.`);
138
+ }
139
+ return this.probeLocalCoreAcpWorkspace(workspaceId, route);
140
+ }
141
+ async withKnowledge(detail) {
142
+ return {
143
+ ...detail,
144
+ selectedKnowledgeBaseIds: await this.options.knowledgeAttachments.listThreadKnowledgeBaseIds(detail.id),
145
+ };
146
+ }
147
+ emitBridgeEvent(event) {
148
+ this.options.eventBus.emit({
149
+ type: 'platform.bridge.updated',
150
+ payload: event,
151
+ });
152
+ this.notifyBridgeSubscribers(event);
153
+ }
154
+ notifyBridgeSubscribers(event) {
155
+ for (const listener of this.bridgeSubscribers) {
156
+ listener(event);
157
+ }
158
+ }
159
+ subscribeBridge(listener) {
160
+ this.bridgeSubscribers.add(listener);
161
+ return () => {
162
+ this.bridgeSubscribers.delete(listener);
163
+ };
164
+ }
165
+ subscribeBridgeEvents(listener) {
166
+ return this.subscribeBridge(listener);
167
+ }
168
+ createProbeCollector() {
169
+ return {
170
+ startedAt: new Date().toISOString(),
171
+ events: [],
172
+ sawTypingStart: false,
173
+ sawTypingStop: false,
174
+ sawReply: false,
175
+ sawPreviewLike: false,
176
+ firstPreviewAt: null,
177
+ firstReplyAt: null,
178
+ updateMessageCount: 0,
179
+ cumulativeUpdates: true,
180
+ lastPreviewContent: '',
181
+ };
182
+ }
183
+ recordProbeEvent(collector, event) {
184
+ const at = Date.now();
185
+ const content = String(event.content || '');
186
+ collector.events.push({
187
+ type: event.type,
188
+ at: new Date(at).toISOString(),
189
+ contentLength: content.length,
190
+ previewHandle: event.previewHandle,
191
+ });
192
+ switch (event.type) {
193
+ case 'typing_start':
194
+ collector.sawTypingStart = true;
195
+ break;
196
+ case 'typing_stop':
197
+ collector.sawTypingStop = true;
198
+ break;
199
+ case 'preview_start':
200
+ collector.sawPreviewLike = true;
201
+ collector.firstPreviewAt ??= at;
202
+ collector.lastPreviewContent = content;
203
+ break;
204
+ case 'update_message':
205
+ collector.sawPreviewLike = true;
206
+ collector.firstPreviewAt ??= at;
207
+ collector.updateMessageCount += 1;
208
+ if (collector.lastPreviewContent &&
209
+ content &&
210
+ !content.startsWith(collector.lastPreviewContent)) {
211
+ collector.cumulativeUpdates = false;
212
+ }
213
+ collector.lastPreviewContent = content;
214
+ break;
215
+ case 'reply':
216
+ collector.sawReply = true;
217
+ collector.firstReplyAt ??= at;
218
+ break;
219
+ default:
220
+ break;
221
+ }
222
+ }
223
+ finalizeProbeResult(workspaceId, agentType, transport, prompt, collector, options = {}) {
224
+ const completedAt = new Date().toISOString();
225
+ const durationMs = Math.max(0, Date.parse(completedAt) - Date.parse(collector.startedAt));
226
+ const previewBeforeFinal = collector.sawPreviewLike && (collector.firstReplyAt == null ||
227
+ (collector.firstPreviewAt != null && collector.firstPreviewAt <= collector.firstReplyAt));
228
+ const finalEvent = options.error
229
+ ? 'error'
230
+ : options.timedOut
231
+ ? 'timeout'
232
+ : collector.sawReply
233
+ ? 'reply'
234
+ : collector.sawTypingStop
235
+ ? 'typing_stop'
236
+ : 'none';
237
+ const hungPreview = collector.sawPreviewLike && !collector.sawTypingStop;
238
+ const passed = Boolean(collector.sawTypingStart &&
239
+ collector.sawTypingStop &&
240
+ previewBeforeFinal &&
241
+ collector.updateMessageCount >= 2 &&
242
+ collector.cumulativeUpdates &&
243
+ !hungPreview &&
244
+ !options.error &&
245
+ !options.timedOut);
246
+ return {
247
+ workspaceId,
248
+ agentType,
249
+ transport,
250
+ prompt,
251
+ passed,
252
+ startedAt: collector.startedAt,
253
+ completedAt,
254
+ durationMs,
255
+ threadId: options.threadId,
256
+ sessionKey: options.sessionKey,
257
+ error: options.error,
258
+ criteria: {
259
+ sawTypingStart: collector.sawTypingStart,
260
+ sawTypingStop: collector.sawTypingStop,
261
+ previewBeforeFinal,
262
+ updateMessageCount: collector.updateMessageCount,
263
+ cumulativeUpdates: collector.cumulativeUpdates,
264
+ finalEvent,
265
+ hungPreview,
266
+ },
267
+ events: collector.events,
268
+ };
269
+ }
270
+ waitForProbeSequence(sessionKey, timeoutMs, collector) {
271
+ let active = true;
272
+ let unsubscribe = () => { };
273
+ const promise = new Promise((resolve, reject) => {
274
+ const timeout = setTimeout(() => {
275
+ active = false;
276
+ unsubscribe();
277
+ reject(new Error(`Timed out waiting for ACP streaming events after ${timeoutMs}ms`));
278
+ }, timeoutMs);
279
+ unsubscribe = this.subscribeBridge((event) => {
280
+ if (!active) {
281
+ return;
282
+ }
283
+ if (event.sessionKey !== sessionKey) {
284
+ return;
285
+ }
286
+ this.recordProbeEvent(collector, event);
287
+ if (event.type === 'typing_stop') {
288
+ active = false;
289
+ clearTimeout(timeout);
290
+ unsubscribe();
291
+ resolve();
292
+ }
293
+ });
294
+ });
295
+ return {
296
+ promise,
297
+ cancel: () => {
298
+ if (!active) {
299
+ return;
300
+ }
301
+ active = false;
302
+ unsubscribe();
303
+ },
304
+ };
305
+ }
306
+ buildProbePrompt() {
307
+ return 'Reply with exactly three short plain-text lines: alpha, beta, gamma. Do not call tools or ask questions.';
308
+ }
309
+ async probeLocalCoreAcpWorkspace(workspaceId, route) {
310
+ const prompt = this.buildProbePrompt();
311
+ const thread = await this.localCoreAcp.createThread(workspaceId, `[probe] ${new Date().toISOString()}`, route.agentType);
312
+ const collector = this.createProbeCollector();
313
+ const sequence = this.waitForProbeSequence(thread.bridgeSessionKey || '', 20000, collector);
314
+ try {
315
+ const sent = await this.localCoreAcp.sendThreadMessage(thread.id, prompt, route.config);
316
+ await sequence.promise;
317
+ await this.localCoreAcp.interruptRun(sent.runId).catch(() => ({ interrupted: false }));
318
+ return this.finalizeProbeResult(workspaceId, route.agentType, 'localcore-acp', prompt, collector, {
319
+ threadId: thread.id,
320
+ sessionKey: thread.bridgeSessionKey,
321
+ });
322
+ }
323
+ catch (error) {
324
+ sequence.cancel();
325
+ return this.finalizeProbeResult(workspaceId, route.agentType, 'localcore-acp', prompt, collector, {
326
+ threadId: thread.id,
327
+ sessionKey: thread.bridgeSessionKey,
328
+ error: error instanceof Error ? error.message : String(error),
329
+ timedOut: error instanceof Error && error.message.includes('Timed out'),
330
+ });
331
+ }
332
+ finally {
333
+ await this.localCoreAcp.deleteThread(thread.id).catch(() => ({ deleted: false }));
334
+ }
335
+ }
336
+ async getWorkspaceRoute(workspaceId) {
337
+ const configState = await this.options.readConfigState();
338
+ const projects = Array.isArray(configState.parsed?.projects) ? configState.parsed.projects : [];
339
+ const matched = projects.find((project) => String(project?.name || '').trim() === workspaceId);
340
+ const route = matched ? this.resolveProjectRoute(configState, matched) : null;
341
+ if (!matched || !route) {
342
+ throw new Error(`Workspace "${workspaceId}" is not configured as a Local AI Core ACP workspace.`);
343
+ }
344
+ return route;
345
+ }
346
+ async listLocalCoreProjects() {
347
+ const configState = await this.options.readConfigState();
348
+ const projects = Array.isArray(configState.parsed?.projects) ? configState.parsed.projects : [];
349
+ return projects.filter((project) => this.resolveProjectRoute(configState, project));
350
+ }
351
+ resolveProjectRoute(configState, project) {
352
+ for (const runtime of this.options.getAgentRuntimes?.() || []) {
353
+ if (!runtime.matchesProject(project)) {
354
+ continue;
355
+ }
356
+ const route = runtime.createRoute(configState, project);
357
+ if (route) {
358
+ return {
359
+ ...route,
360
+ runtime,
361
+ };
362
+ }
363
+ }
364
+ if ((0, workspace_route_config_js_1.isLocalCoreNativeAcpProject)(project)) {
365
+ const agentType = String(project.agent?.type || '').trim().toLowerCase() || 'localcore-acp';
366
+ return {
367
+ kind: 'localcore-acp',
368
+ agentType,
369
+ transport: 'localcore-acp',
370
+ config: {
371
+ ...(0, workspace_route_config_js_1.toLocalCoreProjectConfig)(configState, project),
372
+ agentType,
373
+ },
374
+ supportsStreamingProbe: true,
375
+ runtime: {
376
+ agentType,
377
+ transport: 'localcore-acp',
378
+ matchesProject: () => true,
379
+ createRoute: () => null,
380
+ },
381
+ };
382
+ }
383
+ return null;
384
+ }
385
+ }
386
+ exports.WorkspaceRouter = WorkspaceRouter;
387
+ function createWorkspaceRouter(options) {
388
+ return new WorkspaceRouter(options);
389
+ }
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalCoreController = void 0;
4
+ const node_events_1 = require("node:events");
5
+ const desktop_js_1 = require("../../../../shared/desktop.js");
6
+ const bootstrap_js_1 = require("../kernel/bootstrap.js");
7
+ class LocalCoreController extends node_events_1.EventEmitter {
8
+ userDataPath;
9
+ state;
10
+ workspaceRouter;
11
+ knowledgeProvider;
12
+ channelRuntime;
13
+ weixinChannelRuntime;
14
+ scheduler;
15
+ kernel;
16
+ runtime;
17
+ busUnsubscribers = [];
18
+ constructor(userDataPath, runtime) {
19
+ super();
20
+ this.userDataPath = userDataPath;
21
+ this.runtime = runtime || (0, bootstrap_js_1.bootstrapLocalCoreRuntime)({
22
+ userDataPath,
23
+ localCoreBase: 'http://127.0.0.1:9831/api/local/v1',
24
+ log: (message) => this.handleLog(message),
25
+ });
26
+ this.state = this.runtime.state;
27
+ this.kernel = this.runtime.kernel;
28
+ this.knowledgeProvider = this.runtime.knowledgeProvider;
29
+ this.workspaceRouter = this.runtime.workspaceRouter;
30
+ this.channelRuntime = this.runtime.channelRuntime;
31
+ this.weixinChannelRuntime = this.runtime.weixinChannelRuntime;
32
+ this.scheduler = this.runtime.scheduler;
33
+ this.busUnsubscribers.push(this.kernel.context.bus.on('platform.bridge.updated', (event) => {
34
+ this.emit('bridge', event);
35
+ }), this.kernel.context.bus.on('scheduler.job.updated', (job) => {
36
+ this.emit('scheduler-job', job);
37
+ }), this.kernel.context.bus.on('scheduler.run.updated', (run) => {
38
+ this.emit('scheduler-run', run);
39
+ }), this.kernel.context.bus.on('runtime.state.changed', () => {
40
+ void this.emitRuntime();
41
+ }));
42
+ }
43
+ async init() {
44
+ await this.runtime.start();
45
+ await this.emitRuntime();
46
+ }
47
+ async close() {
48
+ for (const unsubscribe of this.busUnsubscribers) {
49
+ unsubscribe();
50
+ }
51
+ await this.runtime.stop();
52
+ }
53
+ async getRuntimeStatus() {
54
+ const service = {
55
+ status: 'running',
56
+ startedAt: new Date().toISOString(),
57
+ };
58
+ return {
59
+ mode: 'desktop',
60
+ phase: 'api_ready',
61
+ pendingRestart: false,
62
+ service,
63
+ roles: (0, desktop_js_1.deriveDesktopRuntimeRoles)(service),
64
+ settings: this.state.getSettings(),
65
+ configFile: await this.readConfigFile(),
66
+ logs: this.getLogs(200),
67
+ pluginDiagnostics: await this.getPluginDiagnostics(),
68
+ };
69
+ }
70
+ async startService() {
71
+ return { status: 'running' };
72
+ }
73
+ async stopService() {
74
+ return { status: 'running' };
75
+ }
76
+ async restartService() {
77
+ await this.channelRuntime.refreshBindings?.();
78
+ await this.weixinChannelRuntime.refreshBindings?.();
79
+ await this.emitRuntime();
80
+ return { status: 'running' };
81
+ }
82
+ getLogs(limit = 200) {
83
+ return this.state.getLogs(limit);
84
+ }
85
+ async readConfigFile() {
86
+ return this.state.readConfigFile();
87
+ }
88
+ async saveRawConfigFile(raw) {
89
+ const next = await this.state.saveRawConfigFile(raw);
90
+ await this.channelRuntime.refreshBindings?.();
91
+ await this.weixinChannelRuntime.refreshBindings?.();
92
+ await this.emitRuntime();
93
+ return next;
94
+ }
95
+ async saveStructuredConfigFile(config) {
96
+ const next = await this.state.saveStructuredConfigFile(config);
97
+ await this.channelRuntime.refreshBindings?.();
98
+ await this.weixinChannelRuntime.refreshBindings?.();
99
+ await this.emitRuntime();
100
+ return next;
101
+ }
102
+ async saveSettings(input) {
103
+ const settings = await this.state.saveSettings(input);
104
+ await this.channelRuntime.refreshBindings?.();
105
+ await this.weixinChannelRuntime.refreshBindings?.();
106
+ await this.emitRuntime();
107
+ return settings;
108
+ }
109
+ async listWorkspaces() {
110
+ return this.workspaceRouter.listWorkspaces();
111
+ }
112
+ async listScheduledJobs(workspaceId) {
113
+ return this.scheduler.listJobs(workspaceId);
114
+ }
115
+ async getScheduledJob(jobId) {
116
+ const job = this.scheduler.getJob(jobId);
117
+ if (!job) {
118
+ throw new Error(`Scheduled job not found: ${jobId}`);
119
+ }
120
+ return job;
121
+ }
122
+ async createScheduledJob(input) {
123
+ return this.scheduler.createJob(input);
124
+ }
125
+ async updateScheduledJob(jobId, input) {
126
+ return this.scheduler.updateJob(jobId, input);
127
+ }
128
+ async deleteScheduledJob(jobId) {
129
+ return this.scheduler.deleteJob(jobId);
130
+ }
131
+ async runScheduledJob(jobId) {
132
+ return this.scheduler.runJobNow(jobId);
133
+ }
134
+ async listScheduledJobRuns(jobId) {
135
+ return this.scheduler.listJobRuns(jobId);
136
+ }
137
+ async listThreads(workspaceId) {
138
+ return this.workspaceRouter.listThreads(workspaceId);
139
+ }
140
+ async createThread(workspaceId, title) {
141
+ return this.workspaceRouter.createThread(workspaceId, title);
142
+ }
143
+ async getThread(threadId) {
144
+ return this.workspaceRouter.getThread(threadId);
145
+ }
146
+ async renameThread(threadId, title) {
147
+ return this.workspaceRouter.renameThread(threadId, title);
148
+ }
149
+ async updateThreadKnowledgeBases(threadId, knowledgeBaseIds) {
150
+ return this.workspaceRouter.updateThreadKnowledgeBases(threadId, knowledgeBaseIds);
151
+ }
152
+ async deleteThread(threadId) {
153
+ return this.workspaceRouter.deleteThread(threadId);
154
+ }
155
+ async sendThreadMessage(threadId, content) {
156
+ return this.workspaceRouter.sendThreadMessage(threadId, content);
157
+ }
158
+ async sendThreadAction(threadId, content) {
159
+ return this.workspaceRouter.sendThreadAction(threadId, content);
160
+ }
161
+ async interruptRun(runId) {
162
+ return this.workspaceRouter.interruptRun(runId);
163
+ }
164
+ async listKnowledgeSources() {
165
+ return this.knowledgeProvider.listSources();
166
+ }
167
+ async getKnowledgeConfig() {
168
+ return this.knowledgeProvider.getConfig();
169
+ }
170
+ async updateKnowledgeConfig(input) {
171
+ return this.knowledgeProvider.updateConfig(input);
172
+ }
173
+ async listKnowledgeFolders() {
174
+ return this.knowledgeProvider.listFolders();
175
+ }
176
+ async createKnowledgeFolder(input) {
177
+ return this.knowledgeProvider.createFolder(input);
178
+ }
179
+ async updateKnowledgeFolder(id, input) {
180
+ return this.knowledgeProvider.updateFolder(id, input);
181
+ }
182
+ async deleteKnowledgeFolder(id) {
183
+ return this.knowledgeProvider.deleteFolder(id);
184
+ }
185
+ async listKnowledgeBases() {
186
+ return this.knowledgeProvider.listKnowledgeBases();
187
+ }
188
+ async getKnowledgeBase(id) {
189
+ return this.knowledgeProvider.getKnowledgeBase(id);
190
+ }
191
+ async createKnowledgeBase(input) {
192
+ return this.knowledgeProvider.createKnowledgeBase(input);
193
+ }
194
+ async updateKnowledgeBase(id, input) {
195
+ return this.knowledgeProvider.updateKnowledgeBase(id, input);
196
+ }
197
+ async deleteKnowledgeBase(id) {
198
+ return this.knowledgeProvider.deleteKnowledgeBase(id);
199
+ }
200
+ async listKnowledgeBaseFiles(knowledgeBaseId) {
201
+ return this.knowledgeProvider.listKnowledgeBaseFiles(knowledgeBaseId);
202
+ }
203
+ async uploadKnowledgeBaseFiles(knowledgeBaseId, request) {
204
+ return this.knowledgeProvider.uploadKnowledgeBaseFiles(knowledgeBaseId, request);
205
+ }
206
+ async deleteKnowledgeBaseFile(knowledgeBaseId, fileId) {
207
+ return this.knowledgeProvider.deleteKnowledgeBaseFile(knowledgeBaseId, fileId);
208
+ }
209
+ async searchKnowledgeBase(knowledgeBaseId, input) {
210
+ return this.knowledgeProvider.searchKnowledgeBase(knowledgeBaseId, input);
211
+ }
212
+ async getCapabilities() {
213
+ return this.kernel.getCapabilitySnapshot();
214
+ }
215
+ async getCapabilitySnapshot() {
216
+ return this.kernel.getCapabilitySnapshot().snapshot;
217
+ }
218
+ async getPluginDiagnostics() {
219
+ return this.kernel.diagnostics.snapshot();
220
+ }
221
+ async probeWorkspaceStreaming(workspaceId) {
222
+ return this.workspaceRouter.probeWorkspaceStreaming(workspaceId);
223
+ }
224
+ async listChannelGatewayStatuses(platform) {
225
+ if (!platform) {
226
+ const [larkStatuses, weixinStatuses] = await Promise.all([
227
+ this.channelRuntime.listStatuses(),
228
+ this.weixinChannelRuntime.listStatuses(),
229
+ ]);
230
+ return [...larkStatuses, ...weixinStatuses];
231
+ }
232
+ return this.resolveChannelRuntime(platform).listStatuses();
233
+ }
234
+ async getChannelGatewayStatus(platform, workspaceId) {
235
+ return this.resolveChannelRuntime(platform).getStatus(workspaceId);
236
+ }
237
+ async testChannelConnection(platform, workspaceId) {
238
+ return this.resolveChannelRuntime(platform).testConnection(workspaceId);
239
+ }
240
+ async enableChannelGateway(platform, workspaceId) {
241
+ return this.resolveChannelRuntime(platform).enable(workspaceId);
242
+ }
243
+ async disableChannelGateway(platform, workspaceId) {
244
+ return this.resolveChannelRuntime(platform).disable(workspaceId);
245
+ }
246
+ async listChannelPendingPairings(platform, workspaceId) {
247
+ return this.resolveChannelRuntime(platform).listPendingPairings(workspaceId);
248
+ }
249
+ async approveChannelPairing(platform, code) {
250
+ return this.resolveChannelRuntime(platform).approvePairing(code);
251
+ }
252
+ async rejectChannelPairing(platform, code) {
253
+ return this.resolveChannelRuntime(platform).rejectPairing(code);
254
+ }
255
+ async listChannelAuthorizedUsers(platform, workspaceId) {
256
+ return this.resolveChannelRuntime(platform).listAuthorizedUsers(workspaceId);
257
+ }
258
+ async getWeixinQrCode(workspaceId) {
259
+ const runtime = this.weixinChannelRuntime;
260
+ return runtime.getQrCode(workspaceId);
261
+ }
262
+ async checkWeixinQrCodeStatus(workspaceId, ticket) {
263
+ const runtime = this.weixinChannelRuntime;
264
+ return runtime.checkQrCodeStatus(workspaceId, ticket);
265
+ }
266
+ async listLarkGatewayStatuses() {
267
+ return this.listChannelGatewayStatuses('lark');
268
+ }
269
+ async getLarkGatewayStatus(workspaceId) {
270
+ return this.getChannelGatewayStatus('lark', workspaceId);
271
+ }
272
+ async testLarkConnection(workspaceId) {
273
+ return this.testChannelConnection('lark', workspaceId);
274
+ }
275
+ async enableLarkGateway(workspaceId) {
276
+ return this.enableChannelGateway('lark', workspaceId);
277
+ }
278
+ async disableLarkGateway(workspaceId) {
279
+ return this.disableChannelGateway('lark', workspaceId);
280
+ }
281
+ async listLarkPendingPairings(workspaceId) {
282
+ return this.listChannelPendingPairings('lark', workspaceId);
283
+ }
284
+ async approveLarkPairing(code) {
285
+ return this.approveChannelPairing('lark', code);
286
+ }
287
+ async rejectLarkPairing(code) {
288
+ return this.rejectChannelPairing('lark', code);
289
+ }
290
+ async listLarkAuthorizedUsers(workspaceId) {
291
+ return this.listChannelAuthorizedUsers('lark', workspaceId);
292
+ }
293
+ emitBridge(event) {
294
+ this.emit('bridge', event);
295
+ }
296
+ async emitRuntime() {
297
+ this.emit('runtime', await this.getRuntimeStatus());
298
+ }
299
+ handleLog(message) {
300
+ this.emit('logs', message);
301
+ }
302
+ resolveChannelRuntime(platform) {
303
+ if (platform === this.channelRuntime.platform) {
304
+ return this.channelRuntime;
305
+ }
306
+ if (platform === this.weixinChannelRuntime.platform) {
307
+ return this.weixinChannelRuntime;
308
+ }
309
+ throw new Error(`Unsupported channel platform: ${platform}`);
310
+ }
311
+ assertPlatform(platform) {
312
+ this.resolveChannelRuntime(platform);
313
+ }
314
+ }
315
+ exports.LocalCoreController = LocalCoreController;