@xopcai/xopc 0.0.118 → 0.0.120
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.
- package/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dzUrQoeZ.js → agent-avatar-dicebear-APTlX9Sq.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CFW_FS_V.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-DTKc5HHT.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-BTciFrE9.js +1 -0
- package/dist/gateway/static/root/assets/{apps-page--wMEL00f.js → apps-page-DT52OrbM.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-Cki4SfU2.js → archive-plugin-CiHaUMII.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-D-KnS2Do.js → attachment-load-t4gSrNjL.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CtysjSoQ.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-B2YvT3ES.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D2sgvJja.js → binary-plugins-BAbSldW5.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DIq-4Gvb.js → block-editor-BNr_82xl.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-BQEXPhDU.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-tzD702Gg.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-AGhTueAc.js +1 -0
- package/dist/gateway/static/root/assets/channel-recipient-api-DL_KzwGE.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-DRTutLlN.js +1 -0
- package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-DneJVuge.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-B3B1eqnr.js +2 -0
- package/dist/gateway/static/root/assets/dreaming-settings-BEwWA1yf.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DYu1KaFQ.js → extension-debug-page-Dl2kO0Sf.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-B3W6QwlZ.js → extension-page-DmbLPsx_.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D7VQ-cxE.js → extension-settings-page-BS2rx40e.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B7xDPu-R.js → fetch-B3ME5Eri.js} +1 -1
- package/dist/gateway/static/root/assets/format-cron-label-arqgGlVV.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-BTBLSeUu.js → gateway-config-api-DI9_BBTo.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-DAFI_T0W.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CYj9FWCp.js → gateway-startup-retry-CSZQTz6K.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DLuz4jC9.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CQQgzPr3.js → goals-config-api-Bhzqrp2w.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BHitvJAv.js → goals-page-DTAfv9Ft.js} +2 -2
- package/dist/gateway/static/root/assets/goals-settings-CWN2iirQ.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-CkkkHvOi.js +1 -0
- package/dist/gateway/static/root/assets/index-CnjzMw5i.js +191 -0
- package/dist/gateway/static/root/assets/index-E1QinYKp.css +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-kMp08SlX.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-DjbfSsfA.js → locale-store-Ba72bFmP.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-C2Uqvae9.js → logs-page-CDXDlS_W.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-BwOFrJ2E.js → markdown-split-Bc0w40vz.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Cnz6Q5G6.js → media-plugins-DJ_HvgIy.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CISb1HLv.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BTwxMIgZ.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BBfOeB0m.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-B-Svpmza.js → note-image-lightbox-4zntqpZq.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-VocWOjoK.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Bss4TiwP.js → preview-open-alternatives-BbA7sRd_.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXwjuD_Q.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BRNjdgKq.js → save-bar-controls-Dividh61.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-pRheF2CO.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-Dub9sy8r.js → schema-form-D6PiPxfr.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CpcVySQK.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BVy_TawT.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BeFLavGi.js → settings-collapsible-section-BMCOfuE_.js} +1 -1
- package/dist/gateway/static/root/assets/settings-form-section-DBkGwpIN.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-CZpNyCWn.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-NxoW5Y57.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-MVHLLu_a.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-C8glrdqe.js → share-preview-page-B0suFCfj.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-C6DBbQGo.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-6hJmhwSn.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Im1MA0Iw.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-CrmEnyX4.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-CD2wtgZV.js → theme-store-Bt6vAkSB.js} +1 -1
- package/dist/gateway/static/root/assets/typed-models-lib-BAsGn25g.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-DqlWTsDb.js → use-channel-catalog-C7vcAoGb.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-QAQWGelF.js +1 -0
- package/dist/gateway/static/root/assets/utils-Dl9efgnV.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-C73IVZeC.js → voice-api-key-field-D-6XueTv.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-player-store-C_ArLJPM.js → voice-player-store-CMC5NOJp.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DVPllR4k.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-B94WISTW.js +18 -0
- package/dist/gateway/static/root/index.html +8 -9
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +4 -5
- package/dist/src/agent/agent-manager.js +4 -8
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +3 -2
- package/dist/src/agent/embedded/run-for-session.js +102 -14
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.d.ts +0 -8
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/index.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
- package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.d.ts +0 -1
- package/dist/src/agent/lifecycle/progress.js +1 -6
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.d.ts +2 -2
- package/dist/src/agent/memory/builtin-provider.js +2 -2
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +0 -7
- package/dist/src/agent/memory/dreaming/light-sweep.js +16 -277
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/short-term-store.js +5 -5
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/dreaming/utils.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/utils.js +2 -2
- package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
- package/dist/src/agent/memory/index.d.ts +0 -2
- package/dist/src/agent/memory/index.js +1 -2
- package/dist/src/agent/middleware/self-verify.d.ts +0 -1
- package/dist/src/agent/middleware/self-verify.js +0 -2
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/models/index.d.ts +1 -1
- package/dist/src/agent/models/manager.d.ts +4 -20
- package/dist/src/agent/models/manager.js +9 -126
- package/dist/src/agent/models/manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +11 -10
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +4 -4
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +0 -12
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/subagent-context.js +1 -1
- package/dist/src/agent/prompt/subagent-context.js.map +1 -1
- package/dist/src/agent/prompt/types.d.ts +1 -1
- package/dist/src/agent/reply/startup-context.js +6 -105
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -12
- package/dist/src/agent/service.js +3 -81
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +2 -2
- package/dist/src/agent/session/session-config-service.d.ts +11 -11
- package/dist/src/agent/session/session-config-service.js +14 -14
- package/dist/src/agent/session/session-config-service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +3 -2
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/starter-agents.js +12 -12
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/automation-tool.d.ts +14 -0
- package/dist/src/agent/tools/automation-tool.js +102 -0
- package/dist/src/agent/tools/automation-tool.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.js +1 -1
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -3
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/index.js +2 -2
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent-manifest/resolver.d.ts +1 -0
- package/dist/src/agent-manifest/resolver.js +1 -0
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +6 -0
- package/dist/src/agent-manifest/schema.js +12 -3
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +1 -1
- package/dist/src/ai-assist/text-assist.js +56 -0
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/auth/profiles/store.js.map +1 -1
- package/dist/src/automations/api/routes.d.ts +3 -0
- package/dist/src/automations/api/routes.js +193 -0
- package/dist/src/automations/api/routes.js.map +1 -0
- package/dist/src/automations/domain/index.d.ts +3 -0
- package/dist/src/automations/domain/index.js +3 -0
- package/dist/src/automations/domain/schedule.d.ts +4 -0
- package/dist/src/automations/domain/schedule.js +37 -0
- package/dist/src/automations/domain/schedule.js.map +1 -0
- package/dist/src/automations/domain/types.d.ts +160 -0
- package/dist/src/automations/domain/validation.d.ts +370 -0
- package/dist/src/automations/domain/validation.js +149 -0
- package/dist/src/automations/domain/validation.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
- package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
- package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
- package/dist/src/automations/draft/automation-draft-service.js +135 -0
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
- package/dist/src/automations/draft/automation-draft-validator.js +105 -0
- package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
- package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
- package/dist/src/automations/draft/index.d.ts +3 -0
- package/dist/src/automations/draft/index.js +3 -0
- package/dist/src/automations/index.d.ts +3 -0
- package/dist/src/automations/index.js +8 -0
- package/dist/src/automations/product-events.d.ts +5 -0
- package/dist/src/automations/product-events.js +21 -0
- package/dist/src/automations/product-events.js.map +1 -0
- package/dist/src/automations/service/action-executor.d.ts +9 -0
- package/dist/src/automations/service/action-executor.js +157 -0
- package/dist/src/automations/service/action-executor.js.map +1 -0
- package/dist/src/automations/service/automation-service.d.ts +54 -0
- package/dist/src/automations/service/automation-service.js +404 -0
- package/dist/src/automations/service/automation-service.js.map +1 -0
- package/dist/src/automations/service/index.d.ts +2 -0
- package/dist/src/automations/service/index.js +3 -0
- package/dist/src/automations/storage/automation-repository.d.ts +6 -0
- package/dist/src/automations/storage/automation-repository.js +61 -0
- package/dist/src/automations/storage/automation-repository.js.map +1 -0
- package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
- package/dist/src/automations/storage/automation-run-repository.js +130 -0
- package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
- package/dist/src/automations/storage/index.d.ts +2 -0
- package/dist/src/automations/storage/index.js +3 -0
- package/dist/src/channels/plugin-types.d.ts +3 -0
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/cli/command-catalog.js +0 -39
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +0 -1
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +0 -4
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agents.js +7 -6
- package/dist/src/cli/commands/agents.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
- package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
- package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.js +2 -2
- package/dist/src/cli/commands/doctor/flow.js.map +1 -1
- package/dist/src/cli/commands/gateway/call.js +2 -2
- package/dist/src/cli/commands/gateway/call.js.map +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/init.js +27 -9
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/tui.js +24 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/templates.js +3 -2
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -0
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +9 -0
- package/dist/src/commands/agents.config.js +40 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +4 -3
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/config-surface.d.ts +3 -0
- package/dist/src/config/index.d.ts +0 -1
- package/dist/src/config/index.js +3 -3
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/paths.d.ts +0 -9
- package/dist/src/config/paths.js +1 -14
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +0 -1
- package/dist/src/config/profile.js.map +1 -1
- package/dist/src/config/rules.js +0 -5
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +13 -12
- package/dist/src/config/schema.js +22 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +0 -12
- package/dist/src/config/web-patch.js +2 -29
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/extensions/api.d.ts +2 -0
- package/dist/src/extensions/api.js +10 -0
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
- package/dist/src/extensions/extension-registry-impl.js +8 -0
- package/dist/src/extensions/extension-registry-impl.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +3 -3
- package/dist/src/extensions/loader.js +3 -3
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/sdk/testing.d.ts +2 -0
- package/dist/src/extensions/sdk/testing.js +7 -0
- package/dist/src/extensions/sdk/testing.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +10 -1
- package/dist/src/extensions/types/index.d.ts +1 -1
- package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +1 -0
- package/dist/src/gateway/agents-admin.js +13 -15
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
- package/dist/src/gateway/capability-presets-admin.js +19 -10
- package/dist/src/gateway/capability-presets-admin.js.map +1 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
- package/dist/src/gateway/heartbeat/service.d.ts +0 -2
- package/dist/src/gateway/heartbeat/service.js +0 -7
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +15 -6
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +27 -37
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +2 -2
- package/dist/src/gateway/hono/routes/home.js +34 -25
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -6
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
- package/dist/src/gateway/hono/routes/migrations.js +35 -0
- package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
- package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/run-loop.js +2 -0
- package/dist/src/gateway/run-loop.js.map +1 -1
- package/dist/src/gateway/security/operator-scopes.js +5 -1
- package/dist/src/gateway/security/operator-scopes.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
- package/dist/src/gateway/service/config-coordinator.js +14 -8
- package/dist/src/gateway/service/config-coordinator.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +2 -1
- package/dist/src/gateway/service/sessions-api.js +6 -1
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +7 -3
- package/dist/src/gateway/service.js +61 -27
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-service.js +45 -4
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
- package/dist/src/migrations/config/default-capability-preset.js +135 -0
- package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
- package/dist/src/migrations/index.d.ts +4 -0
- package/dist/src/migrations/index.js +4 -0
- package/dist/src/migrations/registry.d.ts +8 -0
- package/dist/src/migrations/registry.js +18 -0
- package/dist/src/migrations/registry.js.map +1 -0
- package/dist/src/migrations/runner.d.ts +17 -0
- package/dist/src/migrations/runner.js +191 -0
- package/dist/src/migrations/runner.js.map +1 -0
- package/dist/src/migrations/types.d.ts +34 -0
- package/dist/src/notes/service.js +24 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/model-registry.d.ts +0 -1
- package/dist/src/providers/model-registry.js +0 -3
- package/dist/src/providers/model-registry.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
- package/dist/src/routing/resolve-tui-session-key.js +14 -3
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
- package/dist/src/session/transcript-outline.d.ts +47 -0
- package/dist/src/session/transcript-outline.js +481 -0
- package/dist/src/session/transcript-outline.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +0 -2
- package/dist/src/storage/sqlite/index.js +1 -3
- package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
- package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
- package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/row-mappers.js +3 -1
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +56 -46
- package/dist/src/tui/backends/embedded-backend.d.ts +6 -0
- package/dist/src/tui/backends/embedded-backend.js +19 -9
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +14 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +4 -0
- package/dist/src/tui/tui-commands.d.ts +5 -0
- package/dist/src/tui/tui-commands.js +43 -0
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
- package/dist/src/tui/tui-transcript-tree.js +17 -257
- package/dist/src/tui/tui-transcript-tree.js.map +1 -1
- package/dist/src/tui/tui-types.d.ts +2 -0
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +7 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/workflows/domain/index.js +1 -1
- package/dist/src/workflows/domain/run.d.ts +7 -7
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/index.js +2 -2
- package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
- package/dist/src/workflows/service/workflow-run-service.js +31 -9
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
- package/package.json +4 -2
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-bxYJVJpx.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-BCIykXlI.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +0 -1
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +0 -2
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +0 -1
- package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
- package/dist/gateway/static/root/assets/format-interval-label-BzxafKxR.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +0 -1
- package/dist/gateway/static/root/assets/goals-settings-CYVY4NGp.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DriO_CN9.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +0 -1
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +0 -1
- package/dist/gateway/static/root/assets/index-Cc41r16l.js +0 -191
- package/dist/gateway/static/root/assets/interval-presets-DFPCKW_W.js +0 -1
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CcVcqstx.js +0 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-CUCKODde.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-dmyaPOTG.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-DI-LN_8G.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +0 -1
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +0 -18
- package/dist/src/agent/fallback/error.d.ts +0 -22
- package/dist/src/agent/fallback/error.js +0 -32
- package/dist/src/agent/fallback/error.js.map +0 -1
- package/dist/src/agent/fallback/index.d.ts +0 -5
- package/dist/src/agent/fallback/index.js +0 -9
- package/dist/src/agent/fallback/index.js.map +0 -1
- package/dist/src/agent/memory/memory-flush.d.ts +0 -27
- package/dist/src/agent/memory/memory-flush.js +0 -124
- package/dist/src/agent/memory/memory-flush.js.map +0 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
- package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
- package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
- package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
- package/dist/src/agent/tools/cronjob-tool.js +0 -274
- package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
- package/dist/src/cli/commands/cron-cli.d.ts +0 -2
- package/dist/src/cli/commands/cron-cli.js +0 -15
- package/dist/src/cli/commands/cron-cli.js.map +0 -1
- package/dist/src/cli/commands/cron.d.ts +0 -4
- package/dist/src/cli/commands/cron.js +0 -188
- package/dist/src/cli/commands/cron.js.map +0 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
- package/dist/src/cron/execution-types.d.ts +0 -42
- package/dist/src/cron/executor.d.ts +0 -67
- package/dist/src/cron/executor.js +0 -669
- package/dist/src/cron/executor.js.map +0 -1
- package/dist/src/cron/index.d.ts +0 -7
- package/dist/src/cron/index.js +0 -7
- package/dist/src/cron/job-content.d.ts +0 -5
- package/dist/src/cron/job-content.js +0 -15
- package/dist/src/cron/job-content.js.map +0 -1
- package/dist/src/cron/run-log-store.d.ts +0 -12
- package/dist/src/cron/run-log-store.js +0 -58
- package/dist/src/cron/run-log-store.js.map +0 -1
- package/dist/src/cron/schedule.d.ts +0 -10
- package/dist/src/cron/schedule.js +0 -85
- package/dist/src/cron/schedule.js.map +0 -1
- package/dist/src/cron/service.d.ts +0 -58
- package/dist/src/cron/service.js +0 -419
- package/dist/src/cron/service.js.map +0 -1
- package/dist/src/cron/types.d.ts +0 -183
- package/dist/src/cron/validation.d.ts +0 -500
- package/dist/src/cron/validation.js +0 -192
- package/dist/src/cron/validation.js.map +0 -1
- package/dist/src/cron/workflow-run-completion.d.ts +0 -23
- package/dist/src/cron/workflow-run-completion.js +0 -72
- package/dist/src/cron/workflow-run-completion.js.map +0 -1
- package/dist/src/extensions/types/phase4.js +0 -1
- package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
- package/dist/src/gateway/hono/routes/cron.js +0 -109
- package/dist/src/gateway/hono/routes/cron.js.map +0 -1
- package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
- package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
- package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
- package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
- package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
- package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
- /package/dist/src/{cron → automations/domain}/types.js +0 -0
- /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
- /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
- /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { init_agent_scope, normalizeAgentId } from "../../agent/agent-scope.js";
|
|
2
|
+
import { buildSessionKey, init_session_key } from "../../routing/session-key.js";
|
|
3
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
4
|
+
import { init_logger } from "../../utils/logger.js";
|
|
5
|
+
import crypto from "node:crypto";
|
|
6
|
+
//#region src/automations/service/action-executor.ts
|
|
7
|
+
init_agent_scope();
|
|
8
|
+
init_session_key();
|
|
9
|
+
init_logger();
|
|
10
|
+
const log = createLogger("Automation:ActionExecutor");
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = 18e4;
|
|
12
|
+
function withTimeout(promise, timeoutMs, signal) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
if (signal.aborted) {
|
|
15
|
+
reject(/* @__PURE__ */ new Error("Automation run was cancelled"));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Automation timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
19
|
+
const onAbort = () => {
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
reject(/* @__PURE__ */ new Error("Automation run was cancelled"));
|
|
22
|
+
};
|
|
23
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
24
|
+
promise.then((value) => {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
signal.removeEventListener("abort", onAbort);
|
|
27
|
+
resolve(value);
|
|
28
|
+
}, (err) => {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
signal.removeEventListener("abort", onAbort);
|
|
31
|
+
reject(err);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
var AutomationActionExecutor = class {
|
|
36
|
+
deps = {};
|
|
37
|
+
setDeps(deps) {
|
|
38
|
+
this.deps = {
|
|
39
|
+
...this.deps,
|
|
40
|
+
...deps
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async execute(automation, run, signal) {
|
|
44
|
+
const timeoutMs = (automation.action.timeoutSeconds ?? automation.reliability?.timeoutSeconds ?? 0) > 0 ? (automation.action.timeoutSeconds ?? automation.reliability?.timeoutSeconds) * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
45
|
+
return withTimeout(this.executeWithoutTimeout(automation, run, signal), timeoutMs, signal).catch((err) => {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
return {
|
|
48
|
+
status: message.toLowerCase().includes("cancelled") ? "cancelled" : message.toLowerCase().includes("timed out") ? "timeout" : "failed",
|
|
49
|
+
error: message
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async executeWithoutTimeout(automation, run, signal) {
|
|
54
|
+
if (signal.aborted) return {
|
|
55
|
+
status: "cancelled",
|
|
56
|
+
error: "Automation run was cancelled"
|
|
57
|
+
};
|
|
58
|
+
if (automation.action.kind === "workflow") return this.executeWorkflow(automation, automation.action, run);
|
|
59
|
+
return this.executeAgent(automation, automation.action);
|
|
60
|
+
}
|
|
61
|
+
async executeAgent(automation, action) {
|
|
62
|
+
const agentService = this.deps.agentService;
|
|
63
|
+
if (!agentService?.turnDispatcher?.processDirect) return {
|
|
64
|
+
status: "failed",
|
|
65
|
+
error: "Agent service is not available"
|
|
66
|
+
};
|
|
67
|
+
const sessionKey = buildSessionKey({
|
|
68
|
+
agentId: normalizeAgentId(action.agentId || this.deps.getDefaultAgentId?.() || "main"),
|
|
69
|
+
source: "automation",
|
|
70
|
+
accountId: "default",
|
|
71
|
+
peerKind: "dm",
|
|
72
|
+
peerId: `${automation.id}-${crypto.randomUUID().slice(0, 8)}`
|
|
73
|
+
});
|
|
74
|
+
await agentService.sessionConfig?.applyAutomationWorkingDirectory?.(sessionKey, action.workingDirectory);
|
|
75
|
+
if (agentService.sessionConfig?.applyAutomationModelOverride) {
|
|
76
|
+
if (!await agentService.sessionConfig.applyAutomationModelOverride(sessionKey, action.model) && action.model) log.warn({
|
|
77
|
+
automationId: automation.id,
|
|
78
|
+
sessionKey,
|
|
79
|
+
model: action.model
|
|
80
|
+
}, "Automation model override invalid; using agent default");
|
|
81
|
+
}
|
|
82
|
+
const response = await agentService.turnDispatcher.processDirect(buildSafetyInstruction(automation, action.instruction), sessionKey);
|
|
83
|
+
const model = agentService.getModelForSession?.(sessionKey);
|
|
84
|
+
return {
|
|
85
|
+
status: "succeeded",
|
|
86
|
+
summary: response.slice(0, 500),
|
|
87
|
+
sessionKey,
|
|
88
|
+
model
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async executeWorkflow(automation, action, run) {
|
|
92
|
+
const safetyMode = automation.safety?.mode ?? "auto_apply";
|
|
93
|
+
if (safetyMode === "suggest_only") return {
|
|
94
|
+
status: "succeeded",
|
|
95
|
+
summary: `Suggest only: workflow ${action.workflowId} was not started. Review the automation and upgrade safety mode to run it automatically.`
|
|
96
|
+
};
|
|
97
|
+
if (safetyMode === "ask_before_apply") return {
|
|
98
|
+
status: "succeeded",
|
|
99
|
+
summary: `Ask before applying: workflow ${action.workflowId} is ready, but was not started automatically. Upgrade to Auto apply when you trust this automation.`
|
|
100
|
+
};
|
|
101
|
+
const workflowRunService = this.deps.workflowRunService;
|
|
102
|
+
if (!workflowRunService) return {
|
|
103
|
+
status: "failed",
|
|
104
|
+
error: "Workflow service is not available"
|
|
105
|
+
};
|
|
106
|
+
const agentId = normalizeAgentId(action.agentId || this.deps.getDefaultAgentId?.() || "main");
|
|
107
|
+
const idempotencyKey = `automation:${automation.id}:${run.id}`;
|
|
108
|
+
const result = await workflowRunService.startWorkflowRun({
|
|
109
|
+
agentId,
|
|
110
|
+
definitionId: action.workflowId,
|
|
111
|
+
input: action.input,
|
|
112
|
+
inputEnvelope: action.inputEnvelope,
|
|
113
|
+
goal: action.goal,
|
|
114
|
+
concurrency: action.concurrency,
|
|
115
|
+
maxSubagents: action.maxSubagents,
|
|
116
|
+
source: {
|
|
117
|
+
kind: "automation",
|
|
118
|
+
automationId: automation.id,
|
|
119
|
+
runId: run.id
|
|
120
|
+
},
|
|
121
|
+
idempotencyKey
|
|
122
|
+
});
|
|
123
|
+
if (result.ok === false) return {
|
|
124
|
+
status: "failed",
|
|
125
|
+
error: result.message
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
status: "succeeded",
|
|
129
|
+
summary: `Started workflow run ${result.runId}`,
|
|
130
|
+
sessionKey: result.sessionKey,
|
|
131
|
+
workflowRunId: result.runId
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function buildSafetyInstruction(automation, instruction) {
|
|
136
|
+
const mode = automation.safety?.mode ?? "auto_apply";
|
|
137
|
+
if (mode === "suggest_only") return [
|
|
138
|
+
"Automation safety mode: Suggest only.",
|
|
139
|
+
"Only analyze the situation and produce a concise recommendation.",
|
|
140
|
+
"Do not modify files, notes, goals, workflows, external systems, or persistent state.",
|
|
141
|
+
"If a change seems useful, describe the exact change for the user to review.",
|
|
142
|
+
"",
|
|
143
|
+
instruction
|
|
144
|
+
].join("\n");
|
|
145
|
+
if (mode === "ask_before_apply") return [
|
|
146
|
+
"Automation safety mode: Ask before applying.",
|
|
147
|
+
"Draft the proposed change or action and clearly ask for user confirmation before applying anything.",
|
|
148
|
+
"Do not perform irreversible or external side effects unless the user has explicitly approved them in this run.",
|
|
149
|
+
"",
|
|
150
|
+
instruction
|
|
151
|
+
].join("\n");
|
|
152
|
+
return instruction;
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { AutomationActionExecutor };
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=action-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-executor.js","names":[],"sources":["../../../../src/automations/service/action-executor.ts"],"sourcesContent":["import crypto from 'node:crypto';\n\nimport { DEFAULT_AGENT_ID, normalizeAgentId } from '../../agent/agent-scope.js';\nimport { buildSessionKey } from '../../routing/session-key.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type {\n Automation,\n AutomationAction,\n AutomationActionOutcome,\n AutomationDeps,\n AutomationRun,\n} from '../domain/types.js';\n\nconst log = createLogger('Automation:ActionExecutor');\n\nconst DEFAULT_TIMEOUT_MS = 180_000;\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs: number, signal: AbortSignal): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n if (signal.aborted) {\n reject(new Error('Automation run was cancelled'));\n return;\n }\n const timer = setTimeout(() => reject(new Error(`Automation timed out after ${timeoutMs}ms`)), timeoutMs);\n const onAbort = () => {\n clearTimeout(timer);\n reject(new Error('Automation run was cancelled'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n promise.then(\n (value) => {\n clearTimeout(timer);\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n signal.removeEventListener('abort', onAbort);\n reject(err);\n },\n );\n });\n}\n\nexport class AutomationActionExecutor {\n private deps: AutomationDeps = {};\n\n setDeps(deps: AutomationDeps): void {\n this.deps = { ...this.deps, ...deps };\n }\n\n async execute(\n automation: Automation,\n run: AutomationRun,\n signal: AbortSignal,\n ): Promise<AutomationActionOutcome> {\n const timeoutMs =\n (automation.action.timeoutSeconds ?? automation.reliability?.timeoutSeconds ?? 0) > 0\n ? (automation.action.timeoutSeconds ?? automation.reliability?.timeoutSeconds)! * 1000\n : DEFAULT_TIMEOUT_MS;\n\n return withTimeout(this.executeWithoutTimeout(automation, run, signal), timeoutMs, signal).catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n return {\n status: message.toLowerCase().includes('cancelled')\n ? 'cancelled'\n : message.toLowerCase().includes('timed out')\n ? 'timeout'\n : 'failed',\n error: message,\n };\n });\n }\n\n private async executeWithoutTimeout(\n automation: Automation,\n run: AutomationRun,\n signal: AbortSignal,\n ): Promise<AutomationActionOutcome> {\n if (signal.aborted) {\n return { status: 'cancelled', error: 'Automation run was cancelled' };\n }\n if (automation.action.kind === 'workflow') {\n return this.executeWorkflow(automation, automation.action, run);\n }\n return this.executeAgent(automation, automation.action);\n }\n\n private async executeAgent(\n automation: Automation,\n action: Extract<AutomationAction, { kind: 'agent' }>,\n ): Promise<AutomationActionOutcome> {\n const agentService = this.deps.agentService;\n if (!agentService?.turnDispatcher?.processDirect) {\n return { status: 'failed', error: 'Agent service is not available' };\n }\n const agentId = normalizeAgentId(\n action.agentId || this.deps.getDefaultAgentId?.() || DEFAULT_AGENT_ID,\n );\n const sessionKey = buildSessionKey({\n agentId,\n source: 'automation',\n accountId: 'default',\n peerKind: 'dm',\n peerId: `${automation.id}-${crypto.randomUUID().slice(0, 8)}`,\n });\n\n await agentService.sessionConfig?.applyAutomationWorkingDirectory?.(\n sessionKey,\n action.workingDirectory,\n );\n if (agentService.sessionConfig?.applyAutomationModelOverride) {\n const ok = await agentService.sessionConfig.applyAutomationModelOverride(sessionKey, action.model);\n if (!ok && action.model) {\n log.warn(\n { automationId: automation.id, sessionKey, model: action.model },\n 'Automation model override invalid; using agent default',\n );\n }\n }\n\n const response = await agentService.turnDispatcher.processDirect(\n buildSafetyInstruction(automation, action.instruction),\n sessionKey,\n );\n const model = agentService.getModelForSession?.(sessionKey);\n return {\n status: 'succeeded',\n summary: response.slice(0, 500),\n sessionKey,\n model,\n };\n }\n\n private async executeWorkflow(\n automation: Automation,\n action: Extract<AutomationAction, { kind: 'workflow' }>,\n run: AutomationRun,\n ): Promise<AutomationActionOutcome> {\n const safetyMode = automation.safety?.mode ?? 'auto_apply';\n if (safetyMode === 'suggest_only') {\n return {\n status: 'succeeded',\n summary: `Suggest only: workflow ${action.workflowId} was not started. Review the automation and upgrade safety mode to run it automatically.`,\n };\n }\n if (safetyMode === 'ask_before_apply') {\n return {\n status: 'succeeded',\n summary: `Ask before applying: workflow ${action.workflowId} is ready, but was not started automatically. Upgrade to Auto apply when you trust this automation.`,\n };\n }\n const workflowRunService = this.deps.workflowRunService;\n if (!workflowRunService) {\n return { status: 'failed', error: 'Workflow service is not available' };\n }\n const agentId = normalizeAgentId(\n action.agentId || this.deps.getDefaultAgentId?.() || DEFAULT_AGENT_ID,\n );\n const idempotencyKey = `automation:${automation.id}:${run.id}`;\n const result = await workflowRunService.startWorkflowRun({\n agentId,\n definitionId: action.workflowId,\n input: action.input,\n inputEnvelope: action.inputEnvelope,\n goal: action.goal,\n concurrency: action.concurrency,\n maxSubagents: action.maxSubagents,\n source: { kind: 'automation', automationId: automation.id, runId: run.id },\n idempotencyKey,\n });\n if (result.ok === false) {\n return { status: 'failed', error: result.message };\n }\n return {\n status: 'succeeded',\n summary: `Started workflow run ${result.runId}`,\n sessionKey: result.sessionKey,\n workflowRunId: result.runId,\n };\n }\n}\n\nfunction buildSafetyInstruction(automation: Automation, instruction: string): string {\n const mode = automation.safety?.mode ?? 'auto_apply';\n if (mode === 'suggest_only') {\n return [\n 'Automation safety mode: Suggest only.',\n 'Only analyze the situation and produce a concise recommendation.',\n 'Do not modify files, notes, goals, workflows, external systems, or persistent state.',\n 'If a change seems useful, describe the exact change for the user to review.',\n '',\n instruction,\n ].join('\\n');\n }\n if (mode === 'ask_before_apply') {\n return [\n 'Automation safety mode: Ask before applying.',\n 'Draft the proposed change or action and clearly ask for user confirmation before applying anything.',\n 'Do not perform irreversible or external side effects unless the user has explicitly approved them in this run.',\n '',\n instruction,\n ].join('\\n');\n }\n return instruction;\n}\n"],"mappings":";;;;;;kBAEgF;kBACjB;aACV;AASrD,MAAM,MAAM,aAAa,4BAA4B;AAErD,MAAM,qBAAqB;AAE3B,SAAS,YAAe,SAAqB,WAAmB,QAAiC;AAC/F,QAAO,IAAI,SAAY,SAAS,WAAW;AACzC,MAAI,OAAO,SAAS;AAClB,0BAAO,IAAI,MAAM,+BAA+B,CAAC;AACjD;;EAEF,MAAM,QAAQ,iBAAiB,uBAAO,IAAI,MAAM,8BAA8B,UAAU,IAAI,CAAC,EAAE,UAAU;EACzG,MAAM,gBAAgB;AACpB,gBAAa,MAAM;AACnB,0BAAO,IAAI,MAAM,+BAA+B,CAAC;;AAEnD,SAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AACzD,UAAQ,MACL,UAAU;AACT,gBAAa,MAAM;AACnB,UAAO,oBAAoB,SAAS,QAAQ;AAC5C,WAAQ,MAAM;MAEf,QAAQ;AACP,gBAAa,MAAM;AACnB,UAAO,oBAAoB,SAAS,QAAQ;AAC5C,UAAO,IAAI;IAEd;GACD;;AAGJ,IAAa,2BAAb,MAAsC;CACpC,OAA+B,EAAE;CAEjC,QAAQ,MAA4B;AAClC,OAAK,OAAO;GAAE,GAAG,KAAK;GAAM,GAAG;GAAM;;CAGvC,MAAM,QACJ,YACA,KACA,QACkC;EAClC,MAAM,aACH,WAAW,OAAO,kBAAkB,WAAW,aAAa,kBAAkB,KAAK,KAC/E,WAAW,OAAO,kBAAkB,WAAW,aAAa,kBAAmB,MAChF;AAEN,SAAO,YAAY,KAAK,sBAAsB,YAAY,KAAK,OAAO,EAAE,WAAW,OAAO,CAAC,OAAO,QAAQ;GACxG,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,UAAO;IACL,QAAQ,QAAQ,aAAa,CAAC,SAAS,YAAY,GAC/C,cACA,QAAQ,aAAa,CAAC,SAAS,YAAY,GACzC,YACA;IACN,OAAO;IACR;IACD;;CAGJ,MAAc,sBACZ,YACA,KACA,QACkC;AAClC,MAAI,OAAO,QACT,QAAO;GAAE,QAAQ;GAAa,OAAO;GAAgC;AAEvE,MAAI,WAAW,OAAO,SAAS,WAC7B,QAAO,KAAK,gBAAgB,YAAY,WAAW,QAAQ,IAAI;AAEjE,SAAO,KAAK,aAAa,YAAY,WAAW,OAAO;;CAGzD,MAAc,aACZ,YACA,QACkC;EAClC,MAAM,eAAe,KAAK,KAAK;AAC/B,MAAI,CAAC,cAAc,gBAAgB,cACjC,QAAO;GAAE,QAAQ;GAAU,OAAO;GAAkC;EAKtE,MAAM,aAAa,gBAAgB;GACjC,SAJc,iBACd,OAAO,WAAW,KAAK,KAAK,qBAAqB,IAAA,OAG1C;GACP,QAAQ;GACR,WAAW;GACX,UAAU;GACV,QAAQ,GAAG,WAAW,GAAG,GAAG,OAAO,YAAY,CAAC,MAAM,GAAG,EAAE;GAC5D,CAAC;AAEF,QAAM,aAAa,eAAe,kCAChC,YACA,OAAO,iBACR;AACD,MAAI,aAAa,eAAe;OAE1B,CAAC,MADY,aAAa,cAAc,6BAA6B,YAAY,OAAO,MAAM,IACvF,OAAO,MAChB,KAAI,KACF;IAAE,cAAc,WAAW;IAAI;IAAY,OAAO,OAAO;IAAO,EAChE,yDACD;;EAIL,MAAM,WAAW,MAAM,aAAa,eAAe,cACjD,uBAAuB,YAAY,OAAO,YAAY,EACtD,WACD;EACD,MAAM,QAAQ,aAAa,qBAAqB,WAAW;AAC3D,SAAO;GACL,QAAQ;GACR,SAAS,SAAS,MAAM,GAAG,IAAI;GAC/B;GACA;GACD;;CAGH,MAAc,gBACZ,YACA,QACA,KACkC;EAClC,MAAM,aAAa,WAAW,QAAQ,QAAQ;AAC9C,MAAI,eAAe,eACjB,QAAO;GACL,QAAQ;GACR,SAAS,0BAA0B,OAAO,WAAW;GACtD;AAEH,MAAI,eAAe,mBACjB,QAAO;GACL,QAAQ;GACR,SAAS,iCAAiC,OAAO,WAAW;GAC7D;EAEH,MAAM,qBAAqB,KAAK,KAAK;AACrC,MAAI,CAAC,mBACH,QAAO;GAAE,QAAQ;GAAU,OAAO;GAAqC;EAEzE,MAAM,UAAU,iBACd,OAAO,WAAW,KAAK,KAAK,qBAAqB,IAAA,OAClD;EACD,MAAM,iBAAiB,cAAc,WAAW,GAAG,GAAG,IAAI;EAC1D,MAAM,SAAS,MAAM,mBAAmB,iBAAiB;GACvD;GACA,cAAc,OAAO;GACrB,OAAO,OAAO;GACd,eAAe,OAAO;GACtB,MAAM,OAAO;GACb,aAAa,OAAO;GACpB,cAAc,OAAO;GACrB,QAAQ;IAAE,MAAM;IAAc,cAAc,WAAW;IAAI,OAAO,IAAI;IAAI;GAC1E;GACD,CAAC;AACF,MAAI,OAAO,OAAO,MAChB,QAAO;GAAE,QAAQ;GAAU,OAAO,OAAO;GAAS;AAEpD,SAAO;GACL,QAAQ;GACR,SAAS,wBAAwB,OAAO;GACxC,YAAY,OAAO;GACnB,eAAe,OAAO;GACvB;;;AAIL,SAAS,uBAAuB,YAAwB,aAA6B;CACnF,MAAM,OAAO,WAAW,QAAQ,QAAQ;AACxC,KAAI,SAAS,eACX,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK;AAEd,KAAI,SAAS,mBACX,QAAO;EACL;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK;AAEd,QAAO"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Automation, AutomationDeps, AutomationEvent, AutomationMetrics, AutomationProductEventRun, AutomationRun, AutomationRunEvent } from '../domain/types.js';
|
|
2
|
+
import { type CreateAutomationInput, type UpdateAutomationInput } from '../domain/validation.js';
|
|
3
|
+
export declare class AutomationAlreadyRunningError extends Error {
|
|
4
|
+
readonly automationId: string;
|
|
5
|
+
readonly runningRunId?: string;
|
|
6
|
+
constructor(automationId: string, runningRunId?: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class AutomationService {
|
|
9
|
+
private readonly executor;
|
|
10
|
+
private timer;
|
|
11
|
+
private stopped;
|
|
12
|
+
private runningScheduler;
|
|
13
|
+
private deps;
|
|
14
|
+
private maxConcurrentRuns;
|
|
15
|
+
private readonly activeRuns;
|
|
16
|
+
setDeps(deps: AutomationDeps): void;
|
|
17
|
+
initialize(options?: {
|
|
18
|
+
maxConcurrentRuns?: number;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
stop(): Promise<void>;
|
|
21
|
+
create(input: CreateAutomationInput): Promise<Automation>;
|
|
22
|
+
list(): Promise<Automation[]>;
|
|
23
|
+
get(id: string): Promise<Automation | null>;
|
|
24
|
+
update(id: string, patch: UpdateAutomationInput): Promise<Automation | null>;
|
|
25
|
+
remove(id: string): Promise<boolean>;
|
|
26
|
+
pause(id: string): Promise<Automation | null>;
|
|
27
|
+
resume(id: string): Promise<Automation | null>;
|
|
28
|
+
runNow(id: string): Promise<AutomationRun>;
|
|
29
|
+
rerunFromRun(runId: string): Promise<AutomationRun>;
|
|
30
|
+
triggerEvent(event: AutomationEvent): Promise<AutomationRun[]>;
|
|
31
|
+
listRuns(options?: {
|
|
32
|
+
automationId?: string;
|
|
33
|
+
limit?: number;
|
|
34
|
+
}): Promise<AutomationRun[]>;
|
|
35
|
+
listRunsForProductEvent(options: {
|
|
36
|
+
eventType: string;
|
|
37
|
+
source?: string;
|
|
38
|
+
payloadKey?: string;
|
|
39
|
+
payloadValue?: string;
|
|
40
|
+
limit?: number;
|
|
41
|
+
}): Promise<AutomationProductEventRun[]>;
|
|
42
|
+
getRun(runId: string): Promise<AutomationRun | null>;
|
|
43
|
+
listRunEvents(runId: string): Promise<AutomationRunEvent[]>;
|
|
44
|
+
cancelRun(runId: string): Promise<boolean>;
|
|
45
|
+
getMetrics(): Promise<AutomationMetrics>;
|
|
46
|
+
private recomputeNextRuns;
|
|
47
|
+
private armTimer;
|
|
48
|
+
private onTimer;
|
|
49
|
+
private startRun;
|
|
50
|
+
private executeRun;
|
|
51
|
+
private appendRunEvent;
|
|
52
|
+
private finishAutomationRun;
|
|
53
|
+
private postAfterRunWebhook;
|
|
54
|
+
}
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { computeNextAutomationRunAtMs, timerDelayUntil } from "../domain/schedule.js";
|
|
4
|
+
import { AutomationSchema, CreateAutomationSchema, UpdateAutomationSchema } from "../domain/validation.js";
|
|
5
|
+
import { AutomationActionExecutor } from "./action-executor.js";
|
|
6
|
+
import { deleteAutomation, getAutomation, listAutomations, saveAutomation, saveAutomations } from "../storage/automation-repository.js";
|
|
7
|
+
import { appendAutomationRunEvent, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, saveAutomationRun } from "../storage/automation-run-repository.js";
|
|
8
|
+
import "../storage/index.js";
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
10
|
+
//#region src/automations/service/automation-service.ts
|
|
11
|
+
init_logger();
|
|
12
|
+
const log = createLogger("AutomationService");
|
|
13
|
+
const DEFAULT_MAX_CONCURRENT_RUNS = 5;
|
|
14
|
+
const MISSED_RUN_STAGGER_MS = 5e3;
|
|
15
|
+
var AutomationAlreadyRunningError = class extends Error {
|
|
16
|
+
constructor(automationId, runningRunId) {
|
|
17
|
+
super(`Automation is already running: ${automationId}`);
|
|
18
|
+
this.automationId = automationId;
|
|
19
|
+
this.runningRunId = runningRunId;
|
|
20
|
+
this.name = "AutomationAlreadyRunningError";
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var AutomationService = class {
|
|
24
|
+
executor = new AutomationActionExecutor();
|
|
25
|
+
timer = null;
|
|
26
|
+
stopped = true;
|
|
27
|
+
runningScheduler = false;
|
|
28
|
+
deps = {};
|
|
29
|
+
maxConcurrentRuns = DEFAULT_MAX_CONCURRENT_RUNS;
|
|
30
|
+
activeRuns = /* @__PURE__ */ new Map();
|
|
31
|
+
setDeps(deps) {
|
|
32
|
+
this.deps = {
|
|
33
|
+
...this.deps,
|
|
34
|
+
...deps
|
|
35
|
+
};
|
|
36
|
+
this.executor.setDeps(this.deps);
|
|
37
|
+
}
|
|
38
|
+
async initialize(options) {
|
|
39
|
+
this.maxConcurrentRuns = Math.max(1, Math.floor(options?.maxConcurrentRuns ?? DEFAULT_MAX_CONCURRENT_RUNS));
|
|
40
|
+
this.stopped = false;
|
|
41
|
+
await this.recomputeNextRuns({ catchUp: true });
|
|
42
|
+
this.armTimer();
|
|
43
|
+
log.info("Automation service initialized");
|
|
44
|
+
}
|
|
45
|
+
async stop() {
|
|
46
|
+
this.stopped = true;
|
|
47
|
+
if (this.timer) {
|
|
48
|
+
clearTimeout(this.timer);
|
|
49
|
+
this.timer = null;
|
|
50
|
+
}
|
|
51
|
+
for (const controller of this.activeRuns.values()) controller.abort();
|
|
52
|
+
log.info("Automation service stopped");
|
|
53
|
+
}
|
|
54
|
+
async create(input) {
|
|
55
|
+
const parsed = CreateAutomationSchema.parse(input);
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
const automation = AutomationSchema.parse({
|
|
58
|
+
...parsed,
|
|
59
|
+
id: parsed.id?.trim() || randomUUID().slice(0, 12),
|
|
60
|
+
enabled: parsed.enabled ?? true,
|
|
61
|
+
safety: parsed.safety ?? { mode: "auto_apply" },
|
|
62
|
+
afterRun: parsed.afterRun ?? { kind: "none" },
|
|
63
|
+
state: parsed.state ?? {},
|
|
64
|
+
createdAtMs: now,
|
|
65
|
+
updatedAtMs: now
|
|
66
|
+
});
|
|
67
|
+
automation.state.nextRunAtMs = computeNextAutomationRunAtMs(automation, now);
|
|
68
|
+
saveAutomation(automation);
|
|
69
|
+
this.armTimer();
|
|
70
|
+
return automation;
|
|
71
|
+
}
|
|
72
|
+
async list() {
|
|
73
|
+
return listAutomations();
|
|
74
|
+
}
|
|
75
|
+
async get(id) {
|
|
76
|
+
return getAutomation(id);
|
|
77
|
+
}
|
|
78
|
+
async update(id, patch) {
|
|
79
|
+
const parsed = UpdateAutomationSchema.parse(patch);
|
|
80
|
+
const current = getAutomation(id);
|
|
81
|
+
if (!current) return null;
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
const next = AutomationSchema.parse({
|
|
84
|
+
...current,
|
|
85
|
+
...parsed,
|
|
86
|
+
id: current.id,
|
|
87
|
+
createdAtMs: current.createdAtMs,
|
|
88
|
+
updatedAtMs: now,
|
|
89
|
+
state: {
|
|
90
|
+
...current.state,
|
|
91
|
+
...parsed.state ?? {}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
if ("enabled" in parsed || "trigger" in parsed) next.state.nextRunAtMs = computeNextAutomationRunAtMs(next, now);
|
|
95
|
+
saveAutomation(next);
|
|
96
|
+
this.armTimer();
|
|
97
|
+
return next;
|
|
98
|
+
}
|
|
99
|
+
async remove(id) {
|
|
100
|
+
const automation = getAutomation(id);
|
|
101
|
+
if (automation?.state.runningRunId) this.activeRuns.get(automation.state.runningRunId)?.abort();
|
|
102
|
+
const removed = deleteAutomation(id);
|
|
103
|
+
if (removed) this.armTimer();
|
|
104
|
+
return removed;
|
|
105
|
+
}
|
|
106
|
+
async pause(id) {
|
|
107
|
+
return this.update(id, { enabled: false });
|
|
108
|
+
}
|
|
109
|
+
async resume(id) {
|
|
110
|
+
return this.update(id, { enabled: true });
|
|
111
|
+
}
|
|
112
|
+
async runNow(id) {
|
|
113
|
+
const automation = getAutomation(id);
|
|
114
|
+
if (!automation) throw new Error(`Automation not found: ${id}`);
|
|
115
|
+
if (automation.state.runningRunId) throw new AutomationAlreadyRunningError(id, automation.state.runningRunId);
|
|
116
|
+
return this.startRun(automation, { manual: true });
|
|
117
|
+
}
|
|
118
|
+
async rerunFromRun(runId) {
|
|
119
|
+
const previous = getAutomationRun(runId);
|
|
120
|
+
if (!previous) throw new Error(`Automation run not found: ${runId}`);
|
|
121
|
+
const automation = getAutomation(previous.automationId);
|
|
122
|
+
if (!automation) throw new Error(`Automation not found: ${previous.automationId}`);
|
|
123
|
+
if (automation.state.runningRunId) throw new AutomationAlreadyRunningError(automation.id, automation.state.runningRunId);
|
|
124
|
+
const triggerEvent = listAutomationRunEvents(runId).map((event) => readAutomationEventFromRunEvent(event)).find((event) => event !== null);
|
|
125
|
+
return this.startRun(automation, triggerEvent ? {
|
|
126
|
+
manual: false,
|
|
127
|
+
event: triggerEvent
|
|
128
|
+
} : { manual: true });
|
|
129
|
+
}
|
|
130
|
+
async triggerEvent(event) {
|
|
131
|
+
const normalized = {
|
|
132
|
+
...event,
|
|
133
|
+
occurredAtMs: event.occurredAtMs ?? Date.now()
|
|
134
|
+
};
|
|
135
|
+
const automations = listAutomations().filter((automation) => automation.enabled && automation.trigger.kind === "event" && !automation.state.runningRunId && matchesAutomationEvent(automation.trigger, normalized));
|
|
136
|
+
const availableSlots = Math.max(0, this.maxConcurrentRuns - this.activeRuns.size);
|
|
137
|
+
const started = [];
|
|
138
|
+
for (const automation of automations.slice(0, availableSlots)) started.push(await this.startRun(automation, {
|
|
139
|
+
manual: false,
|
|
140
|
+
event: normalized
|
|
141
|
+
}));
|
|
142
|
+
return started;
|
|
143
|
+
}
|
|
144
|
+
async listRuns(options) {
|
|
145
|
+
return listAutomationRuns(options);
|
|
146
|
+
}
|
|
147
|
+
async listRunsForProductEvent(options) {
|
|
148
|
+
return listAutomationRunsForProductEvent(options);
|
|
149
|
+
}
|
|
150
|
+
async getRun(runId) {
|
|
151
|
+
return getAutomationRun(runId);
|
|
152
|
+
}
|
|
153
|
+
async listRunEvents(runId) {
|
|
154
|
+
return listAutomationRunEvents(runId);
|
|
155
|
+
}
|
|
156
|
+
async cancelRun(runId) {
|
|
157
|
+
const controller = this.activeRuns.get(runId);
|
|
158
|
+
if (!controller) return false;
|
|
159
|
+
controller.abort();
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
async getMetrics() {
|
|
163
|
+
const automations = listAutomations();
|
|
164
|
+
const enabled = automations.filter((automation) => automation.enabled);
|
|
165
|
+
const next = enabled.filter((automation) => automation.state.nextRunAtMs != null).toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0))[0];
|
|
166
|
+
const oneHourAgo = Date.now() - 60 * 6e4;
|
|
167
|
+
return {
|
|
168
|
+
totalAutomations: automations.length,
|
|
169
|
+
enabledAutomations: enabled.length,
|
|
170
|
+
runningRuns: this.activeRuns.size,
|
|
171
|
+
failedLastHour: automations.filter((automation) => (automation.state.lastRunStatus === "failed" || automation.state.lastRunStatus === "timeout") && (automation.state.lastRunAtMs ?? 0) >= oneHourAgo).length,
|
|
172
|
+
nextRun: next?.state.nextRunAtMs ? {
|
|
173
|
+
automationId: next.id,
|
|
174
|
+
name: next.name,
|
|
175
|
+
runAtMs: next.state.nextRunAtMs
|
|
176
|
+
} : void 0
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
async recomputeNextRuns(options) {
|
|
180
|
+
const now = Date.now();
|
|
181
|
+
saveAutomations(listAutomations().map((automation, index) => {
|
|
182
|
+
const next = {
|
|
183
|
+
...automation,
|
|
184
|
+
state: { ...automation.state }
|
|
185
|
+
};
|
|
186
|
+
if (next.state.runningRunId) {
|
|
187
|
+
next.state.lastRunStatus = "failed";
|
|
188
|
+
next.state.lastError = "Interrupted by gateway restart";
|
|
189
|
+
next.state.consecutiveFailures = (next.state.consecutiveFailures ?? 0) + 1;
|
|
190
|
+
delete next.state.runningRunId;
|
|
191
|
+
}
|
|
192
|
+
const computed = computeNextAutomationRunAtMs(next, now);
|
|
193
|
+
next.state.nextRunAtMs = options?.catchUp && computed != null && computed <= now ? now + index * MISSED_RUN_STAGGER_MS : computed;
|
|
194
|
+
return next;
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
armTimer() {
|
|
198
|
+
if (this.stopped) return;
|
|
199
|
+
if (this.timer) {
|
|
200
|
+
clearTimeout(this.timer);
|
|
201
|
+
this.timer = null;
|
|
202
|
+
}
|
|
203
|
+
const next = listAutomations().filter((automation) => automation.enabled && automation.state.nextRunAtMs != null).toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0))[0];
|
|
204
|
+
if (!next?.state.nextRunAtMs) return;
|
|
205
|
+
this.timer = setTimeout(() => {
|
|
206
|
+
this.onTimer();
|
|
207
|
+
}, timerDelayUntil(next.state.nextRunAtMs));
|
|
208
|
+
this.timer.unref?.();
|
|
209
|
+
}
|
|
210
|
+
async onTimer() {
|
|
211
|
+
if (this.stopped) return;
|
|
212
|
+
if (this.runningScheduler) {
|
|
213
|
+
this.armTimer();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this.runningScheduler = true;
|
|
217
|
+
try {
|
|
218
|
+
const now = Date.now();
|
|
219
|
+
const due = listAutomations().filter((automation) => automation.enabled && automation.trigger.kind === "schedule" && automation.state.nextRunAtMs != null && automation.state.nextRunAtMs <= now && !automation.state.runningRunId).slice(0, this.maxConcurrentRuns);
|
|
220
|
+
await Promise.all(due.map((automation) => this.startRun(automation, { manual: false })));
|
|
221
|
+
} finally {
|
|
222
|
+
this.runningScheduler = false;
|
|
223
|
+
this.armTimer();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async startRun(automation, opts) {
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const run = {
|
|
229
|
+
id: randomUUID(),
|
|
230
|
+
automationId: automation.id,
|
|
231
|
+
automationName: automation.name,
|
|
232
|
+
status: "queued",
|
|
233
|
+
triggerSnapshot: automation.trigger,
|
|
234
|
+
actionSnapshot: automation.action,
|
|
235
|
+
manual: opts.manual,
|
|
236
|
+
createdAtMs: now
|
|
237
|
+
};
|
|
238
|
+
saveAutomationRun(run);
|
|
239
|
+
this.appendRunEvent(run, "run.queued", opts.event ? `Event ${opts.event.type} queued automation` : opts.manual ? "Manual run queued" : "Scheduled run queued", {
|
|
240
|
+
trigger: automation.trigger,
|
|
241
|
+
actionKind: automation.action.kind,
|
|
242
|
+
safety: automation.safety ?? { mode: "auto_apply" },
|
|
243
|
+
event: opts.event
|
|
244
|
+
});
|
|
245
|
+
const nextAutomation = {
|
|
246
|
+
...automation,
|
|
247
|
+
state: {
|
|
248
|
+
...automation.state,
|
|
249
|
+
runningRunId: run.id
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
saveAutomation(nextAutomation);
|
|
253
|
+
this.executeRun(nextAutomation, run).catch((err) => {
|
|
254
|
+
log.error({
|
|
255
|
+
err,
|
|
256
|
+
automationId: automation.id,
|
|
257
|
+
runId: run.id
|
|
258
|
+
}, `Automation run failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
259
|
+
});
|
|
260
|
+
return run;
|
|
261
|
+
}
|
|
262
|
+
async executeRun(automation, initialRun) {
|
|
263
|
+
const controller = new AbortController();
|
|
264
|
+
this.activeRuns.set(initialRun.id, controller);
|
|
265
|
+
const startedAtMs = Date.now();
|
|
266
|
+
let run = {
|
|
267
|
+
...initialRun,
|
|
268
|
+
status: "running",
|
|
269
|
+
startedAtMs
|
|
270
|
+
};
|
|
271
|
+
saveAutomationRun(run);
|
|
272
|
+
this.appendRunEvent(run, "run.started", "Automation run started");
|
|
273
|
+
let status = "failed";
|
|
274
|
+
let error;
|
|
275
|
+
let activePhase = "action";
|
|
276
|
+
try {
|
|
277
|
+
this.appendRunEvent(run, "action.started", `Running ${automation.action.kind} action`, {
|
|
278
|
+
actionKind: automation.action.kind,
|
|
279
|
+
safety: automation.safety ?? { mode: "auto_apply" }
|
|
280
|
+
});
|
|
281
|
+
const outcome = await this.executor.execute(automation, run, controller.signal);
|
|
282
|
+
status = outcome.status;
|
|
283
|
+
error = outcome.error;
|
|
284
|
+
this.appendRunEvent(run, status === "succeeded" ? "action.completed" : "action.failed", status === "succeeded" ? `${automation.action.kind} action completed` : `${automation.action.kind} action ${status}`, {
|
|
285
|
+
summary: outcome.summary,
|
|
286
|
+
error: outcome.error,
|
|
287
|
+
sessionKey: outcome.sessionKey,
|
|
288
|
+
workflowRunId: outcome.workflowRunId,
|
|
289
|
+
model: outcome.model
|
|
290
|
+
});
|
|
291
|
+
run = {
|
|
292
|
+
...run,
|
|
293
|
+
status,
|
|
294
|
+
summary: outcome.summary,
|
|
295
|
+
error,
|
|
296
|
+
sessionKey: outcome.sessionKey,
|
|
297
|
+
workflowRunId: outcome.workflowRunId,
|
|
298
|
+
model: outcome.model
|
|
299
|
+
};
|
|
300
|
+
if ((automation.safety?.mode ?? "auto_apply") !== "auto_apply" && automation.afterRun?.kind === "webhook") this.appendRunEvent(run, "after_run.completed", "After-run webhook skipped by safety mode", { safety: automation.safety ?? { mode: "auto_apply" } });
|
|
301
|
+
else if (automation.afterRun?.kind === "webhook") {
|
|
302
|
+
activePhase = "after_run";
|
|
303
|
+
this.appendRunEvent(run, "after_run.started", "Calling after-run webhook", { url: automation.afterRun.url });
|
|
304
|
+
await this.postAfterRunWebhook(automation.afterRun.url, run);
|
|
305
|
+
this.appendRunEvent(run, "after_run.completed", "After-run webhook completed");
|
|
306
|
+
}
|
|
307
|
+
} catch (err) {
|
|
308
|
+
error = err instanceof Error ? err.message : String(err);
|
|
309
|
+
status = controller.signal.aborted ? "cancelled" : "failed";
|
|
310
|
+
this.appendRunEvent(run, activePhase === "after_run" ? "after_run.failed" : "action.failed", `Automation run ${status}`, { error });
|
|
311
|
+
run = {
|
|
312
|
+
...run,
|
|
313
|
+
status,
|
|
314
|
+
error
|
|
315
|
+
};
|
|
316
|
+
} finally {
|
|
317
|
+
const endedAtMs = Date.now();
|
|
318
|
+
run = {
|
|
319
|
+
...run,
|
|
320
|
+
status,
|
|
321
|
+
endedAtMs,
|
|
322
|
+
durationMs: endedAtMs - startedAtMs
|
|
323
|
+
};
|
|
324
|
+
saveAutomationRun(run);
|
|
325
|
+
this.appendRunEvent(run, "run.completed", `Automation run ${status}`, {
|
|
326
|
+
status,
|
|
327
|
+
durationMs: run.durationMs,
|
|
328
|
+
error
|
|
329
|
+
});
|
|
330
|
+
this.activeRuns.delete(initialRun.id);
|
|
331
|
+
this.finishAutomationRun(automation.id, status, error, endedAtMs);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
appendRunEvent(run, type, message, data) {
|
|
335
|
+
appendAutomationRunEvent({
|
|
336
|
+
id: randomUUID(),
|
|
337
|
+
runId: run.id,
|
|
338
|
+
automationId: run.automationId,
|
|
339
|
+
type,
|
|
340
|
+
message,
|
|
341
|
+
data,
|
|
342
|
+
createdAtMs: Date.now()
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
finishAutomationRun(automationId, status, error, finishedAtMs) {
|
|
346
|
+
const current = getAutomation(automationId);
|
|
347
|
+
if (!current) return;
|
|
348
|
+
const consecutiveFailures = status === "failed" || status === "timeout" ? (current.state.consecutiveFailures ?? 0) + 1 : 0;
|
|
349
|
+
const disableAfter = current.reliability?.disableAfterConsecutiveFailures;
|
|
350
|
+
const shouldDisable = disableAfter != null && consecutiveFailures >= disableAfter;
|
|
351
|
+
const next = {
|
|
352
|
+
...current,
|
|
353
|
+
enabled: shouldDisable ? false : current.enabled,
|
|
354
|
+
state: {
|
|
355
|
+
...current.state,
|
|
356
|
+
lastRunAtMs: finishedAtMs,
|
|
357
|
+
lastRunStatus: status,
|
|
358
|
+
lastError: error,
|
|
359
|
+
consecutiveFailures
|
|
360
|
+
},
|
|
361
|
+
updatedAtMs: shouldDisable ? finishedAtMs : current.updatedAtMs
|
|
362
|
+
};
|
|
363
|
+
delete next.state.runningRunId;
|
|
364
|
+
next.state.nextRunAtMs = computeNextAutomationRunAtMs(next, finishedAtMs);
|
|
365
|
+
saveAutomation(next);
|
|
366
|
+
this.armTimer();
|
|
367
|
+
}
|
|
368
|
+
async postAfterRunWebhook(url, run) {
|
|
369
|
+
const response = await fetch(url, {
|
|
370
|
+
method: "POST",
|
|
371
|
+
headers: { "content-type": "application/json" },
|
|
372
|
+
body: JSON.stringify({ run })
|
|
373
|
+
});
|
|
374
|
+
if (!response.ok) {
|
|
375
|
+
const text = await response.text().catch(() => "");
|
|
376
|
+
throw new Error(`Automation webhook failed: HTTP ${response.status}${text ? ` ${text.slice(0, 200)}` : ""}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
function matchesAutomationEvent(trigger, event) {
|
|
381
|
+
if (trigger.eventType !== event.type) return false;
|
|
382
|
+
if (trigger.source && trigger.source !== event.source) return false;
|
|
383
|
+
const payloadMatch = trigger.payloadMatch;
|
|
384
|
+
if (!payloadMatch) return true;
|
|
385
|
+
const payload = event.payload ?? {};
|
|
386
|
+
return Object.entries(payloadMatch).every(([key, expected]) => Object.is(payload[key], expected));
|
|
387
|
+
}
|
|
388
|
+
function readAutomationEventFromRunEvent(event) {
|
|
389
|
+
if (!event.data || typeof event.data !== "object" || Array.isArray(event.data)) return null;
|
|
390
|
+
const raw = event.data.event;
|
|
391
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
392
|
+
const candidate = raw;
|
|
393
|
+
if (typeof candidate.type !== "string" || !candidate.type.trim()) return null;
|
|
394
|
+
return {
|
|
395
|
+
type: candidate.type,
|
|
396
|
+
source: typeof candidate.source === "string" ? candidate.source : void 0,
|
|
397
|
+
payload: candidate.payload && typeof candidate.payload === "object" && !Array.isArray(candidate.payload) ? candidate.payload : void 0,
|
|
398
|
+
occurredAtMs: typeof candidate.occurredAtMs === "number" ? candidate.occurredAtMs : void 0
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
//#endregion
|
|
402
|
+
export { AutomationAlreadyRunningError, AutomationService };
|
|
403
|
+
|
|
404
|
+
//# sourceMappingURL=automation-service.js.map
|