@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
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AutomationMonitorService = void 0;
4
+ const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
5
+ const condition_evaluator_js_1 = require("./condition-evaluator.js");
6
+ const automation_conversation_executor_js_1 = require("./automation-conversation-executor.js");
7
+ const automation_monitor_repository_js_1 = require("./automation-monitor-repository.js");
8
+ class AutomationMonitorService {
9
+ options;
10
+ timer = null;
11
+ pollInFlight = false;
12
+ runningMonitors = new Set();
13
+ subscriptionHandles = new Map();
14
+ providers = new Map();
15
+ executor;
16
+ repository;
17
+ constructor(options) {
18
+ this.options = options;
19
+ for (const provider of options.providers) {
20
+ this.providers.set(provider.sourceType, provider);
21
+ }
22
+ this.repository = new automation_monitor_repository_js_1.AutomationMonitorRepository(options.store);
23
+ this.executor = new automation_conversation_executor_js_1.AutomationConversationExecutor({
24
+ store: options.store,
25
+ getWorkspaceRouter: options.getWorkspaceRouter,
26
+ getChannelRuntime: options.getChannelRuntime,
27
+ });
28
+ }
29
+ async start() {
30
+ await this.refreshSubscriptions();
31
+ await this.tick();
32
+ this.timer = setInterval(() => {
33
+ void this.tick();
34
+ }, 30_000);
35
+ }
36
+ async stop() {
37
+ if (this.timer) {
38
+ clearInterval(this.timer);
39
+ this.timer = null;
40
+ }
41
+ for (const handle of this.subscriptionHandles.values()) {
42
+ await handle.stop();
43
+ }
44
+ this.subscriptionHandles.clear();
45
+ }
46
+ listMonitors(workspaceId) {
47
+ return this.repository.list(workspaceId);
48
+ }
49
+ getMonitor(monitorId) {
50
+ const resolvedMonitorId = this.resolveMonitorId(monitorId);
51
+ return resolvedMonitorId ? this.repository.get(resolvedMonitorId) : undefined;
52
+ }
53
+ createMonitor(input) {
54
+ const resolved = this.resolveCreateInput(input);
55
+ const provider = this.providers.get(resolved.sourceType);
56
+ provider?.validateConfig?.(resolved.sourceConfig || {});
57
+ const monitor = this.repository.create(resolved);
58
+ this.emitMonitor(monitor);
59
+ void this.ensureSubscription(monitor);
60
+ return monitor;
61
+ }
62
+ updateMonitor(monitorId, input) {
63
+ const resolvedMonitorId = this.resolveRequiredMonitorId(monitorId);
64
+ const existing = this.repository.get(resolvedMonitorId);
65
+ if (existing && input.sourceConfig) {
66
+ this.providers.get(existing.sourceType)?.validateConfig?.(input.sourceConfig);
67
+ }
68
+ const monitor = this.repository.update(resolvedMonitorId, {
69
+ ...input,
70
+ ...(input.route ? { route: (0, scheduled_job_route_js_1.withoutThreadRoute)(input.route) } : {}),
71
+ });
72
+ this.emitMonitor(monitor);
73
+ void this.ensureSubscription(monitor);
74
+ return monitor;
75
+ }
76
+ deleteMonitor(monitorId) {
77
+ const resolvedMonitorId = this.resolveRequiredMonitorId(monitorId);
78
+ void this.stopSubscription(resolvedMonitorId);
79
+ return this.repository.delete(resolvedMonitorId);
80
+ }
81
+ listRuns(monitorId) {
82
+ return this.repository.listRuns(this.resolveRequiredMonitorId(monitorId));
83
+ }
84
+ async runMonitorNow(monitorId, event) {
85
+ const monitor = this.getRequiredMonitor(monitorId);
86
+ const snapshot = event || await this.pollMonitor(monitor, true);
87
+ if (!snapshot) {
88
+ const skipped = this.markSkipped(monitor, new Date().toISOString(), 'No event snapshot is available for this monitor.');
89
+ this.emitRun(skipped);
90
+ return skipped;
91
+ }
92
+ return this.executeMonitor(monitor, snapshot, true);
93
+ }
94
+ listMonitorsForThread(threadId) {
95
+ const binding = this.repository.getPlatformThreadBindingByThreadId(threadId);
96
+ return this.repository
97
+ .list()
98
+ .filter((monitor) => monitor.route.threadId === threadId ||
99
+ (binding ? (0, scheduled_job_route_js_1.scheduledJobMatchesPlatformBinding)(this.repository.toScheduledLike(monitor), binding) : false));
100
+ }
101
+ async tick() {
102
+ if (this.pollInFlight) {
103
+ return;
104
+ }
105
+ this.pollInFlight = true;
106
+ try {
107
+ for (const monitor of this.repository.list().filter((candidate) => candidate.enabled)) {
108
+ const provider = this.providers.get(monitor.sourceType);
109
+ if (provider?.startMonitor) {
110
+ continue;
111
+ }
112
+ const event = await this.pollMonitor(monitor, false);
113
+ if (!event) {
114
+ continue;
115
+ }
116
+ if (!(0, condition_evaluator_js_1.evaluateMonitorCondition)(monitor.condition, event)) {
117
+ this.repository.updateState(monitor.id, {
118
+ lastState: this.stateFromEvent(event, monitor.lastState),
119
+ });
120
+ continue;
121
+ }
122
+ if (this.isCoolingDown(monitor, event.occurredAt)) {
123
+ continue;
124
+ }
125
+ void this.executeMonitor(monitor, event, false);
126
+ }
127
+ }
128
+ finally {
129
+ this.pollInFlight = false;
130
+ }
131
+ }
132
+ async pollMonitor(monitor, manual) {
133
+ const provider = this.providers.get(monitor.sourceType);
134
+ if (!provider?.poll) {
135
+ if (manual) {
136
+ throw new Error(`No polling provider is available for monitor source "${monitor.sourceType}"`);
137
+ }
138
+ return null;
139
+ }
140
+ return provider.poll({
141
+ monitorId: monitor.id,
142
+ workspaceId: monitor.workspaceId,
143
+ sourceConfig: monitor.sourceConfig,
144
+ lastState: monitor.lastState,
145
+ });
146
+ }
147
+ async executeMonitor(monitor, event, manual) {
148
+ if (this.runningMonitors.has(monitor.id)) {
149
+ const skipped = this.markSkipped(monitor, event.occurredAt, 'Skipped because the previous monitor run is still active.', event);
150
+ this.emitRun(skipped);
151
+ return skipped;
152
+ }
153
+ this.runningMonitors.add(monitor.id);
154
+ const run = this.repository.createRun(monitor.id, 'queued', {
155
+ triggeredAt: event.occurredAt,
156
+ eventSnapshot: event,
157
+ deliveryStatus: 'pending',
158
+ });
159
+ this.emitRun(run);
160
+ try {
161
+ const running = this.repository.updateRun(run.id, {
162
+ status: 'running',
163
+ startedAt: new Date().toISOString(),
164
+ });
165
+ this.emitRun(running);
166
+ const result = await this.executor.execute(monitor, event);
167
+ const succeeded = this.repository.updateRun(run.id, {
168
+ status: 'succeeded',
169
+ finishedAt: new Date().toISOString(),
170
+ threadId: result.threadId,
171
+ runId: result.runId,
172
+ deliveryMode: result.deliveryMode,
173
+ deliveryStatus: result.deliveryStatus || 'succeeded',
174
+ deliveryError: result.deliveryError || '',
175
+ lastBridgeEventAt: result.lastBridgeEventAt,
176
+ error: '',
177
+ });
178
+ this.repository.updateState(monitor.id, {
179
+ lastState: this.stateFromEvent(event, monitor.lastState),
180
+ lastTriggeredAt: event.occurredAt,
181
+ lastStatus: 'succeeded',
182
+ lastError: '',
183
+ });
184
+ this.emitRun(succeeded);
185
+ const nextMonitor = this.repository.get(monitor.id);
186
+ if (nextMonitor)
187
+ this.emitMonitor(nextMonitor);
188
+ return succeeded;
189
+ }
190
+ catch (error) {
191
+ const message = error instanceof Error ? error.message : String(error);
192
+ const failed = this.repository.updateRun(run.id, {
193
+ status: 'failed',
194
+ finishedAt: new Date().toISOString(),
195
+ error: message,
196
+ deliveryStatus: 'failed',
197
+ deliveryError: message,
198
+ });
199
+ this.repository.updateState(monitor.id, {
200
+ lastState: this.stateFromEvent(event, monitor.lastState),
201
+ lastTriggeredAt: event.occurredAt,
202
+ lastStatus: 'failed',
203
+ lastError: message,
204
+ });
205
+ this.emitRun(failed);
206
+ const nextMonitor = this.repository.get(monitor.id);
207
+ if (nextMonitor)
208
+ this.emitMonitor(nextMonitor);
209
+ this.options.log?.(`automation monitor failed ${monitor.id}: ${message}`);
210
+ return failed;
211
+ }
212
+ finally {
213
+ this.runningMonitors.delete(monitor.id);
214
+ }
215
+ }
216
+ markSkipped(monitor, triggeredAt, error, eventSnapshot) {
217
+ return this.repository.createRun(monitor.id, 'skipped', {
218
+ triggeredAt,
219
+ error,
220
+ eventSnapshot,
221
+ deliveryStatus: 'skipped',
222
+ deliveryError: error,
223
+ });
224
+ }
225
+ stateFromEvent(event, previous) {
226
+ return {
227
+ ...(previous || {}),
228
+ lastEventId: event.id,
229
+ lastEventAt: event.occurredAt,
230
+ latestPrice: event.payload.latestPrice ?? previous?.latestPrice,
231
+ previousPrice: event.payload.previousPrice ?? previous?.previousPrice,
232
+ payload: event.payload,
233
+ };
234
+ }
235
+ isCoolingDown(monitor, occurredAt) {
236
+ if (!monitor.lastTriggeredAt || monitor.cooldownMs <= 0) {
237
+ return false;
238
+ }
239
+ return Date.parse(occurredAt) - Date.parse(monitor.lastTriggeredAt) < monitor.cooldownMs;
240
+ }
241
+ resolveCreateInput(input) {
242
+ if (input.platform && input.route) {
243
+ return {
244
+ ...input,
245
+ route: (0, scheduled_job_route_js_1.routeWithPlatformInstance)((0, scheduled_job_route_js_1.withoutThreadRoute)(input.route), input.platform),
246
+ };
247
+ }
248
+ const threadId = String(input.threadId || input.route?.threadId || '').trim();
249
+ if (threadId) {
250
+ const binding = this.repository.getPlatformThreadBindingByThreadId(threadId);
251
+ if (binding && binding.workspace_id === input.workspaceId) {
252
+ return {
253
+ ...input,
254
+ platform: binding.platform,
255
+ route: (0, scheduled_job_route_js_1.routeFromPlatformThreadBinding)(binding),
256
+ };
257
+ }
258
+ }
259
+ return {
260
+ ...input,
261
+ platform: 'local',
262
+ route: {
263
+ type: 'local.thread',
264
+ channelId: input.workspaceId,
265
+ },
266
+ };
267
+ }
268
+ getRequiredMonitor(monitorId) {
269
+ const monitor = this.getMonitor(monitorId);
270
+ if (!monitor) {
271
+ throw new Error(`Automation monitor not found: ${monitorId}`);
272
+ }
273
+ return monitor;
274
+ }
275
+ resolveMonitorId(monitorId) {
276
+ if (this.repository.get(monitorId)) {
277
+ return monitorId;
278
+ }
279
+ const matches = this.repository
280
+ .list()
281
+ .filter((monitor) => publicMonitorId(monitor.id) === monitorId);
282
+ if (matches.length === 0) {
283
+ return '';
284
+ }
285
+ if (matches.length > 1) {
286
+ throw new Error(`Automation monitor id is ambiguous: ${monitorId}`);
287
+ }
288
+ return matches[0].id;
289
+ }
290
+ resolveRequiredMonitorId(monitorId) {
291
+ const resolved = this.resolveMonitorId(monitorId);
292
+ if (!resolved) {
293
+ throw new Error(`Automation monitor not found: ${monitorId}`);
294
+ }
295
+ return resolved;
296
+ }
297
+ emitMonitor(monitor) {
298
+ this.options.eventBus.emit({ type: 'automation.monitor.updated', payload: monitor });
299
+ }
300
+ emitRun(run) {
301
+ this.options.eventBus.emit({ type: 'automation.monitor.run.updated', payload: run });
302
+ }
303
+ async refreshSubscriptions() {
304
+ const activeIds = new Set();
305
+ for (const monitor of this.repository.list().filter((candidate) => candidate.enabled)) {
306
+ const provider = this.providers.get(monitor.sourceType);
307
+ if (!provider?.startMonitor)
308
+ continue;
309
+ activeIds.add(monitor.id);
310
+ await this.ensureSubscription(monitor);
311
+ }
312
+ for (const monitorId of [...this.subscriptionHandles.keys()]) {
313
+ if (!activeIds.has(monitorId)) {
314
+ await this.stopSubscription(monitorId);
315
+ }
316
+ }
317
+ }
318
+ async ensureSubscription(monitor) {
319
+ const provider = this.providers.get(monitor.sourceType);
320
+ if (!monitor.enabled || !provider?.startMonitor) {
321
+ await this.stopSubscription(monitor.id);
322
+ return;
323
+ }
324
+ if (this.subscriptionHandles.has(monitor.id)) {
325
+ return;
326
+ }
327
+ const handle = await provider.startMonitor({
328
+ monitorId: monitor.id,
329
+ workspaceId: monitor.workspaceId,
330
+ sourceConfig: monitor.sourceConfig,
331
+ lastState: monitor.lastState,
332
+ emit: async (event) => {
333
+ const latest = this.repository.get(monitor.id);
334
+ if (!latest || !latest.enabled)
335
+ return;
336
+ if (!(0, condition_evaluator_js_1.evaluateMonitorCondition)(latest.condition, event)) {
337
+ this.repository.updateState(latest.id, { lastState: this.stateFromEvent(event, latest.lastState) });
338
+ return;
339
+ }
340
+ if (this.isCoolingDown(latest, event.occurredAt))
341
+ return;
342
+ await this.executeMonitor(latest, event, false);
343
+ },
344
+ });
345
+ this.subscriptionHandles.set(monitor.id, handle);
346
+ }
347
+ async stopSubscription(monitorId) {
348
+ const handle = this.subscriptionHandles.get(monitorId);
349
+ if (!handle)
350
+ return;
351
+ this.subscriptionHandles.delete(monitorId);
352
+ await handle.stop();
353
+ }
354
+ }
355
+ exports.AutomationMonitorService = AutomationMonitorService;
356
+ function publicMonitorId(monitorId) {
357
+ const normalized = monitorId.startsWith('monitor:') ? monitorId.slice('monitor:'.length) : monitorId;
358
+ return normalized.includes('-') ? normalized.split('-')[0] || normalized : normalized;
359
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluateMonitorCondition = evaluateMonitorCondition;
4
+ exports.evaluateExpression = evaluateExpression;
5
+ exports.readMetric = readMetric;
6
+ function evaluateMonitorCondition(condition, event) {
7
+ if (condition.expression) {
8
+ return evaluateExpression(condition.expression, event);
9
+ }
10
+ const actual = readMetric(event, condition.metric);
11
+ const expected = condition.value;
12
+ switch (condition.operator) {
13
+ case '>':
14
+ return Number(actual) > Number(expected);
15
+ case '>=':
16
+ return Number(actual) >= Number(expected);
17
+ case '<':
18
+ return Number(actual) < Number(expected);
19
+ case '<=':
20
+ return Number(actual) <= Number(expected);
21
+ case '==':
22
+ return String(actual) === String(expected);
23
+ case '!=':
24
+ return String(actual) !== String(expected);
25
+ default:
26
+ return false;
27
+ }
28
+ }
29
+ function evaluateExpression(expression, event) {
30
+ const orParts = splitExpression(expression, '||');
31
+ return orParts.some((orPart) => splitExpression(orPart, '&&').every((andPart) => evaluateComparison(andPart.trim(), event)));
32
+ }
33
+ function evaluateComparison(expression, event) {
34
+ const match = expression.match(/^([a-zA-Z0-9_.-]+)\s*(>=|<=|==|!=|>|<)\s*(.+)$/);
35
+ if (!match) {
36
+ throw new Error(`Unsupported monitor condition expression: ${expression}`);
37
+ }
38
+ const rawValue = String(match[3] || '').trim().replace(/^["']|["']$/g, '');
39
+ const numeric = Number(rawValue);
40
+ return evaluateMonitorCondition({
41
+ metric: String(match[1] || '').trim(),
42
+ operator: match[2],
43
+ value: Number.isFinite(numeric) && rawValue !== '' ? numeric : rawValue,
44
+ }, event);
45
+ }
46
+ function splitExpression(expression, operator) {
47
+ return expression
48
+ .split(operator)
49
+ .map((part) => part.trim())
50
+ .filter(Boolean);
51
+ }
52
+ function readMetric(event, metric) {
53
+ const key = String(metric || '').trim();
54
+ if (!key) {
55
+ return undefined;
56
+ }
57
+ if (key === 'subject')
58
+ return event.subject;
59
+ if (key === 'sourceType')
60
+ return event.sourceType;
61
+ const payload = event.payload || {};
62
+ if (key === 'abs_change_percent') {
63
+ return Math.abs(Number(payload.change_percent ?? payload.changePercent ?? 0));
64
+ }
65
+ const normalizedKey = key.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`);
66
+ if (Object.prototype.hasOwnProperty.call(payload, key)) {
67
+ return payload[key];
68
+ }
69
+ if (Object.prototype.hasOwnProperty.call(payload, normalizedKey)) {
70
+ return payload[normalizedKey];
71
+ }
72
+ return key.split('.').reduce((current, part) => {
73
+ if (!current || typeof current !== 'object')
74
+ return undefined;
75
+ return current[part];
76
+ }, payload);
77
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MockStockQuoteProvider = void 0;
4
+ class MockStockQuoteProvider {
5
+ sourceType = 'stock.quote';
6
+ modes = ['poll'];
7
+ validateConfig(config) {
8
+ const symbol = String(config.symbol || '').trim();
9
+ if (!symbol) {
10
+ throw new Error('stock.quote monitor requires sourceConfig.symbol.');
11
+ }
12
+ }
13
+ poll(input) {
14
+ this.validateConfig(input.sourceConfig);
15
+ const symbol = String(input.sourceConfig.symbol || '').trim().toUpperCase();
16
+ const latestPrice = Number(input.sourceConfig.price ?? input.sourceConfig.latestPrice ?? input.lastState?.latestPrice ?? 0);
17
+ if (!Number.isFinite(latestPrice) || latestPrice <= 0) {
18
+ return null;
19
+ }
20
+ const previousPrice = Number(input.lastState?.latestPrice ?? input.sourceConfig.previousPrice ?? latestPrice);
21
+ const changePercent = previousPrice > 0 ? ((latestPrice - previousPrice) / previousPrice) * 100 : 0;
22
+ const now = new Date().toISOString();
23
+ return {
24
+ id: `${input.monitorId}:${symbol}:${now}`,
25
+ sourceType: this.sourceType,
26
+ occurredAt: now,
27
+ subject: symbol,
28
+ summary: `${symbol} ${latestPrice} (${changePercent.toFixed(2)}%)`,
29
+ payload: {
30
+ symbol,
31
+ latestPrice,
32
+ previousPrice,
33
+ change_percent: changePercent,
34
+ changePercent,
35
+ timestamp: now,
36
+ },
37
+ };
38
+ }
39
+ }
40
+ exports.MockStockQuoteProvider = MockStockQuoteProvider;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toPublicAutomationMonitorId = toPublicAutomationMonitorId;
4
+ function toPublicAutomationMonitorId(monitorId) {
5
+ const normalized = monitorId.startsWith('monitor:') ? monitorId.slice('monitor:'.length) : monitorId;
6
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(normalized)) {
7
+ return normalized.split('-')[0] || normalized;
8
+ }
9
+ return normalized;
10
+ }
@@ -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
  }