@kafca/agentdock 0.1.58 → 0.1.62

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 (127) hide show
  1. package/README.md +18 -0
  2. package/dist/renderer/assets/AutomationList-BgJgAdVO.js +16 -0
  3. package/dist/renderer/assets/{Badge-BfY1VaHS.js → Badge-Bq2hPVcR.js} +1 -1
  4. package/dist/renderer/assets/{Card-DWA_Tww_.js → Card-BPJNSZce.js} +1 -1
  5. package/dist/renderer/assets/{Config-nHj3g1U5.js → Config-aSFqlI88.js} +2 -2
  6. package/dist/renderer/assets/Dashboard-D3ezFmb7.js +36 -0
  7. package/dist/renderer/assets/{EmptyState-zatDjLj_.js → EmptyState-DK496gBq.js} +1 -1
  8. package/dist/renderer/assets/{HighlightedMarkdown-CsM5n70d.js → HighlightedMarkdown-Ckre5jNv.js} +1 -1
  9. package/dist/renderer/assets/{Input-R1XdFK1K.js → Input-C5C1d0ba.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeDetail-Co5sxeGd.js → KnowledgeDetail-N8Ey1ikc.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-DwziPw5m.js → KnowledgeHome-9aF8nJEf.js} +2 -2
  12. package/dist/renderer/assets/{Logs-NwZUtR_G.js → Logs-sgAdwEeS.js} +2 -2
  13. package/dist/renderer/assets/{Modal-CrcIwIFL.js → Modal-BB10hTRc.js} +3 -3
  14. package/dist/renderer/assets/{Page-Dp0obeSw.js → Page-DfC319Ck.js} +1 -1
  15. package/dist/renderer/assets/{Select-6mVQaf84.js → Select-RHJBmNER.js} +1 -1
  16. package/dist/renderer/assets/{ThreadChat-BFzbn3L6.js → ThreadChat-BU1zCdr4.js} +3 -3
  17. package/dist/renderer/assets/{Workspace-DCmo8BMm.js → Workspace-BoZCz7S8.js} +1 -1
  18. package/dist/renderer/assets/{arrow-left-9rjg_Hp4.js → arrow-left-D2V1eZSD.js} +1 -1
  19. package/dist/renderer/assets/{book-open-Bu8GCHnG.js → book-open-DUcBn7Bb.js} +1 -1
  20. package/dist/renderer/assets/{channels-BxVbG-6j.js → channels-DMhDSlf2.js} +2 -2
  21. package/dist/renderer/assets/{chevron-down-BE8uQmWM.js → chevron-down-Ca2FQDB7.js} +1 -1
  22. package/dist/renderer/assets/en-Bnr4nMzg.js +1 -0
  23. package/dist/renderer/assets/es-B1GIFh3i.js +1 -0
  24. package/dist/renderer/assets/{index-BIKL3fTP.css → index-B6WcpkJF.css} +1 -1
  25. package/dist/renderer/assets/{index-B7TeF6Es.js → index-BlnvlekJ.js} +1 -1
  26. package/dist/renderer/assets/index-DRJ5wgw_.js +162 -0
  27. package/dist/renderer/assets/ja-CDWPWqEW.js +1 -0
  28. package/dist/renderer/assets/{knowledge-Kl19SqGS.js → knowledge-D1-k56eY.js} +1 -1
  29. package/dist/renderer/assets/{pencil-CPB7SK1m.js → pencil-BhWdv_86.js} +1 -1
  30. package/dist/renderer/assets/{plus-Bt26z-4q.js → plus-BacLMlK3.js} +1 -1
  31. package/dist/renderer/assets/{save-Une7GMxT.js → save-Bpoxbzau.js} +1 -1
  32. package/dist/renderer/assets/{search-DE0agJjJ.js → search-BVJcpdFX.js} +1 -1
  33. package/dist/renderer/assets/{shield-check-De7xaXZh.js → shield-check-C2cw_Ip6.js} +1 -1
  34. package/dist/renderer/assets/{threads-BnsNL5ei.js → threads-DOsBQBg_.js} +1 -1
  35. package/dist/renderer/assets/{trash-2-6iGF59Ac.js → trash-2-Bs3rEm3g.js} +1 -1
  36. package/dist/renderer/assets/zh-MSddxMDX.js +1 -0
  37. package/dist/renderer/assets/zh-TW-C_LNWX0o.js +1 -0
  38. package/dist/renderer/index.html +2 -2
  39. package/dist-electron/electron/managed-skills/agent-browser/SKILL.md +41 -0
  40. package/dist-electron/electron/managed-skills/agent-browser/references/authentication.md +83 -0
  41. package/dist-electron/electron/managed-skills/agent-browser/references/commands.md +50 -0
  42. package/dist-electron/electron/managed-skills/agent-browser/references/profiling.md +20 -0
  43. package/dist-electron/electron/managed-skills/agent-browser/references/proxy-support.md +18 -0
  44. package/dist-electron/electron/managed-skills/agent-browser/references/session-management.md +17 -0
  45. package/dist-electron/electron/managed-skills/agent-browser/references/snapshot-refs.md +17 -0
  46. package/dist-electron/electron/managed-skills/agent-browser/references/video-recording.md +21 -0
  47. package/dist-electron/electron/managed-skills/agent-browser/templates/authenticated-session.sh +11 -0
  48. package/dist-electron/electron/managed-skills/agent-browser/templates/capture-workflow.sh +12 -0
  49. package/dist-electron/electron/managed-skills/agent-browser/templates/form-automation.sh +10 -0
  50. package/dist-electron/electron/managed-skills/condition-trigger/SKILL.md +21 -0
  51. package/dist-electron/electron/managed-skills/condition-trigger/scripts/register-condition-trigger.sh +106 -0
  52. package/dist-electron/electron/managed-skills/knowledge-base/SKILL.md +13 -0
  53. package/dist-electron/electron/managed-skills/knowledge-base/scripts/search-knowledge.sh +80 -0
  54. package/dist-electron/packages/contracts/src/automations.js +211 -0
  55. package/dist-electron/packages/contracts/src/index.js +1 -0
  56. package/dist-electron/packages/core-sdk/src/automations.js +87 -0
  57. package/dist-electron/packages/core-sdk/src/client.js +101 -0
  58. package/dist-electron/packages/core-sdk/src/index.js +2 -1
  59. package/dist-electron/services/local-ai-core/src/acp/store/automation-script-store.js +415 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/automation-store.js +829 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +158 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +81 -0
  63. package/dist-electron/services/local-ai-core/src/automation/automation-action-executor.js +144 -0
  64. package/dist-electron/services/local-ai-core/src/automation/automation-condition-engine.js +79 -0
  65. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +39 -73
  66. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +695 -260
  67. package/dist-electron/services/local-ai-core/src/automation/automation-script-service.js +507 -0
  68. package/dist-electron/services/local-ai-core/src/automation/automation-service.js +1019 -0
  69. package/dist-electron/services/local-ai-core/src/automation/automation-trigger-engine.js +141 -0
  70. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +60 -17
  71. package/dist-electron/services/local-ai-core/src/automation/legacy-automation-mappers.js +286 -0
  72. package/dist-electron/services/local-ai-core/src/automation/scripts/anthropic-sandbox-runner.js +792 -0
  73. package/dist-electron/services/local-ai-core/src/automation/scripts/sandbox-runner.js +2 -0
  74. package/dist-electron/services/local-ai-core/src/automation/scripts/script-package.js +475 -0
  75. package/dist-electron/services/local-ai-core/src/automation/scripts/script-protocol-runner.js +266 -0
  76. package/dist-electron/services/local-ai-core/src/automation/scripts/secret-resolver.js +37 -0
  77. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +1 -2
  78. package/dist-electron/services/local-ai-core/src/channel/weixin/transport.js +9 -8
  79. package/dist-electron/services/local-ai-core/src/cli/lac.js +229 -0
  80. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +21 -0
  81. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +76 -0
  82. package/dist-electron/services/local-ai-core/src/runtime/handlers/automations-handler.js +322 -0
  83. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +20 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/managed-skill-catalog.js +37 -0
  85. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +14 -4
  86. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +75 -0
  87. package/dist-electron/services/local-ai-core/src/runtime/server.js +21 -0
  88. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +1 -0
  89. package/dist-electron/services/local-ai-core/src/scheduler/cron.js +151 -39
  90. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +2 -4
  91. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js +64 -12
  92. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +71 -4
  93. package/dist-electron/services/local-ai-core/src/scheduler/thread-resolution.js +10 -0
  94. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +16 -1
  95. package/dist-electron/src/pages/Automation/automation-page-model.js +76 -0
  96. package/dist-electron/tests/contracts/agent-message-policy.test.js +32 -0
  97. package/dist-electron/tests/contracts/architecture-docs.test.js +30 -0
  98. package/dist-electron/tests/contracts/automation-contracts.test.js +154 -0
  99. package/dist-electron/tests/contracts/automation-renderer-model.test.js +47 -0
  100. package/dist-electron/tests/electron/automation-action-executor.test.js +75 -0
  101. package/dist-electron/tests/electron/automation-compatibility.test.js +463 -0
  102. package/dist-electron/tests/electron/automation-deployment.test.js +66 -0
  103. package/dist-electron/tests/electron/automation-engine.test.js +264 -0
  104. package/dist-electron/tests/electron/automation-monitor.test.js +1333 -0
  105. package/dist-electron/tests/electron/automation-sandbox-runner.test.js +333 -0
  106. package/dist-electron/tests/electron/automation-script-approval.test.js +553 -0
  107. package/dist-electron/tests/electron/automation-script-package.test.js +499 -0
  108. package/dist-electron/tests/electron/automation-script-runner.test.js +120 -0
  109. package/dist-electron/tests/electron/automation-service.test.js +1078 -0
  110. package/dist-electron/tests/electron/automation-store.test.js +593 -0
  111. package/dist-electron/tests/electron/condition-trigger-skill.test.js +93 -0
  112. package/dist-electron/tests/electron/core-client.test.js +99 -0
  113. package/dist-electron/tests/electron/lac-cli.test.js +110 -0
  114. package/dist-electron/tests/electron/workspace-task-store.test.js +25 -0
  115. package/dist-electron/tests/integration/automation-routes.test.js +186 -0
  116. package/dist-electron/tests/integration/automation-sandbox-runtime.test.js +92 -0
  117. package/package.json +5 -6
  118. package/dist/renderer/assets/CronList-BwkA_I7v.js +0 -1
  119. package/dist/renderer/assets/Dashboard-D0_A7k02.js +0 -41
  120. package/dist/renderer/assets/MonitorList-CS1uLS5A.js +0 -1
  121. package/dist/renderer/assets/en-CmAr_0e6.js +0 -1
  122. package/dist/renderer/assets/es-Cs9x52ca.js +0 -1
  123. package/dist/renderer/assets/index-BkI9POxj.js +0 -167
  124. package/dist/renderer/assets/ja-DtvtBRTW.js +0 -1
  125. package/dist/renderer/assets/play-DGAO4OCu.js +0 -6
  126. package/dist/renderer/assets/zh-CcJ9vBZj.js +0 -1
  127. package/dist/renderer/assets/zh-TW-elI72AC1.js +0 -1
@@ -7,6 +7,9 @@ const node_path_1 = require("node:path");
7
7
  const superai_contracts_1 = require("../../../../../packages/contracts/src/index.js");
8
8
  const agent_task_store_js_1 = require("./agent-task-store.js");
9
9
  const automation_monitor_store_js_1 = require("./automation-monitor-store.js");
10
+ const automation_script_store_js_1 = require("./automation-script-store.js");
11
+ const automation_script_service_js_1 = require("../../automation/automation-script-service.js");
12
+ const automation_store_js_1 = require("./automation-store.js");
10
13
  const schema_js_1 = require("./schema.js");
11
14
  const platform_store_js_1 = require("./platform-store.js");
12
15
  const scheduler_store_js_1 = require("./scheduler-store.js");
@@ -24,6 +27,9 @@ class LocalCoreAcpStore {
24
27
  agentTasks;
25
28
  scheduler;
26
29
  automationMonitors;
30
+ automationScripts;
31
+ automationScriptLifecycle;
32
+ automations;
27
33
  platform;
28
34
  modelProviders;
29
35
  external;
@@ -43,6 +49,9 @@ class LocalCoreAcpStore {
43
49
  });
44
50
  this.scheduler = new scheduler_store_js_1.LocalSchedulerStore(this.db);
45
51
  this.automationMonitors = new automation_monitor_store_js_1.LocalAutomationMonitorStore(this.db);
52
+ this.automationScripts = new automation_script_store_js_1.LocalAutomationScriptStore(this.db, userDataPath);
53
+ this.automationScriptLifecycle = new automation_script_service_js_1.AutomationScriptService({ db: this.db, security: this.security });
54
+ this.automations = new automation_store_js_1.LocalAutomationStore(this.db);
46
55
  this.platform = new platform_store_js_1.LocalPlatformStore(this.db);
47
56
  this.modelProviders = new model_provider_store_js_1.LocalModelProviderStore(this.db);
48
57
  this.external = new external_store_js_1.LocalExternalStore(this.db);
@@ -237,6 +246,143 @@ class LocalCoreAcpStore {
237
246
  updateAutomationMonitorRun(runId, input) {
238
247
  return this.automationMonitors.updateRun(runId, input);
239
248
  }
249
+ listAutomations(workspaceId) {
250
+ return this.automations.list(workspaceId);
251
+ }
252
+ getAutomation(automationId) {
253
+ return this.automations.get(automationId);
254
+ }
255
+ getAutomationNextCheckAt(automationId) {
256
+ return this.automations.getNextCheckAt(automationId);
257
+ }
258
+ createAutomation(input) {
259
+ return this.automations.create(input);
260
+ }
261
+ createTrustedAutomation(input) {
262
+ return this.automations.createTrusted(input);
263
+ }
264
+ createAutomationAtomically(input, initialize) {
265
+ return this.automationTransaction(() => {
266
+ const created = this.automations.create(input);
267
+ return this.automations.updateState(created.id, initialize(created));
268
+ });
269
+ }
270
+ createTrustedAutomationAtomically(input, initialize) {
271
+ return this.automationTransaction(() => {
272
+ const created = this.automations.createTrusted(input);
273
+ return this.automations.updateState(created.id, initialize(created));
274
+ });
275
+ }
276
+ updateAutomation(automationId, input) {
277
+ return this.automations.update(automationId, input);
278
+ }
279
+ updateTrustedAutomation(automationId, input) {
280
+ return this.automations.updateTrusted(automationId, input);
281
+ }
282
+ updateAutomationAtomically(automationId, input, initialize) {
283
+ return this.automationTransaction(() => {
284
+ const updated = this.automations.update(automationId, input);
285
+ const state = initialize?.(updated);
286
+ return state ? this.automations.updateState(automationId, state) : updated;
287
+ });
288
+ }
289
+ updateTrustedAutomationAtomically(automationId, input, initialize) {
290
+ return this.automationTransaction(() => {
291
+ const updated = this.automations.updateTrusted(automationId, input);
292
+ const state = initialize?.(updated);
293
+ return state ? this.automations.updateState(automationId, state) : updated;
294
+ });
295
+ }
296
+ updateAutomationState(automationId, input) {
297
+ return this.automations.updateState(automationId, input);
298
+ }
299
+ deleteAutomation(automationId) {
300
+ return this.automations.delete(automationId);
301
+ }
302
+ listAutomationScripts(workspaceId) {
303
+ return this.automationScripts.listScripts(workspaceId);
304
+ }
305
+ getAutomationScript(scriptId) {
306
+ return this.automationScripts.getScript(scriptId);
307
+ }
308
+ createAutomationScript(input) {
309
+ return this.automationScripts.createScript(input);
310
+ }
311
+ updateAutomationScript(scriptId, input) {
312
+ return this.automationScripts.updateScript(scriptId, input);
313
+ }
314
+ createAutomationScriptVersionFromPackage(input) {
315
+ return this.automationScripts.createVersionFromPackage(input);
316
+ }
317
+ stageAutomationScriptSource(input) {
318
+ return this.automationScripts.stageSource(input);
319
+ }
320
+ createAutomationScriptVersionFromStaged(input) {
321
+ return this.automationScripts.createVersionFromStaged(input.scriptId, input.staged, input.interpreterPath, input.interpreterVersion);
322
+ }
323
+ discardUnreferencedAutomationScriptPackage(scriptId, staged) {
324
+ this.automationScripts.discardUnreferencedPackage(scriptId, staged);
325
+ }
326
+ listAutomationScriptVersions(scriptId) {
327
+ return this.automationScripts.listVersions(scriptId);
328
+ }
329
+ getAutomationScriptVersion(versionId) {
330
+ return this.automationScripts.getVersion(versionId);
331
+ }
332
+ requestAutomationScriptTestApproval(versionId, actor) {
333
+ return this.automationScriptLifecycle.requestTestApproval(versionId, actor);
334
+ }
335
+ authorizeAutomationScriptTest(versionId, approvalId, actor) {
336
+ return this.automationScriptLifecycle.authorizeTest(versionId, approvalId, actor);
337
+ }
338
+ recordAutomationScriptTestResult(versionId, result) {
339
+ return this.automationScriptLifecycle.recordTestResult(versionId, result);
340
+ }
341
+ claimAutomationScriptTestExecution(versionId) {
342
+ return this.automationScriptLifecycle.claimTestExecution(versionId);
343
+ }
344
+ failClaimedAutomationScriptTestExecution(versionId) {
345
+ return this.automationScriptLifecycle.failClaimedTestExecution(versionId);
346
+ }
347
+ requestAutomationScriptEnableApproval(versionId, actor) {
348
+ return this.automationScriptLifecycle.requestEnableApproval(versionId, actor);
349
+ }
350
+ approveAutomationScriptVersion(versionId, approvalId, actor) {
351
+ return this.automationScriptLifecycle.approveVersion(versionId, approvalId, actor);
352
+ }
353
+ revokeAutomationScriptVersion(versionId, actor) {
354
+ return this.automationScriptLifecycle.revokeVersion(versionId, actor);
355
+ }
356
+ createAutomationEvaluation(automationId, input) {
357
+ return this.automations.createEvaluation(automationId, input);
358
+ }
359
+ finishAutomationEvaluation(evaluationId, input) {
360
+ return this.automations.finishEvaluation(evaluationId, input);
361
+ }
362
+ listAutomationEvaluations(automationId) {
363
+ return this.automations.listEvaluations(automationId);
364
+ }
365
+ getLatestAutomationEvaluationWithState(automationId) {
366
+ return this.automations.getLatestEvaluationWithState(automationId);
367
+ }
368
+ createAutomationRun(automationId, evaluationId, input = {}) {
369
+ return this.automations.createRun(automationId, evaluationId, input);
370
+ }
371
+ updateAutomationRun(runId, input) {
372
+ return this.automations.updateRun(runId, input);
373
+ }
374
+ listAutomationRuns(automationId) {
375
+ return this.automations.listRuns(automationId);
376
+ }
377
+ reconcileInterruptedAutomationRuns(reason, finishedAt) {
378
+ return this.automations.reconcileInterruptedRuns(reason, finishedAt);
379
+ }
380
+ importLegacyAutomations() {
381
+ return this.automations.importLegacyRecords();
382
+ }
383
+ pruneAutomationEvaluations(now) {
384
+ return this.automations.pruneEvaluations(now);
385
+ }
240
386
  getThreadRow(threadId) {
241
387
  return this.threads.getRow(threadId);
242
388
  }
@@ -303,6 +449,18 @@ class LocalCoreAcpStore {
303
449
  listPairingRequests(workspaceId, platform) {
304
450
  return this.platform.listPairingRequests(workspaceId, platform);
305
451
  }
452
+ automationTransaction(work) {
453
+ this.db.exec('BEGIN IMMEDIATE');
454
+ try {
455
+ const result = work();
456
+ this.db.exec('COMMIT');
457
+ return result;
458
+ }
459
+ catch (error) {
460
+ this.db.exec('ROLLBACK');
461
+ throw error;
462
+ }
463
+ }
306
464
  }
307
465
  exports.LocalCoreAcpStore = LocalCoreAcpStore;
308
466
  function resolveLegacyConfigPaths(runtimeDir) {
@@ -162,6 +162,86 @@ function ensureLocalCoreAcpSchema(db) {
162
162
  FOREIGN KEY (monitor_id) REFERENCES automation_monitors(id) ON DELETE CASCADE
163
163
  );
164
164
  CREATE INDEX IF NOT EXISTS idx_automation_monitor_runs_monitor_triggered ON automation_monitor_runs (monitor_id, triggered_at DESC);
165
+ CREATE TABLE IF NOT EXISTS automations (
166
+ id TEXT PRIMARY KEY,
167
+ workspace_id TEXT NOT NULL,
168
+ title TEXT NOT NULL,
169
+ enabled INTEGER NOT NULL,
170
+ health TEXT NOT NULL,
171
+ blocked_reason TEXT,
172
+ activation_json TEXT NOT NULL,
173
+ condition_json TEXT NOT NULL,
174
+ action_json TEXT NOT NULL,
175
+ delivery_json TEXT NOT NULL,
176
+ policies_json TEXT NOT NULL,
177
+ last_successful_match INTEGER,
178
+ last_evaluation_at TEXT,
179
+ last_triggered_at TEXT,
180
+ consecutive_evaluation_failures INTEGER NOT NULL DEFAULT 0,
181
+ next_check_at TEXT,
182
+ origin_kind TEXT NOT NULL DEFAULT 'native',
183
+ legacy_metadata_json TEXT,
184
+ created_at TEXT NOT NULL,
185
+ updated_at TEXT NOT NULL
186
+ );
187
+ CREATE INDEX IF NOT EXISTS idx_automations_workspace_updated ON automations (workspace_id, updated_at DESC);
188
+ CREATE INDEX IF NOT EXISTS idx_automations_enabled_next_check ON automations (enabled, next_check_at);
189
+ CREATE INDEX IF NOT EXISTS idx_automations_health ON automations (health);
190
+ CREATE INDEX IF NOT EXISTS idx_automations_origin ON automations (origin_kind);
191
+ CREATE TABLE IF NOT EXISTS automation_evaluations (
192
+ id TEXT PRIMARY KEY,
193
+ automation_id TEXT NOT NULL,
194
+ status TEXT NOT NULL,
195
+ activation_kind TEXT NOT NULL,
196
+ script_version_id TEXT,
197
+ started_at TEXT NOT NULL,
198
+ finished_at TEXT,
199
+ evaluation_json TEXT NOT NULL,
200
+ FOREIGN KEY (automation_id) REFERENCES automations(id) ON DELETE CASCADE
201
+ );
202
+ CREATE INDEX IF NOT EXISTS idx_automation_evaluations_automation_started
203
+ ON automation_evaluations (automation_id, started_at DESC);
204
+ CREATE TABLE IF NOT EXISTS automation_runs (
205
+ id TEXT PRIMARY KEY,
206
+ automation_id TEXT NOT NULL,
207
+ evaluation_id TEXT NOT NULL UNIQUE,
208
+ status TEXT NOT NULL,
209
+ created_at TEXT NOT NULL,
210
+ run_json TEXT NOT NULL,
211
+ FOREIGN KEY (automation_id) REFERENCES automations(id) ON DELETE CASCADE,
212
+ FOREIGN KEY (evaluation_id) REFERENCES automation_evaluations(id) ON DELETE CASCADE
213
+ );
214
+ CREATE INDEX IF NOT EXISTS idx_automation_runs_automation_created
215
+ ON automation_runs (automation_id, created_at DESC);
216
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_automation_runs_evaluation_unique ON automation_runs (evaluation_id);
217
+ CREATE TABLE IF NOT EXISTS automation_scripts (
218
+ id TEXT PRIMARY KEY,
219
+ workspace_id TEXT NOT NULL,
220
+ title TEXT NOT NULL,
221
+ description TEXT,
222
+ created_at TEXT NOT NULL,
223
+ updated_at TEXT NOT NULL
224
+ );
225
+ CREATE INDEX IF NOT EXISTS idx_automation_scripts_workspace_updated
226
+ ON automation_scripts (workspace_id, updated_at DESC);
227
+ CREATE TABLE IF NOT EXISTS automation_script_versions (
228
+ id TEXT PRIMARY KEY,
229
+ script_id TEXT NOT NULL,
230
+ status TEXT NOT NULL,
231
+ package_sha256 TEXT NOT NULL,
232
+ package_path TEXT NOT NULL,
233
+ shebang TEXT NOT NULL,
234
+ interpreter_path TEXT NOT NULL,
235
+ interpreter_version TEXT NOT NULL,
236
+ created_at TEXT NOT NULL,
237
+ updated_at TEXT NOT NULL,
238
+ version_json TEXT NOT NULL,
239
+ FOREIGN KEY (script_id) REFERENCES automation_scripts(id) ON DELETE CASCADE
240
+ );
241
+ CREATE INDEX IF NOT EXISTS idx_automation_script_versions_script_created
242
+ ON automation_script_versions (script_id, created_at DESC);
243
+ CREATE INDEX IF NOT EXISTS idx_automation_script_versions_hash
244
+ ON automation_script_versions (script_id, package_sha256);
165
245
  CREATE TABLE IF NOT EXISTS workspace_registry (
166
246
  id TEXT PRIMARY KEY,
167
247
  display_name TEXT NOT NULL,
@@ -317,6 +397,7 @@ function ensureLocalCoreAcpSchema(db) {
317
397
  ensureColumn(db, 'scheduled_job_runs', 'delivery_error', 'TEXT');
318
398
  ensureColumn(db, 'scheduled_job_runs', 'last_bridge_event_at', 'TEXT');
319
399
  ensureColumn(db, 'threads', 'agent_mode', "TEXT NOT NULL DEFAULT 'default'");
400
+ ensureColumn(db, 'automations', 'legacy_metadata_json', 'TEXT');
320
401
  }
321
402
  function ensureColumn(db, table, column, definition) {
322
403
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AutomationActionExecutor = void 0;
4
+ exports.renderAutomationPrompt = renderAutomationPrompt;
5
+ const scheduled_bridge_session_js_1 = require("../scheduler/scheduled-bridge-session.js");
6
+ const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
7
+ const run_polling_js_1 = require("../scheduler/run-polling.js");
8
+ const thread_resolution_js_1 = require("../scheduler/thread-resolution.js");
9
+ const AUTOMATION_RUN_PERMISSION_MODE = 'bypassPermissions';
10
+ const UNSAFE_PROMPT_KEYS = new Set(['__proto__', 'constructor', 'prototype', 'toString']);
11
+ class AutomationActionExecutor {
12
+ options;
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+ async execute(input, timeoutMs = 15 * 60 * 1_000) {
17
+ const { automation } = input;
18
+ const workspaceRouter = this.options.getWorkspaceRouter();
19
+ const threadId = await this.resolveThread(automation);
20
+ const prompt = renderAutomationPrompt(automation.action.promptTemplate, input.promptVariables);
21
+ const channelRuntime = automation.delivery.platform === 'local'
22
+ ? undefined
23
+ : this.options.getChannelRuntime(automation.delivery.platform);
24
+ const bridge = channelRuntime
25
+ ? await scheduled_bridge_session_js_1.ScheduledBridgeSession.open({
26
+ target: {
27
+ id: automation.id,
28
+ workspaceId: automation.workspaceId,
29
+ platform: automation.delivery.platform,
30
+ route: automation.delivery.route,
31
+ title: automation.title,
32
+ promptTemplate: automation.action.promptTemplate,
33
+ },
34
+ threadId,
35
+ workspaceRouter,
36
+ getChannelRuntime: () => channelRuntime,
37
+ noticeIcon: automation.originKind === 'automation-monitor'
38
+ && input.promptVariables.sourceType === 'stock.quote' ? '📈' : '🔔',
39
+ noticeTitle: automation.title,
40
+ })
41
+ : undefined;
42
+ try {
43
+ const sendResult = await workspaceRouter.sendThreadMessage(threadId, prompt, {
44
+ permissionMode: AUTOMATION_RUN_PERMISSION_MODE,
45
+ runtimeEnv: (0, scheduled_job_route_js_1.buildPlatformRuntimeEnv)(automation.delivery.platform, automation.delivery.route),
46
+ });
47
+ await (0, run_polling_js_1.waitForRunCompletion)(this.options.store, sendResult.runId, timeoutMs, automation.originKind === 'automation-monitor' ? 'Monitor' : 'Automation');
48
+ const thread = await workspaceRouter.getThread(threadId);
49
+ const replyText = [...thread.messages]
50
+ .reverse()
51
+ .find((message) => message.role === 'assistant' && message.kind === 'final')
52
+ ?.content;
53
+ return {
54
+ threadId,
55
+ acpRunId: sendResult.runId,
56
+ replyText,
57
+ deliveryMode: bridge ? 'bridge-stream' : 'thread-only',
58
+ deliveryStatus: 'succeeded',
59
+ lastBridgeEventAt: bridge ? new Date().toISOString() : undefined,
60
+ };
61
+ }
62
+ finally {
63
+ await bridge?.close();
64
+ }
65
+ }
66
+ async resolveThread(automation) {
67
+ const workspaceRouter = this.options.getWorkspaceRouter();
68
+ const route = automation.delivery.route;
69
+ const platform = automation.delivery.platform;
70
+ if (automation.action.executionMode === 'same-thread') {
71
+ const binding = this.options.store.getPlatformThreadBinding(automation.workspaceId, route.channelId, route.participantId || '', platform);
72
+ if (binding?.thread_id && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, binding.thread_id))
73
+ return binding.thread_id;
74
+ if (route.threadId && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, route.threadId))
75
+ return route.threadId;
76
+ }
77
+ const label = automation.originKind === 'automation-monitor' ? 'Monitor' : 'Automation';
78
+ const title = platform === 'local'
79
+ ? `[${label}] ${automation.title}`
80
+ : `[${label}:${(0, scheduled_job_route_js_1.getChannelPlatformBase)(platform) || platform}] ${automation.title}`;
81
+ const existing = (await workspaceRouter.listThreads(automation.workspaceId))
82
+ .find((thread) => thread.title === title);
83
+ if (existing)
84
+ return existing.id;
85
+ return (await workspaceRouter.createThread(automation.workspaceId, title)).id;
86
+ }
87
+ }
88
+ exports.AutomationActionExecutor = AutomationActionExecutor;
89
+ function renderAutomationPrompt(template, values) {
90
+ return String(template || '').replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g, (_match, key) => {
91
+ if (UNSAFE_PROMPT_KEYS.has(key))
92
+ return '';
93
+ const descriptor = Object.getOwnPropertyDescriptor(values, key);
94
+ if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value'))
95
+ return '';
96
+ return serializePromptValue(descriptor.value);
97
+ });
98
+ }
99
+ function serializePromptValue(value) {
100
+ if (value === null || value === undefined)
101
+ return '';
102
+ if (typeof value !== 'object')
103
+ return String(value);
104
+ try {
105
+ return JSON.stringify(toSafeJsonValue(value, new Set())) ?? '';
106
+ }
107
+ catch {
108
+ return '[Unserializable]';
109
+ }
110
+ }
111
+ function toSafeJsonValue(value, seen) {
112
+ if (value === null || typeof value !== 'object') {
113
+ return typeof value === 'bigint' ? String(value) : value;
114
+ }
115
+ if (seen.has(value))
116
+ throw new Error('Circular prompt value.');
117
+ seen.add(value);
118
+ try {
119
+ if (Array.isArray(value)) {
120
+ return value.map((_entry, index) => {
121
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
122
+ return descriptor && Object.prototype.hasOwnProperty.call(descriptor, 'value')
123
+ ? toSafeJsonValue(descriptor.value, seen)
124
+ : null;
125
+ });
126
+ }
127
+ const result = Object.create(null);
128
+ for (const key of Object.keys(value)) {
129
+ if (UNSAFE_PROMPT_KEYS.has(key))
130
+ continue;
131
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
132
+ if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value'))
133
+ continue;
134
+ const nested = descriptor.value;
135
+ if (typeof nested === 'function' || typeof nested === 'symbol' || nested === undefined)
136
+ continue;
137
+ result[key] = toSafeJsonValue(nested, seen);
138
+ }
139
+ return result;
140
+ }
141
+ finally {
142
+ seen.delete(value);
143
+ }
144
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.admitConditionEvaluation = admitConditionEvaluation;
4
+ exports.decideTrigger = decideTrigger;
5
+ exports.evaluateCondition = evaluateCondition;
6
+ exports.decideCondition = decideCondition;
7
+ const condition_evaluator_js_1 = require("./condition-evaluator.js");
8
+ function admitConditionEvaluation(evaluationRunning) {
9
+ return evaluationRunning
10
+ ? { admitted: false, conditionOutcome: 'skipped', triggerDecision: 'skipped_concurrent' }
11
+ : { admitted: true };
12
+ }
13
+ function decideTrigger(input) {
14
+ if (!input.matched) {
15
+ return { conditionOutcome: 'not_matched', triggerDecision: 'not_rising', nextMatch: false };
16
+ }
17
+ if (input.previous === true) {
18
+ return { conditionOutcome: 'matched', triggerDecision: 'not_rising', nextMatch: true };
19
+ }
20
+ if (input.coolingDown) {
21
+ return { conditionOutcome: 'matched', triggerDecision: 'skipped_cooldown', nextMatch: true };
22
+ }
23
+ if (input.actionRunning) {
24
+ return { conditionOutcome: 'matched', triggerDecision: 'skipped_action_running', nextMatch: true };
25
+ }
26
+ return { conditionOutcome: 'matched', triggerDecision: 'triggered', nextMatch: true };
27
+ }
28
+ function evaluateCondition(condition, payload = {}) {
29
+ switch (condition.kind) {
30
+ case 'always':
31
+ return { kind: 'evaluated', matched: true };
32
+ case 'expression':
33
+ return { kind: 'evaluated', matched: (0, condition_evaluator_js_1.evaluateRestrictedExpression)(condition.expression, payload) };
34
+ case 'approved-script':
35
+ return {
36
+ kind: 'script-delegation',
37
+ request: {
38
+ scriptId: condition.scriptId,
39
+ approvedVersionId: condition.approvedVersionId,
40
+ edge: condition.edge,
41
+ payload,
42
+ },
43
+ };
44
+ }
45
+ }
46
+ function decideCondition(input, evaluator = evaluateCondition) {
47
+ const admission = admitConditionEvaluation(input.evaluationRunning === true);
48
+ if (!admission.admitted) {
49
+ return {
50
+ kind: 'decision',
51
+ conditionOutcome: admission.conditionOutcome,
52
+ triggerDecision: admission.triggerDecision,
53
+ nextMatch: input.previous,
54
+ };
55
+ }
56
+ try {
57
+ const evaluation = evaluator(input.condition, input.payload);
58
+ if (evaluation.kind === 'script-delegation')
59
+ return evaluation;
60
+ return {
61
+ kind: 'decision',
62
+ ...decideTrigger({
63
+ previous: input.previous,
64
+ matched: evaluation.matched,
65
+ coolingDown: input.coolingDown,
66
+ actionRunning: input.actionRunning,
67
+ }),
68
+ };
69
+ }
70
+ catch (error) {
71
+ return {
72
+ kind: 'decision',
73
+ conditionOutcome: 'error',
74
+ triggerDecision: 'not_evaluated',
75
+ nextMatch: input.previous,
76
+ error: error instanceof Error ? error.message : String(error),
77
+ };
78
+ }
79
+ }
@@ -2,88 +2,55 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutomationConversationExecutor = void 0;
4
4
  exports.renderMonitorPrompt = renderMonitorPrompt;
5
- const scheduled_bridge_session_js_1 = require("../scheduler/scheduled-bridge-session.js");
6
- const scheduled_job_route_js_1 = require("../scheduler/scheduled-job-route.js");
7
- const run_polling_js_1 = require("../scheduler/run-polling.js");
8
- const thread_resolution_js_1 = require("../scheduler/thread-resolution.js");
9
- const MONITOR_RUN_PERMISSION_MODE = 'bypassPermissions';
5
+ const automation_action_executor_js_1 = require("./automation-action-executor.js");
10
6
  class AutomationConversationExecutor {
11
- options;
7
+ executor;
12
8
  constructor(options) {
13
- this.options = options;
9
+ this.executor = new automation_action_executor_js_1.AutomationActionExecutor(options);
14
10
  }
15
11
  async execute(monitor, event, timeoutMs = 15 * 60 * 1000) {
16
- const workspaceRouter = this.options.getWorkspaceRouter();
17
- const threadId = await this.resolveThread(monitor);
18
- const prompt = renderMonitorPrompt(monitor.promptTemplate, event, monitor);
19
- const channelRuntime = monitor.platform === 'local' ? undefined : this.options.getChannelRuntime(monitor.platform);
20
- const bridge = channelRuntime
21
- ? await scheduled_bridge_session_js_1.ScheduledBridgeSession.open({
22
- target: {
23
- id: monitor.id,
24
- workspaceId: monitor.workspaceId,
25
- platform: monitor.platform,
26
- route: monitor.route,
27
- title: monitor.title,
12
+ const result = await this.executor.execute({
13
+ automation: {
14
+ id: monitor.id,
15
+ workspaceId: monitor.workspaceId,
16
+ title: monitor.title,
17
+ enabled: monitor.enabled,
18
+ health: 'healthy',
19
+ activation: { kind: 'provider-event', sourceType: monitor.sourceType, sourceConfig: monitor.sourceConfig },
20
+ condition: { kind: 'always' },
21
+ action: {
22
+ kind: 'agent-prompt',
28
23
  promptTemplate: monitor.promptTemplate,
24
+ executionMode: monitor.executionMode === 'same-thread' ? 'same-thread' : 'side-thread',
29
25
  },
30
- threadId,
31
- workspaceRouter,
32
- getChannelRuntime: () => channelRuntime,
33
- noticeIcon: monitor.sourceType === 'stock.quote' ? '📈' : '🔔',
34
- noticeTitle: monitor.title,
35
- })
36
- : undefined;
37
- try {
38
- const sendResult = await workspaceRouter.sendThreadMessage(threadId, prompt, {
39
- permissionMode: MONITOR_RUN_PERMISSION_MODE,
40
- runtimeEnv: (0, scheduled_job_route_js_1.buildPlatformRuntimeEnv)(monitor.platform, monitor.route),
41
- });
42
- await (0, run_polling_js_1.waitForRunCompletion)(this.options.store, sendResult.runId, timeoutMs, 'Monitor');
43
- const thread = await workspaceRouter.getThread(threadId);
44
- const replyText = [...thread.messages]
45
- .reverse()
46
- .find((message) => message.role === 'assistant' && message.kind === 'final')
47
- ?.content;
48
- return {
49
- threadId,
50
- runId: sendResult.runId,
51
- replyText,
52
- deliveryMode: bridge ? 'bridge-stream' : 'thread-only',
53
- deliveryStatus: 'succeeded',
54
- lastBridgeEventAt: bridge ? new Date().toISOString() : undefined,
55
- };
56
- }
57
- finally {
58
- await bridge?.close();
59
- }
60
- }
61
- async resolveThread(monitor) {
62
- const workspaceRouter = this.options.getWorkspaceRouter();
63
- if (monitor.executionMode === 'same-thread') {
64
- const binding = this.options.store.getPlatformThreadBinding(monitor.workspaceId, monitor.route.channelId, monitor.route.participantId || '', monitor.platform);
65
- if (binding?.thread_id && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, binding.thread_id)) {
66
- return binding.thread_id;
67
- }
68
- if (monitor.route.threadId && await (0, thread_resolution_js_1.threadExists)(workspaceRouter, monitor.route.threadId)) {
69
- return monitor.route.threadId;
70
- }
71
- }
72
- const title = monitor.platform === 'local'
73
- ? `[Monitor] ${monitor.title}`
74
- : `[Monitor:${(0, scheduled_job_route_js_1.getChannelPlatformBase)(monitor.platform) || monitor.platform}] ${monitor.title}`;
75
- const existing = (await workspaceRouter.listThreads(monitor.workspaceId))
76
- .find((thread) => thread.title === title);
77
- if (existing) {
78
- return existing.id;
79
- }
80
- const created = await workspaceRouter.createThread(monitor.workspaceId, title);
81
- return created.id;
26
+ delivery: { platform: monitor.platform, route: monitor.route },
27
+ policies: { concurrency: 'skip-if-running', cooldownMs: monitor.cooldownMs },
28
+ consecutiveEvaluationFailures: 0,
29
+ createdAt: monitor.createdAt,
30
+ updatedAt: monitor.updatedAt,
31
+ originKind: 'automation-monitor',
32
+ },
33
+ evaluation: {
34
+ id: `legacy-monitor-event:${monitor.id}`,
35
+ automationId: monitor.id,
36
+ status: 'finished',
37
+ activationKind: 'provider-event',
38
+ startedAt: event.occurredAt,
39
+ finishedAt: event.occurredAt,
40
+ conditionOutcome: 'matched',
41
+ triggerDecision: 'triggered',
42
+ },
43
+ promptVariables: monitorPromptVariables(event, monitor),
44
+ }, timeoutMs);
45
+ return { ...result, runId: result.acpRunId };
82
46
  }
83
47
  }
84
48
  exports.AutomationConversationExecutor = AutomationConversationExecutor;
85
49
  function renderMonitorPrompt(template, event, monitor) {
86
- const values = {
50
+ return String(template || '').replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g, (_match, key) => String(monitorPromptVariables(event, monitor)[key] ?? ''));
51
+ }
52
+ function monitorPromptVariables(event, monitor) {
53
+ return {
87
54
  title: monitor.title,
88
55
  sourceType: event.sourceType,
89
56
  subject: event.subject,
@@ -91,5 +58,4 @@ function renderMonitorPrompt(template, event, monitor) {
91
58
  timestamp: event.occurredAt,
92
59
  ...event.payload,
93
60
  };
94
- return String(template || '').replace(/\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g, (_match, key) => String(values[key] ?? ''));
95
61
  }