@kafca/agentdock 0.1.41 → 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 (102) hide show
  1. package/README.md +10 -0
  2. package/dist/renderer/assets/{Badge-BX3RC8l6.js → Badge-CbG6yRSm.js} +1 -1
  3. package/dist/renderer/assets/{Chat-DJwIciel.js → Chat-BvNNWGGX.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-DfGbRR0S.js → ChatMarkdown-Ct-PvJB8.js} +1 -1
  5. package/dist/renderer/assets/{Config-2x2RDL3j.js → Config-lQX2qVVV.js} +2 -2
  6. package/dist/renderer/assets/CronList-Dj_3muVG.js +1 -0
  7. package/dist/renderer/assets/{Dashboard-2Wcx_bvJ.js → Dashboard-eh_RhGYb.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-DoCpF2tn.js → EmptyState-Bn2Qh14U.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-CBRu2bXX.js → KnowledgeDetail-Bsz6Ou41.js} +2 -2
  10. package/dist/renderer/assets/{KnowledgeHome-CItdlDVR.js → KnowledgeHome-Cgj4XFXn.js} +2 -2
  11. package/dist/renderer/assets/{Logs-Cd_7ZOXc.js → Logs-Dp-NF6GN.js} +1 -1
  12. package/dist/renderer/assets/{Modal-B4eOiBsB.js → Modal-B6YPPBN6.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-xEZWg460.js +1 -0
  14. package/dist/renderer/assets/{Page-C5VH4D9U.js → Page-Bn7RjGOS.js} +1 -1
  15. package/dist/renderer/assets/{ProjectDetail-D_DA--IP.js → ProjectDetail-Cv_jIE61.js} +2 -2
  16. package/dist/renderer/assets/{ProjectList-CtCXJ50u.js → ProjectList-BDk5_gqY.js} +1 -1
  17. package/dist/renderer/assets/{Select-B6E68LcN.js → Select-xshfMIEQ.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-BkHy90z3.js +1 -0
  19. package/dist/renderer/assets/{SessionList-Do-5-Xx6.js → SessionList-BZyXT92L.js} +1 -1
  20. package/dist/renderer/assets/{ThreadChat-B1tEtE3V.js → ThreadChat-DUOIyXrS.js} +7 -7
  21. package/dist/renderer/assets/{Workspace-BlhS2RFw.js → Workspace-Dl80fNEC.js} +1 -1
  22. package/dist/renderer/assets/{arrow-left-DF1_F9Pk.js → arrow-left-C54ZI-AS.js} +1 -1
  23. package/dist/renderer/assets/{book-open-DxRTGpWO.js → book-open-Dl7GO0zn.js} +1 -1
  24. package/dist/renderer/assets/{check-BAqPPYkf.js → check-CiqgtrOL.js} +1 -1
  25. package/dist/renderer/assets/{chevron-down-DIZZgSb3.js → chevron-down-DTL2OuVh.js} +1 -1
  26. package/dist/renderer/assets/{circle-B5raL_XK.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-BPjLpVSB.js → funnel-CrmnLMJI.js} +1 -1
  31. package/dist/renderer/assets/{heart-D2M1xN1N.js → heart-BMfQI7y_.js} +1 -1
  32. package/dist/renderer/assets/{index-Cx71F_Lz.js → index-HPNb1zfx.js} +39 -34
  33. package/dist/renderer/assets/{index-BijJAYmo.js → index-nreiKY1f.js} +3 -3
  34. package/dist/renderer/assets/{pencil-DlDr8Mmp.js → pencil-wTQ4l465.js} +1 -1
  35. package/dist/renderer/assets/{play-BOEG_mY8.js → play-BK--MXmw.js} +1 -1
  36. package/dist/renderer/assets/{plug-BI27elC-.js → plug-BIx9fjip.js} +1 -1
  37. package/dist/renderer/assets/{plus-BhURuFIQ.js → plus-Dn7JFWQ8.js} +1 -1
  38. package/dist/renderer/assets/projects-brJZgwEJ.js +1 -0
  39. package/dist/renderer/assets/{save-RwkHNm9e.js → save-CC3zOSWb.js} +1 -1
  40. package/dist/renderer/assets/{search-DMNtm2WP.js → search-CDTy9Czu.js} +1 -1
  41. package/dist/renderer/assets/{server-CNaxKyAq.js → server-DtQk3t2a.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-vsALZkZN.js → session-utils-4ep5D66T.js} +1 -1
  43. package/dist/renderer/assets/{sessions-BY-R1IL_.js → sessions-Dor1LteH.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-BF-4oJbj.js → shield-check-Cz2LpU6r.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-DduflM4q.js → trash-2-C2EmWFZV.js} +1 -1
  46. package/dist/renderer/assets/{user-DBcvnuW4.js → user-I8B-cs5A.js} +1 -1
  47. package/dist/renderer/assets/{wifi-off-X1nXESYu.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 +76 -39
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +13 -0
  54. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +4 -1357
  55. package/dist-electron/services/local-ai-core/src/acp/local-core-slash-commands.js +28 -0
  56. package/dist-electron/services/local-ai-core/src/acp/store/agent-task-store.js +166 -0
  57. package/dist-electron/services/local-ai-core/src/acp/store/automation-monitor-store.js +231 -0
  58. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +263 -0
  59. package/dist-electron/services/local-ai-core/src/acp/store/platform-store.js +186 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/scheduler-store.js +201 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +275 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/security-store.js +266 -0
  63. package/dist-electron/services/local-ai-core/src/acp/store/thread-store.js +232 -0
  64. package/dist-electron/services/local-ai-core/src/acp/store/utils.js +47 -0
  65. package/dist-electron/services/local-ai-core/src/acp/store/workspace-registry-store.js +109 -0
  66. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +136 -0
  67. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-repository.js +56 -0
  68. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +359 -0
  69. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +77 -0
  70. package/dist-electron/services/local-ai-core/src/automation/mock-stock-provider.js +40 -0
  71. package/dist-electron/services/local-ai-core/src/automation/monitor-id.js +10 -0
  72. package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +55 -0
  73. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +101 -29
  74. package/dist-electron/services/local-ai-core/src/channel/shared/session-command-runtime.js +53 -0
  75. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +51 -33
  76. package/dist-electron/services/local-ai-core/src/cli/lac.js +196 -0
  77. package/dist-electron/services/local-ai-core/src/cli/monitor-cli-parsers.js +37 -0
  78. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +43 -0
  79. package/dist-electron/services/local-ai-core/src/kernel/capability-registry.js +12 -0
  80. package/dist-electron/services/local-ai-core/src/plugins/builtin/monitor-stock-plugin.js +30 -0
  81. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +40 -4
  82. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +41 -0
  83. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +31 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/server.js +36 -0
  85. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-bridge-session.js +25 -11
  86. package/dist-electron/services/local-ai-core/src/thread/session-command-service.js +275 -0
  87. package/dist-electron/services/local-ai-core/src/thread/slash-command-registry.js +27 -0
  88. package/dist-electron/services/local-ai-core/src/thread/thread-command-service.js +134 -0
  89. package/dist-electron/shared/desktop.js +21 -1
  90. package/dist-electron/tests/contracts/local-core-contracts.test.js +9 -0
  91. package/dist-electron/tests/electron/automation-monitor.test.js +38 -0
  92. package/dist-electron/tests/electron/lac-cli.test.js +146 -0
  93. package/dist-electron/tests/electron/plugin-kernel.test.js +26 -0
  94. package/dist-electron/tests/integration/local-core-refactor.test.js +359 -0
  95. package/package.json +1 -1
  96. package/dist/renderer/assets/CronList-C6nPAmEo.js +0 -1
  97. package/dist/renderer/assets/SessionChat-D1HtMdQS.js +0 -1
  98. package/dist/renderer/assets/desktop-CFcnzwcY.js +0 -1
  99. package/dist/renderer/assets/desktop-O8_6ZCVZ.js +0 -4
  100. package/dist/renderer/assets/en-CKhCF6St.js +0 -1
  101. package/dist/renderer/assets/projects-DpR972HM.js +0 -1
  102. package/dist/renderer/assets/zh-Dz5FLTBV.js +0 -1
@@ -17,10 +17,12 @@ const scheduler_cron_plugin_js_1 = require("../plugins/builtin/scheduler-cron-pl
17
17
  const scheduler_lark_plugin_js_1 = require("../plugins/builtin/scheduler-lark-plugin.js");
18
18
  const scheduler_local_plugin_js_1 = require("../plugins/builtin/scheduler-local-plugin.js");
19
19
  const scheduler_weixin_plugin_js_1 = require("../plugins/builtin/scheduler-weixin-plugin.js");
20
+ const monitor_stock_plugin_js_1 = require("../plugins/builtin/monitor-stock-plugin.js");
20
21
  const workspace_router_js_1 = require("../router/workspace-router.js");
21
22
  const local_core_runtime_state_js_1 = require("../runtime/local-core-runtime-state.js");
22
23
  const scheduled_job_application_service_js_1 = require("../scheduler/scheduled-job-application-service.js");
23
24
  const scheduler_service_js_1 = require("../scheduler/scheduler-service.js");
25
+ const automation_monitor_service_js_1 = require("../automation/automation-monitor-service.js");
24
26
  function bootstrapLocalCoreKernel(options) {
25
27
  const capabilities = new capability_registry_js_1.LocalCoreCapabilityRegistry();
26
28
  const plugins = new plugin_registry_js_1.LocalCorePluginRegistry(options?.disabledPluginIds);
@@ -59,6 +61,7 @@ function bootstrapLocalCoreKernel(options) {
59
61
  diagnostics,
60
62
  getCapabilitySnapshot() {
61
63
  const snapshot = capabilities.snapshot();
64
+ const monitorCapabilities = snapshot.monitors || [];
62
65
  return {
63
66
  adapters: {
64
67
  channels: snapshot.channels.map((capability) => capability.platform),
@@ -74,6 +77,14 @@ function bootstrapLocalCoreKernel(options) {
74
77
  deliveryTargets: [...new Set(snapshot.schedulers.flatMap((capability) => capability.deliveryTargets || capability.deliveryPlatforms || []))],
75
78
  platforms: [...new Set(snapshot.schedulers.flatMap((capability) => capability.deliveryTargets || capability.deliveryPlatforms || []))],
76
79
  },
80
+ ...(monitorCapabilities.length > 0
81
+ ? {
82
+ monitors: {
83
+ enabled: monitorCapabilities.some((capability) => capability.enabled !== false),
84
+ sourceTypes: [...new Set(monitorCapabilities.flatMap((capability) => capability.sourceTypes))],
85
+ },
86
+ }
87
+ : {}),
77
88
  snapshot,
78
89
  };
79
90
  },
@@ -99,6 +110,7 @@ function logCapabilityContributions(plugin, log) {
99
110
  ...(plugin.capabilities.channels || []).map((capability) => capability.id),
100
111
  ...(plugin.capabilities.knowledge || []).map((capability) => capability.id),
101
112
  ...(plugin.capabilities.schedulers || []).map((capability) => capability.id),
113
+ ...(plugin.capabilities.monitors || []).map((capability) => capability.id),
102
114
  ...(plugin.capabilities.ui || []).map((capability) => capability.id),
103
115
  ];
104
116
  for (const capabilityId of capabilityIds) {
@@ -145,6 +157,16 @@ function resolveSchedulerRuntime(plugin, context) {
145
157
  }
146
158
  return runtime;
147
159
  }
160
+ function resolveMonitorRuntime(plugin, context) {
161
+ if (!plugin.createRuntime) {
162
+ throw new Error(`Monitor plugin ${plugin.manifest.id} does not provide a runtime factory.`);
163
+ }
164
+ const runtime = plugin.createRuntime(context);
165
+ if (runtime instanceof Promise) {
166
+ throw new Error(`Monitor plugin ${plugin.manifest.id} returned an async runtime factory during synchronous bootstrap.`);
167
+ }
168
+ return runtime;
169
+ }
148
170
  function bootstrapLocalCoreRuntime(options) {
149
171
  const state = (0, local_core_runtime_state_js_1.createLocalCoreRuntimeState)({
150
172
  userDataPath: options.userDataPath,
@@ -209,6 +231,9 @@ function bootstrapLocalCoreRuntime(options) {
209
231
  log: options.log,
210
232
  }),
211
233
  ];
234
+ const monitorPlugins = [
235
+ (0, monitor_stock_plugin_js_1.createBuiltinStockMonitorPlugin)(),
236
+ ];
212
237
  for (const plugin of agentPlugins.filter((plugin) => plugin !== localCoreAgentPlugin)) {
213
238
  registerPlugin(kernel, plugin);
214
239
  }
@@ -218,6 +243,9 @@ function bootstrapLocalCoreRuntime(options) {
218
243
  for (const plugin of schedulerPlugins) {
219
244
  registerPlugin(kernel, plugin);
220
245
  }
246
+ for (const plugin of monitorPlugins) {
247
+ registerPlugin(kernel, plugin);
248
+ }
221
249
  const agentRuntimes = agentPlugins
222
250
  .filter((plugin) => kernel.plugins.isEnabled(plugin.manifest.id))
223
251
  .map((plugin) => resolveAgentRuntime(plugin, kernel.context).runtime);
@@ -241,6 +269,10 @@ function bootstrapLocalCoreRuntime(options) {
241
269
  ];
242
270
  const schedulerTriggers = schedulerRuntimes.flatMap((runtime) => runtime.triggers || []);
243
271
  const schedulerExecutors = schedulerRuntimes.flatMap((runtime) => runtime.executors || []);
272
+ const monitorRuntimes = monitorPlugins
273
+ .filter((plugin) => kernel.plugins.isEnabled(plugin.manifest.id))
274
+ .map((plugin) => resolveMonitorRuntime(plugin, kernel.context));
275
+ const monitorProviders = monitorRuntimes.flatMap((runtime) => runtime.providers || []);
244
276
  const knowledgeProvider = knowledgeRuntime.provider;
245
277
  const knowledgeAttachments = knowledgeRuntime.attachments;
246
278
  workspaceRouter = (0, workspace_router_js_1.createWorkspaceRouter)({
@@ -266,6 +298,14 @@ function bootstrapLocalCoreRuntime(options) {
266
298
  store,
267
299
  scheduler,
268
300
  });
301
+ const automationMonitors = new automation_monitor_service_js_1.AutomationMonitorService({
302
+ store,
303
+ providers: monitorProviders,
304
+ getWorkspaceRouter: () => workspaceRouter,
305
+ getChannelRuntime: (platform) => channelRuntimes.find((runtime) => runtime.platform === platform || platform.startsWith(`${runtime.platform}:`)),
306
+ eventBus: kernel.context.bus,
307
+ log: options.log,
308
+ });
269
309
  workspaceRouter.setSchedulerBridge({
270
310
  createJob: async ({ workspaceId, platform, route, name, schedule, scheduleDescription, message }) => scheduledJobs.createCronJob({ workspaceId, platform, route, name, schedule, scheduleDescription, message }),
271
311
  listJobsForThread: async (threadId) => scheduledJobs.listJobsForThread(threadId),
@@ -286,11 +326,14 @@ function bootstrapLocalCoreRuntime(options) {
286
326
  workspaceRouter,
287
327
  scheduler,
288
328
  scheduledJobs,
329
+ automationMonitors,
289
330
  async start() {
290
331
  await kernel.lifecycle.startAll();
291
332
  await scheduler.start();
333
+ await automationMonitors.start();
292
334
  },
293
335
  async stop() {
336
+ await automationMonitors.stop();
294
337
  await scheduler.stop();
295
338
  await kernel.lifecycle.stopAll();
296
339
  workspaceRouter.close();
@@ -6,6 +6,7 @@ class LocalCoreCapabilityRegistry {
6
6
  channels = new Map();
7
7
  knowledge = new Map();
8
8
  schedulers = new Map();
9
+ monitors = new Map();
9
10
  ui = new Map();
10
11
  registerAgent(capability) {
11
12
  this.agents.set(capability.id, capability);
@@ -19,6 +20,9 @@ class LocalCoreCapabilityRegistry {
19
20
  registerScheduler(capability) {
20
21
  this.schedulers.set(capability.id, capability);
21
22
  }
23
+ registerMonitor(capability) {
24
+ this.monitors.set(capability.id, capability);
25
+ }
22
26
  registerUi(capability) {
23
27
  this.ui.set(capability.id, capability);
24
28
  }
@@ -35,6 +39,9 @@ class LocalCoreCapabilityRegistry {
35
39
  for (const capability of contributions.schedulers || []) {
36
40
  this.registerScheduler(capability);
37
41
  }
42
+ for (const capability of contributions.monitors || []) {
43
+ this.registerMonitor(capability);
44
+ }
38
45
  for (const capability of contributions.ui || []) {
39
46
  this.registerUi(capability);
40
47
  }
@@ -51,15 +58,20 @@ class LocalCoreCapabilityRegistry {
51
58
  listSchedulers() {
52
59
  return [...this.schedulers.values()];
53
60
  }
61
+ listMonitors() {
62
+ return [...this.monitors.values()];
63
+ }
54
64
  listUi() {
55
65
  return [...this.ui.values()];
56
66
  }
57
67
  snapshot() {
68
+ const monitors = this.listMonitors();
58
69
  return {
59
70
  agents: this.listAgents(),
60
71
  channels: this.listChannels(),
61
72
  knowledge: this.listKnowledge(),
62
73
  schedulers: this.listSchedulers(),
74
+ ...(monitors.length > 0 ? { monitors } : {}),
63
75
  ui: this.listUi(),
64
76
  };
65
77
  }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBuiltinStockMonitorPlugin = createBuiltinStockMonitorPlugin;
4
+ const mock_stock_provider_js_1 = require("../../automation/mock-stock-provider.js");
5
+ function createBuiltinStockMonitorPlugin() {
6
+ return {
7
+ manifest: {
8
+ id: 'builtin.monitor-stock',
9
+ kind: 'monitor',
10
+ version: '0.1.0',
11
+ provides: ['monitor.source.stock.quote'],
12
+ },
13
+ capabilities: {
14
+ monitors: [
15
+ {
16
+ id: 'monitor.source.stock.quote',
17
+ sourceTypes: ['stock.quote'],
18
+ modes: ['poll'],
19
+ enabled: true,
20
+ displayName: 'Stock Quote Monitor',
21
+ },
22
+ ],
23
+ },
24
+ createRuntime() {
25
+ return {
26
+ providers: [new mock_stock_provider_js_1.MockStockQuoteProvider()],
27
+ };
28
+ },
29
+ };
30
+ }
@@ -48,6 +48,7 @@ class WorkspaceRouter {
48
48
  return this.schedulerBridge.deleteJob(jobId);
49
49
  },
50
50
  },
51
+ getAgentTypes: () => this.options.getCapabilities().snapshot.agents.map((agent) => agent.agentType),
51
52
  log: options.log,
52
53
  });
53
54
  }
@@ -203,12 +204,14 @@ class WorkspaceRouter {
203
204
  }
204
205
  async sendThreadMessage(threadId, content, options) {
205
206
  const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
206
- const route = await this.getWorkspaceRoute(workspaceId);
207
+ const route = isLocalSlashCommand(content)
208
+ ? await this.getWorkspaceRoute(workspaceId)
209
+ : await this.getThreadWorkspaceRoute(threadId, workspaceId);
207
210
  return this.localCoreAcp.sendThreadMessage(threadId, content, route.config, options);
208
211
  }
209
212
  async sendThreadAction(threadId, content) {
210
213
  const { workspaceId } = (0, workspace_thread_id_js_1.decodeThreadId)(threadId);
211
- const route = await this.getWorkspaceRoute(workspaceId);
214
+ const route = await this.getThreadWorkspaceRoute(threadId, workspaceId);
212
215
  return this.localCoreAcp.sendThreadAction(threadId, content, route.config);
213
216
  }
214
217
  async interruptRun(runId) {
@@ -425,11 +428,21 @@ class WorkspaceRouter {
425
428
  await this.localCoreAcp.deleteThread(thread.id).catch(() => ({ deleted: false }));
426
429
  }
427
430
  }
428
- async getWorkspaceRoute(workspaceId) {
431
+ async getThreadWorkspaceRoute(threadId, workspaceId) {
432
+ const defaultRoute = await this.getWorkspaceRoute(workspaceId);
433
+ const row = this.store.getThreadRow(threadId);
434
+ const threadAgentType = String(row?.agent_type || '').trim().toLowerCase();
435
+ if (!threadAgentType || threadAgentType === defaultRoute.agentType) {
436
+ return defaultRoute;
437
+ }
438
+ return this.getWorkspaceRoute(workspaceId, threadAgentType);
439
+ }
440
+ async getWorkspaceRoute(workspaceId, agentTypeOverride = '') {
429
441
  const configState = await this.options.readConfigState();
430
442
  const projects = Array.isArray(configState.parsed?.projects) ? configState.parsed.projects : [];
431
443
  const matched = projects.find((project) => String(project?.name || '').trim() === workspaceId);
432
- const route = matched ? this.resolveProjectRoute(configState, matched) : null;
444
+ const project = matched && agentTypeOverride ? withAgentTypeOverride(matched, agentTypeOverride) : matched;
445
+ const route = project ? this.resolveProjectRoute(configState, project) : null;
433
446
  if (!matched || !route) {
434
447
  throw new Error(`Workspace "${workspaceId}" is not configured as a Local AI Core ACP workspace.`);
435
448
  }
@@ -512,6 +525,29 @@ function inferWorkspacePath(project) {
512
525
  }
513
526
  return '';
514
527
  }
528
+ function withAgentTypeOverride(project, agentType) {
529
+ const options = project.agent?.options && typeof project.agent.options === 'object'
530
+ ? { ...project.agent.options }
531
+ : {};
532
+ delete options.command;
533
+ delete options.args;
534
+ return {
535
+ ...project,
536
+ agent: {
537
+ ...(project.agent || {}),
538
+ type: agentType,
539
+ options,
540
+ },
541
+ };
542
+ }
543
+ function isLocalSlashCommand(content) {
544
+ const text = typeof content === 'string' ? content : String(content.displayText || '');
545
+ const normalized = text.trim().toLowerCase();
546
+ return normalized === '/agent'
547
+ || normalized.startsWith('/agent ')
548
+ || normalized === '/mode'
549
+ || normalized.startsWith('/mode ');
550
+ }
515
551
  function workspaceHealth(path) {
516
552
  if (!path) {
517
553
  return {
@@ -12,6 +12,7 @@ class LocalCoreController extends node_events_1.EventEmitter {
12
12
  knowledgeProvider;
13
13
  channelRuntimes;
14
14
  scheduledJobs;
15
+ automationMonitors;
15
16
  kernel;
16
17
  runtime;
17
18
  runtimeDetection;
@@ -33,6 +34,15 @@ class LocalCoreController extends node_events_1.EventEmitter {
33
34
  const runtimeChannels = this.runtime.channelRuntimes || [this.runtime.channelRuntime, this.runtime.weixinChannelRuntime];
34
35
  this.channelRuntimes = new Map(runtimeChannels.filter(Boolean).map((runtime) => [runtime.platform, runtime]));
35
36
  this.scheduledJobs = this.runtime.scheduledJobs;
37
+ this.automationMonitors = this.runtime.automationMonitors || {
38
+ listMonitors: () => [],
39
+ getMonitor: () => undefined,
40
+ createMonitor: () => { throw new Error('Automation monitor service is not available.'); },
41
+ updateMonitor: () => { throw new Error('Automation monitor service is not available.'); },
42
+ deleteMonitor: () => ({ deleted: false }),
43
+ runMonitorNow: async () => { throw new Error('Automation monitor service is not available.'); },
44
+ listRuns: () => [],
45
+ };
36
46
  this.runtimeDetection = new runtime_detection_service_js_1.RuntimeDetectionService({
37
47
  userDataPath,
38
48
  readConfig: async () => (await this.readConfigFile()).parsed,
@@ -42,10 +52,16 @@ class LocalCoreController extends node_events_1.EventEmitter {
42
52
  this.flushPendingLogs();
43
53
  this.busUnsubscribers.push(this.kernel.context.bus.on('platform.bridge.updated', (event) => {
44
54
  this.emit('bridge', event);
55
+ }), this.kernel.context.bus.on('thread.session.activated', (event) => {
56
+ this.emit('thread-session-activated', event);
45
57
  }), this.kernel.context.bus.on('scheduler.job.updated', (job) => {
46
58
  this.emit('scheduler-job', job);
47
59
  }), this.kernel.context.bus.on('scheduler.run.updated', (run) => {
48
60
  this.emit('scheduler-run', run);
61
+ }), this.kernel.context.bus.on('automation.monitor.updated', (monitor) => {
62
+ this.emit('automation-monitor', monitor);
63
+ }), this.kernel.context.bus.on('automation.monitor.run.updated', (run) => {
64
+ this.emit('automation-monitor-run', run);
49
65
  }), this.kernel.context.bus.on('runtime.state.changed', () => {
50
66
  void this.emitRuntime();
51
67
  }));
@@ -208,6 +224,31 @@ class LocalCoreController extends node_events_1.EventEmitter {
208
224
  async listScheduledJobRuns(jobId) {
209
225
  return this.scheduledJobs.listJobRuns(jobId);
210
226
  }
227
+ async listAutomationMonitors(workspaceId) {
228
+ return this.automationMonitors.listMonitors(workspaceId);
229
+ }
230
+ async getAutomationMonitor(monitorId) {
231
+ const monitor = this.automationMonitors.getMonitor(monitorId);
232
+ if (!monitor) {
233
+ throw new Error(`Automation monitor not found: ${monitorId}`);
234
+ }
235
+ return monitor;
236
+ }
237
+ async createAutomationMonitor(input) {
238
+ return this.automationMonitors.createMonitor(input);
239
+ }
240
+ async updateAutomationMonitor(monitorId, input) {
241
+ return this.automationMonitors.updateMonitor(monitorId, input);
242
+ }
243
+ async deleteAutomationMonitor(monitorId) {
244
+ return this.automationMonitors.deleteMonitor(monitorId);
245
+ }
246
+ async runAutomationMonitor(monitorId) {
247
+ return this.automationMonitors.runMonitorNow(monitorId);
248
+ }
249
+ async listAutomationMonitorRuns(monitorId) {
250
+ return this.automationMonitors.listRuns(monitorId);
251
+ }
211
252
  async listThreads(workspaceId) {
212
253
  return this.workspaceRouter.listThreads(workspaceId);
213
254
  }
@@ -48,6 +48,9 @@ function parseLocalAiCoreRoute(method, path) {
48
48
  if (segments[0] === 'scheduler' && segments[1] === 'jobs') {
49
49
  return parseSchedulerJobsRoute(normalizedMethod, segments);
50
50
  }
51
+ if (segments[0] === 'automation' && segments[1] === 'monitors') {
52
+ return parseAutomationMonitorsRoute(normalizedMethod, segments);
53
+ }
51
54
  if (segments[0] === 'threads') {
52
55
  return parseThreadsRoute(normalizedMethod, segments);
53
56
  }
@@ -92,6 +95,34 @@ function parseLocalAiCoreRoute(method, path) {
92
95
  }
93
96
  return null;
94
97
  }
98
+ function parseAutomationMonitorsRoute(method, segments) {
99
+ if (method === 'GET' && segments.length === 2) {
100
+ return { name: 'automation.monitors.list' };
101
+ }
102
+ if (method === 'POST' && segments.length === 2) {
103
+ return { name: 'automation.monitors.create' };
104
+ }
105
+ const monitorId = segments.length >= 3 ? decodeURIComponent(segments[2] || '') : '';
106
+ if (!monitorId) {
107
+ return null;
108
+ }
109
+ if (method === 'GET' && segments.length === 3) {
110
+ return { name: 'automation.monitor.get', monitorId };
111
+ }
112
+ if (method === 'GET' && segments.length === 4 && segments[3] === 'runs') {
113
+ return { name: 'automation.monitor.runs', monitorId };
114
+ }
115
+ if (method === 'POST' && segments.length === 4 && segments[3] === 'run') {
116
+ return { name: 'automation.monitor.run', monitorId };
117
+ }
118
+ if (method === 'PATCH' && segments.length === 3) {
119
+ return { name: 'automation.monitor.update', monitorId };
120
+ }
121
+ if (method === 'DELETE' && segments.length === 3) {
122
+ return { name: 'automation.monitor.delete', monitorId };
123
+ }
124
+ return null;
125
+ }
95
126
  function parseRuntimesRoute(method, segments) {
96
127
  if (method === 'GET' && segments.length === 1) {
97
128
  return { name: 'runtimes.list' };
@@ -62,12 +62,21 @@ class LocalAiCoreServer {
62
62
  });
63
63
  }
64
64
  });
65
+ this.bindings.on('thread-session-activated', (event) => {
66
+ this.broadcast({ type: 'thread.session.activated', ...event });
67
+ });
65
68
  this.bindings.on('scheduler-job', (job) => {
66
69
  this.broadcast({ type: 'scheduler.job.updated', job });
67
70
  });
68
71
  this.bindings.on('scheduler-run', (run) => {
69
72
  this.broadcast({ type: 'scheduler.run.updated', run });
70
73
  });
74
+ this.bindings.on('automation-monitor', (monitor) => {
75
+ this.broadcast({ type: 'automation.monitor.updated', monitor });
76
+ });
77
+ this.bindings.on('automation-monitor-run', (run) => {
78
+ this.broadcast({ type: 'automation.monitor.run.updated', run });
79
+ });
71
80
  this.bindings.on('runtime-detection', (event) => {
72
81
  this.broadcast(event);
73
82
  });
@@ -226,6 +235,33 @@ class LocalAiCoreServer {
226
235
  case 'scheduler.job.delete':
227
236
  json(res, 200, await this.bindings.deleteScheduledJob(route.jobId));
228
237
  return;
238
+ case 'automation.monitors.list': {
239
+ const workspaceId = String(url.searchParams.get('workspace_id') || '');
240
+ json(res, 200, { monitors: await this.bindings.listAutomationMonitors(workspaceId || undefined) });
241
+ return;
242
+ }
243
+ case 'automation.monitors.create': {
244
+ const body = await readJsonBody(req);
245
+ json(res, 200, await this.bindings.createAutomationMonitor(body));
246
+ return;
247
+ }
248
+ case 'automation.monitor.get':
249
+ json(res, 200, await this.bindings.getAutomationMonitor(route.monitorId));
250
+ return;
251
+ case 'automation.monitor.runs':
252
+ json(res, 200, { runs: await this.bindings.listAutomationMonitorRuns(route.monitorId) });
253
+ return;
254
+ case 'automation.monitor.run':
255
+ json(res, 200, await this.bindings.runAutomationMonitor(route.monitorId));
256
+ return;
257
+ case 'automation.monitor.update': {
258
+ const body = await readJsonBody(req);
259
+ json(res, 200, await this.bindings.updateAutomationMonitor(route.monitorId, body));
260
+ return;
261
+ }
262
+ case 'automation.monitor.delete':
263
+ json(res, 200, await this.bindings.deleteAutomationMonitor(route.monitorId));
264
+ return;
229
265
  case 'threads.list': {
230
266
  const workspaceId = String(url.searchParams.get('workspace_id') || '');
231
267
  json(res, 200, { threads: workspaceId ? await this.bindings.listThreads(workspaceId) : [] });
@@ -5,19 +5,20 @@ class ScheduledBridgeSession {
5
5
  static async open(input) {
6
6
  const sessionKey = input.workspaceRouter.getThreadSessionKey(input.threadId);
7
7
  const channelRuntime = input.getChannelRuntime();
8
+ const target = input.target || targetFromScheduledJob(input.job);
8
9
  const unregister = await channelRuntime.registerScheduledThreadBridge?.({
9
- workspaceId: input.job.workspaceId,
10
- platform: input.job.platform,
11
- route: input.job.route,
10
+ workspaceId: target.workspaceId,
11
+ platform: target.platform,
12
+ route: target.route,
12
13
  threadId: input.threadId,
13
14
  sessionKey,
14
15
  });
15
- await sendScheduledStartNotice(channelRuntime, input.job, sessionKey);
16
+ await sendScheduledStartNotice(channelRuntime, target, sessionKey, input.noticeIcon, input.noticeTitle);
16
17
  return {
17
18
  mode: 'bridge-stream',
18
- workspaceId: input.job.workspaceId,
19
- platform: input.job.platform,
20
- route: input.job.route,
19
+ workspaceId: target.workspaceId,
20
+ platform: target.platform,
21
+ route: target.route,
21
22
  threadId: input.threadId,
22
23
  sessionKey,
23
24
  close: async () => {
@@ -27,7 +28,20 @@ class ScheduledBridgeSession {
27
28
  }
28
29
  }
29
30
  exports.ScheduledBridgeSession = ScheduledBridgeSession;
30
- async function sendScheduledStartNotice(channelRuntime, job, sessionKey) {
31
+ function targetFromScheduledJob(job) {
32
+ if (!job) {
33
+ throw new Error('Scheduled bridge session requires a job or automation target.');
34
+ }
35
+ return {
36
+ id: job.id,
37
+ workspaceId: job.workspaceId,
38
+ platform: job.platform,
39
+ route: job.route,
40
+ title: job.description || job.promptTemplate || job.id,
41
+ promptTemplate: job.promptTemplate,
42
+ };
43
+ }
44
+ async function sendScheduledStartNotice(channelRuntime, target, sessionKey, noticeIcon, noticeTitle) {
31
45
  if (!channelRuntime.onBridgeEvent) {
32
46
  return;
33
47
  }
@@ -36,15 +50,15 @@ async function sendScheduledStartNotice(channelRuntime, job, sessionKey) {
36
50
  type: 'status',
37
51
  sessionKey,
38
52
  bridgeKind: 'status',
39
- content: `⏰ ${scheduledNoticeTitle(job)}`,
53
+ content: `${noticeIcon || '⏰'} ${noticeTitle || automationNoticeTitle(target)}`,
40
54
  });
41
55
  }
42
56
  catch {
43
57
  // The scheduled run should continue even if the proactive start notice fails.
44
58
  }
45
59
  }
46
- function scheduledNoticeTitle(job) {
47
- const title = normalizeNoticeTitle(job.description) || normalizeNoticeTitle(job.promptTemplate) || job.id;
60
+ function automationNoticeTitle(target) {
61
+ const title = normalizeNoticeTitle(target.title) || normalizeNoticeTitle(target.promptTemplate) || target.id;
48
62
  return truncateNoticeTitle(title, 80);
49
63
  }
50
64
  function normalizeNoticeTitle(value) {