@overlordai/server 1.0.144 → 1.0.146

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 (230) hide show
  1. package/database/migrations/014-automations.sql +67 -0
  2. package/dist/adapters/command-parser.utils.d.ts +1 -0
  3. package/dist/adapters/command-parser.utils.d.ts.map +1 -1
  4. package/dist/adapters/command-parser.utils.js +14 -1
  5. package/dist/adapters/command-parser.utils.js.map +1 -1
  6. package/dist/adapters/help-text.d.ts.map +1 -1
  7. package/dist/adapters/help-text.js +2 -1
  8. package/dist/adapters/help-text.js.map +1 -1
  9. package/dist/adapters/nlu.service.d.ts.map +1 -1
  10. package/dist/adapters/nlu.service.js +4 -1
  11. package/dist/adapters/nlu.service.js.map +1 -1
  12. package/dist/app.module.d.ts.map +1 -1
  13. package/dist/app.module.js +2 -0
  14. package/dist/app.module.js.map +1 -1
  15. package/dist/automation/automation-executor.d.ts +23 -0
  16. package/dist/automation/automation-executor.d.ts.map +1 -0
  17. package/dist/automation/automation-executor.js +365 -0
  18. package/dist/automation/automation-executor.js.map +1 -0
  19. package/dist/automation/automation-scheduler.d.ts +21 -0
  20. package/dist/automation/automation-scheduler.d.ts.map +1 -0
  21. package/dist/automation/automation-scheduler.js +124 -0
  22. package/dist/automation/automation-scheduler.js.map +1 -0
  23. package/dist/automation/automation-template.service.d.ts +30 -0
  24. package/dist/automation/automation-template.service.d.ts.map +1 -0
  25. package/dist/automation/automation-template.service.js +66 -0
  26. package/dist/automation/automation-template.service.js.map +1 -0
  27. package/dist/automation/automation-trigger.d.ts +13 -0
  28. package/dist/automation/automation-trigger.d.ts.map +1 -0
  29. package/dist/automation/automation-trigger.js +96 -0
  30. package/dist/automation/automation-trigger.js.map +1 -0
  31. package/dist/automation/automation-validation.d.ts +14 -0
  32. package/dist/automation/automation-validation.d.ts.map +1 -0
  33. package/dist/automation/automation-validation.js +66 -0
  34. package/dist/automation/automation-validation.js.map +1 -0
  35. package/dist/automation/automation.module.d.ts +3 -0
  36. package/dist/automation/automation.module.d.ts.map +1 -0
  37. package/dist/automation/automation.module.js +33 -0
  38. package/dist/automation/automation.module.js.map +1 -0
  39. package/dist/automation/automation.service.d.ts +22 -0
  40. package/dist/automation/automation.service.d.ts.map +1 -0
  41. package/dist/automation/automation.service.js +232 -0
  42. package/dist/automation/automation.service.js.map +1 -0
  43. package/dist/database/database.service.d.ts +8 -0
  44. package/dist/database/database.service.d.ts.map +1 -1
  45. package/dist/database/database.service.js +16 -5
  46. package/dist/database/database.service.js.map +1 -1
  47. package/dist/database/repositories/automation.repository.d.ts +87 -0
  48. package/dist/database/repositories/automation.repository.d.ts.map +1 -0
  49. package/dist/database/repositories/automation.repository.js +531 -0
  50. package/dist/database/repositories/automation.repository.js.map +1 -0
  51. package/dist/database/repositories/task.repository.d.ts +1 -0
  52. package/dist/database/repositories/task.repository.d.ts.map +1 -1
  53. package/dist/database/repositories/task.repository.js +4 -2
  54. package/dist/database/repositories/task.repository.js.map +1 -1
  55. package/dist/database/repository.module.d.ts.map +1 -1
  56. package/dist/database/repository.module.js +2 -0
  57. package/dist/database/repository.module.js.map +1 -1
  58. package/dist/dispatcher/dispatcher.service.d.ts.map +1 -1
  59. package/dist/dispatcher/dispatcher.service.js +1 -0
  60. package/dist/dispatcher/dispatcher.service.js.map +1 -1
  61. package/dist/dispatcher/task-creation.service.d.ts +3 -3
  62. package/dist/dispatcher/task-creation.service.d.ts.map +1 -1
  63. package/dist/dispatcher/task-creation.service.js +14 -5
  64. package/dist/dispatcher/task-creation.service.js.map +1 -1
  65. package/dist/events/event-types.d.ts +31 -0
  66. package/dist/events/event-types.d.ts.map +1 -1
  67. package/dist/events/event-types.js +4 -0
  68. package/dist/events/event-types.js.map +1 -1
  69. package/dist/notifier/notification-consumer.d.ts.map +1 -1
  70. package/dist/notifier/notification-consumer.js +65 -1
  71. package/dist/notifier/notification-consumer.js.map +1 -1
  72. package/dist/notifier/notification-event-listener.d.ts +7 -2
  73. package/dist/notifier/notification-event-listener.d.ts.map +1 -1
  74. package/dist/notifier/notification-event-listener.js +56 -2
  75. package/dist/notifier/notification-event-listener.js.map +1 -1
  76. package/dist/notifier/notifier.service.d.ts +4 -1
  77. package/dist/notifier/notifier.service.d.ts.map +1 -1
  78. package/dist/notifier/notifier.service.js +23 -2
  79. package/dist/notifier/notifier.service.js.map +1 -1
  80. package/dist/notifier/template.service.d.ts +1 -1
  81. package/dist/notifier/template.service.d.ts.map +1 -1
  82. package/dist/notifier/template.service.js +14 -4
  83. package/dist/notifier/template.service.js.map +1 -1
  84. package/dist/web/automation.controller.d.ts +74 -0
  85. package/dist/web/automation.controller.d.ts.map +1 -0
  86. package/dist/web/automation.controller.js +539 -0
  87. package/dist/web/automation.controller.js.map +1 -0
  88. package/dist/web/frame-handlers/automation-report.handler.d.ts +10 -0
  89. package/dist/web/frame-handlers/automation-report.handler.d.ts.map +1 -0
  90. package/dist/web/frame-handlers/automation-report.handler.js +15 -0
  91. package/dist/web/frame-handlers/automation-report.handler.js.map +1 -0
  92. package/dist/web/frame-handlers/index.d.ts +1 -0
  93. package/dist/web/frame-handlers/index.d.ts.map +1 -1
  94. package/dist/web/frame-handlers/index.js +3 -1
  95. package/dist/web/frame-handlers/index.js.map +1 -1
  96. package/dist/web/frame-handlers/stage-confirm.handler.d.ts.map +1 -1
  97. package/dist/web/frame-handlers/stage-confirm.handler.js +1 -1
  98. package/dist/web/frame-handlers/stage-confirm.handler.js.map +1 -1
  99. package/dist/web/task.controller.d.ts +3 -0
  100. package/dist/web/task.controller.d.ts.map +1 -1
  101. package/dist/web/web-event.service.d.ts +20 -1
  102. package/dist/web/web-event.service.d.ts.map +1 -1
  103. package/dist/web/web-event.service.js +66 -2
  104. package/dist/web/web-event.service.js.map +1 -1
  105. package/dist/web/web.module.d.ts.map +1 -1
  106. package/dist/web/web.module.js +4 -1
  107. package/dist/web/web.module.js.map +1 -1
  108. package/dist/web/worker-channel.gateway.d.ts +2 -1
  109. package/dist/web/worker-channel.gateway.d.ts.map +1 -1
  110. package/dist/web/worker-channel.gateway.js +5 -2
  111. package/dist/web/worker-channel.gateway.js.map +1 -1
  112. package/package.json +5 -4
  113. package/public/assets/AccessTokensPage-jZ0fW6lX.js +1 -0
  114. package/public/assets/{AdminPage-OHTVG-ck.js → AdminPage-BhEFd__u.js} +1 -1
  115. package/public/assets/{AgentCliPage-BsZmnI3p.js → AgentCliPage-BlwF0Ske.js} +1 -1
  116. package/public/assets/{ApiReferencePage-8yiImnYs.js → ApiReferencePage-DYw-AFRb.js} +1 -1
  117. package/public/assets/{ArchitecturePage-Deswgqy2.js → ArchitecturePage-Bj4s2Tjl.js} +1 -1
  118. package/public/assets/{AuditLogPage-Hn4ivp8Y.js → AuditLogPage-Dw56aHuy.js} +1 -1
  119. package/public/assets/AutomationCreatePage-Dt2pGfgf.js +1 -0
  120. package/public/assets/AutomationDetailPage-DNYkC31X.js +16 -0
  121. package/public/assets/AutomationEditPage-C8IUsSvR.js +1 -0
  122. package/public/assets/AutomationListPage-Bqog--Ae.js +16 -0
  123. package/public/assets/AutomationRunDetailPage-C3PuPibC.js +6 -0
  124. package/public/assets/{BindPlatformPage-DjGHKswB.js → BindPlatformPage-M_2I5Qrq.js} +1 -1
  125. package/public/assets/BotIntegrationPage-CAwevaIk.js +1 -0
  126. package/public/assets/{BotManage-Dss1Y_jv.js → BotManage-DGBezqSD.js} +2 -2
  127. package/public/assets/{BotSetupPage-C_KKFdu3.js → BotSetupPage-C0Fs8ZnS.js} +2 -2
  128. package/public/assets/{ChangelogPage-5btaAfls.js → ChangelogPage-DlB2ibrO.js} +1 -1
  129. package/public/assets/{CliReferencePage--yAuXfNl.js → CliReferencePage-CZfrDLHw.js} +1 -1
  130. package/public/assets/ConfirmStageDialog-Z0pbQqim.js +7 -0
  131. package/public/assets/{DeploymentPage-Qi860C4T.js → DeploymentPage-7vnTwGfh.js} +1 -1
  132. package/public/assets/{DevWorkflowPage-CZks72g2.js → DevWorkflowPage-DuwsvFYh.js} +1 -1
  133. package/public/assets/DeveloperManage-D4RJh1ZW.js +16 -0
  134. package/public/assets/{DeveloperSetupPage-CSs2Mh7c.js → DeveloperSetupPage-BrCi0Lwe.js} +1 -1
  135. package/public/assets/{DocsIndexPage-BmSMwLvO.js → DocsIndexPage-rnTjEz8b.js} +1 -1
  136. package/public/assets/{DocsLayout-CunlDzH9.js → DocsLayout-C6xN_yk0.js} +1 -1
  137. package/public/assets/{DocsPrimitives-Bqnk0mEW.js → DocsPrimitives-IJB6nZ_z.js} +1 -1
  138. package/public/assets/{EditProjectPage-CJAdaxRE.js → EditProjectPage-BPUvr801.js} +2 -2
  139. package/public/assets/{EmptyState-DpRw-xch.js → EmptyState-CW1xfNCv.js} +1 -1
  140. package/public/assets/{EnvVariablesPage-DWD4RzmX.js → EnvVariablesPage-CR4pvBH3.js} +2 -2
  141. package/public/assets/{HomePage-oShWGYcN.js → HomePage-A0kDqIF6.js} +1 -1
  142. package/public/assets/{InfoRow-CTXIPrG6.js → InfoRow-D-vceQHX.js} +1 -1
  143. package/public/assets/{InstallationPage-BgbU06Ei.js → InstallationPage-DQOr1ZdF.js} +1 -1
  144. package/public/assets/{LandingPage-C-s-hSgz.js → LandingPage-B1mQ0b1M.js} +7 -12
  145. package/public/assets/{LocalDevelopmentPage-Cg4FYaCn.js → LocalDevelopmentPage-B3tPpv14.js} +1 -1
  146. package/public/assets/{LoginPage-BhyQxY5d.js → LoginPage-2TJGugqP.js} +1 -1
  147. package/public/assets/{MetricBar-DZOZStDZ.js → MetricBar-BWriVYES.js} +1 -1
  148. package/public/assets/{NotFoundPage-DaeTOzAm.js → NotFoundPage-CL8L-hAH.js} +1 -1
  149. package/public/assets/{OnboardingGuide-DGH0Yfsj.js → OnboardingGuide-Cdz3B-Hy.js} +1 -1
  150. package/public/assets/{PermissionsPage-D4Lqb40x.js → PermissionsPage-BdKxCcLI.js} +1 -1
  151. package/public/assets/{PipelineConfigPage-CAWpyPiY.js → PipelineConfigPage-CYPnPxIe.js} +1 -1
  152. package/public/assets/{PipelineEditorPage-BLDxO49P.js → PipelineEditorPage-Cx5jQ7sn.js} +2 -2
  153. package/public/assets/{PlanPage-UX5QUlvv.js → PlanPage-B8izWg2B.js} +1 -1
  154. package/public/assets/{ProfilePage-B73YqnCd.js → ProfilePage-S_chkZka.js} +1 -1
  155. package/public/assets/{ProjectDetailPage-eNAn85vT.js → ProjectDetailPage-DPjR4K6z.js} +3 -3
  156. package/public/assets/ProjectListPage-B7KDEb5r.js +6 -0
  157. package/public/assets/PtyTerminal-SPgs4fDa.js +38 -0
  158. package/public/assets/{QuickAuth-DSSMYJEC.js → QuickAuth-kStSentC.js} +1 -1
  159. package/public/assets/RemoveMemberConfirmDialog-nrYU_g4X.js +6 -0
  160. package/public/assets/ReviewAggregatePage-BycSqu1a.js +6 -0
  161. package/public/assets/{ReviewPage-BNa6T3xv.js → ReviewPage-CDyr8wXz.js} +1 -1
  162. package/public/assets/{Select-FmuTJbfh.js → Select-B0NXCdTE.js} +1 -1
  163. package/public/assets/{SettingsPage-aSrpn6Ta.js → SettingsPage-BOXtwa2r.js} +1 -1
  164. package/public/assets/{Skeleton-Bo0DEIHn.js → Skeleton-BiHQNXJ9.js} +1 -1
  165. package/public/assets/{SkillPage-BjiQKd7n.js → SkillPage-DBiTVuCH.js} +1 -1
  166. package/public/assets/{TaskDetailPage-BLNjDqnY.js → TaskDetailPage-CTVJwy-t.js} +2 -2
  167. package/public/assets/{TaskGuidePage-C5o7i2D0.js → TaskGuidePage-BsH7MBPf.js} +1 -1
  168. package/public/assets/TaskListPage-pui2im5r.js +1 -0
  169. package/public/assets/{TaskStatusBadge-CD8sO9C_.js → TaskStatusBadge-CeC-9VO9.js} +1 -1
  170. package/public/assets/TerminalHomePage-Bu10hJuQ.js +6 -0
  171. package/public/assets/TokenManage-Bo15S_D_.js +1 -0
  172. package/public/assets/{Tooltip-BKRBwA7o.js → Tooltip-BtLbD3s1.js} +1 -1
  173. package/public/assets/{TotpSetupPage-IVkRIgKh.js → TotpSetupPage-QOB1KoQV.js} +1 -1
  174. package/public/assets/{WorkerDetailPage-nw_gzQ45.js → WorkerDetailPage-BbUUJ-4x.js} +1 -1
  175. package/public/assets/WorkerListPage-Cz97ZJ44.js +6 -0
  176. package/public/assets/{WorkerOperationsPage-Clh8jDGG.js → WorkerOperationsPage-BVb41hZJ.js} +1 -1
  177. package/public/assets/{WorkerSetupGuidePage-C1wXY1wd.js → WorkerSetupGuidePage-Cidrk_C8.js} +1 -1
  178. package/public/assets/{WorkerSetupPage-CTCwHKaC.js → WorkerSetupPage-BEBJC4eO.js} +1 -1
  179. package/public/assets/{agent-type-options-5v4PgZnP.js → agent-type-options-js05RaN7.js} +1 -1
  180. package/public/assets/{arrow-left-CR_n40mK.js → arrow-left-B7mlJm2S.js} +1 -1
  181. package/public/assets/{arrow-right-D-j7nSgI.js → arrow-right-pahP-ey1.js} +1 -1
  182. package/public/assets/{bot--DUOKBmv.js → bot-Utar32Rx.js} +1 -1
  183. package/public/assets/{chevron-down-CDFiGGBG.js → chevron-down-rRjDei6n.js} +1 -1
  184. package/public/assets/{chevron-left-C_lJcnCg.js → chevron-left-Bh3DdiT8.js} +1 -1
  185. package/public/assets/{chevron-right-IZlTWMcO.js → chevron-right-BUIsW0nB.js} +1 -1
  186. package/public/assets/{chevron-up-DSOCVgRW.js → chevron-up-CC4d-5nr.js} +1 -1
  187. package/public/assets/circle-alert-DfjZjHfx.js +6 -0
  188. package/public/assets/clock-CcoV8c6t.js +6 -0
  189. package/public/assets/{copy-2UMMaHKT.js → copy-CVElRaVS.js} +1 -1
  190. package/public/assets/{download-D2NyL1OR.js → download-Cuv6Ei5j.js} +1 -1
  191. package/public/assets/{external-link-B9CWNSMc.js → external-link-Beb0-hR9.js} +1 -1
  192. package/public/assets/{file-text-COzaNu8e.js → file-text-DQb29yBJ.js} +1 -1
  193. package/public/assets/{git-fork-9KuFRmam.js → git-fork-IyYS1SDo.js} +1 -1
  194. package/public/assets/index-CFc6KjWS.js +257 -0
  195. package/public/assets/index-CdJk2QGi.css +1 -0
  196. package/public/assets/{key-DoJm5thS.js → key-C5pNR-B1.js} +1 -1
  197. package/public/assets/{loader-circle-B5SLmhRr.js → loader-circle-BlnkIjik.js} +1 -1
  198. package/public/assets/{pencil-C_niWuAb.js → pencil-C2RlSzkd.js} +1 -1
  199. package/public/assets/{play-Do-8kkck.js → play-CShsFo4_.js} +1 -1
  200. package/public/assets/{plus-C8aSzgHN.js → plus-Awea36q5.js} +1 -1
  201. package/public/assets/{rotate-ccw-BSPzJeCn.js → rotate-ccw-Lsbc1OqV.js} +1 -1
  202. package/public/assets/{scroll-text-DdqU_dT6.js → scroll-text-Dljs30sR.js} +1 -1
  203. package/public/assets/{settings-C8PB6BpE.js → settings-Dagn2Hyc.js} +1 -1
  204. package/public/assets/{skip-forward-CEuvYtQc.js → skip-forward-DGvJRd3l.js} +1 -1
  205. package/public/assets/{status-colors-0U8b2F2t.js → status-colors-BDICDBur.js} +1 -1
  206. package/public/assets/{task-constants-DTDx5Lfp.js → task-constants-Cla1S92u.js} +1 -1
  207. package/public/assets/{task.store-CGgehOLp.js → task.store-C7wSxS0U.js} +1 -1
  208. package/public/assets/timer-DJB-k-YQ.js +6 -0
  209. package/public/assets/{trash-2-tEkzRo6q.js → trash-2-Dbr1-vpY.js} +1 -1
  210. package/public/assets/{useFetch-CJDmNhIT.js → useFetch-BXXQ6s_s.js} +1 -1
  211. package/public/assets/{users-Cs2w_uVo.js → users-CAOqfuvd.js} +1 -1
  212. package/public/assets/{wifi-BCoKY35p.js → wifi-CxjX29U2.js} +1 -1
  213. package/public/assets/{workflow-BLCy8gMf.js → workflow-BAPA9kNh.js} +1 -1
  214. package/public/assets/zap-yBKAVFp4.js +6 -0
  215. package/public/index.html +2 -2
  216. package/public/sw.js +1 -1
  217. package/public/assets/AccessTokensPage-zuZElOFy.js +0 -1
  218. package/public/assets/BotIntegrationPage-58cLGS0T.js +0 -1
  219. package/public/assets/ConfirmStageDialog-BatYNr9r.js +0 -12
  220. package/public/assets/DeveloperManage-7tpVdYUx.js +0 -16
  221. package/public/assets/ProjectListPage-61CMBaxl.js +0 -6
  222. package/public/assets/PtyTerminal-DOgYXCFD.js +0 -38
  223. package/public/assets/RemoveMemberConfirmDialog-MiS_sqor.js +0 -6
  224. package/public/assets/ReviewAggregatePage-LBAVcz2T.js +0 -11
  225. package/public/assets/TaskListPage-26QNdjqP.js +0 -1
  226. package/public/assets/TerminalHomePage-DBhs1WQJ.js +0 -6
  227. package/public/assets/TokenManage-BQ0e_d4e.js +0 -1
  228. package/public/assets/WorkerListPage-CF1x84G-.js +0 -6
  229. package/public/assets/index-DvdpkDlU.js +0 -252
  230. package/public/assets/index-kJfGgL_V.css +0 -1
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var AutomationExecutor_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AutomationExecutor = void 0;
14
+ const crypto_1 = require("crypto");
15
+ const common_1 = require("@nestjs/common");
16
+ const event_emitter_1 = require("@nestjs/event-emitter");
17
+ const protocol_1 = require("@overlordai/protocol");
18
+ const automation_repository_1 = require("../database/repositories/automation.repository");
19
+ const task_repository_1 = require("../database/repositories/task.repository");
20
+ const task_creation_service_1 = require("../dispatcher/task-creation.service");
21
+ const redis_service_1 = require("../redis/redis.service");
22
+ const event_types_1 = require("../events/event-types");
23
+ // 5-minute TTL: balances concurrent execution prevention with automatic
24
+ // recovery if the server crashes mid-execution. For long-running automations,
25
+ // the TTL should be increased or made configurable.
26
+ const LOCK_TTL_SEC = 300;
27
+ let AutomationExecutor = AutomationExecutor_1 = class AutomationExecutor {
28
+ constructor(automationRepo, taskRepo, taskCreationService, eventEmitter, redis) {
29
+ this.automationRepo = automationRepo;
30
+ this.taskRepo = taskRepo;
31
+ this.taskCreationService = taskCreationService;
32
+ this.eventEmitter = eventEmitter;
33
+ this.redis = redis;
34
+ this.logger = new common_1.Logger(AutomationExecutor_1.name);
35
+ }
36
+ async execute(automation, triggerContext) {
37
+ // Acquire a Redis-based lock to prevent race conditions between
38
+ // the findActiveRun check and run creation. Without this lock, two
39
+ // concurrent triggers could both see no active run and both create one.
40
+ // Acquire lock atomically with TTL (SET NX EX) to prevent permanent lock on crash.
41
+ // Use a unique token as the lock value so the finally block can safely release
42
+ // only the lock it owns (prevents deleting a lock acquired by a later trigger
43
+ // if the TTL expired while this execution was still running).
44
+ const lockKey = `automation_exec_lock:${automation.id}`;
45
+ const lockToken = (0, crypto_1.randomUUID)();
46
+ const lockResult = await this.redis.getClient().set(lockKey, lockToken, 'EX', LOCK_TTL_SEC, 'NX');
47
+ if (lockResult !== 'OK') {
48
+ // Another execution is in progress for this automation — skip
49
+ const actualTrigger = triggerContext.trigger ?? automation.triggerType;
50
+ const skippedRun = this.automationRepo.createRun({
51
+ automationId: automation.id,
52
+ triggerType: actualTrigger,
53
+ triggerContext,
54
+ status: protocol_1.AutomationRunStatus.SKIPPED,
55
+ });
56
+ this.automationRepo.updateRun(skippedRun.id, {
57
+ inboxStatus: 'archived',
58
+ completedAt: new Date().toISOString(),
59
+ });
60
+ this.logger.log(`Automation #${automation.id} skipped — could not acquire execution lock`);
61
+ const refreshedSkipped = this.automationRepo.findRunById(skippedRun.id);
62
+ if (!refreshedSkipped) {
63
+ this.logger.error(`Automation #${automation.id}: skipped run #${skippedRun.id} not found after create`);
64
+ throw new Error(`Automation run #${skippedRun.id} not found after create`);
65
+ }
66
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_SKIPPED, {
67
+ runId: refreshedSkipped.id,
68
+ automationId: automation.id,
69
+ projectKey: automation.projectKey,
70
+ reason: 'execution lock not acquired',
71
+ });
72
+ return refreshedSkipped;
73
+ }
74
+ try {
75
+ return await this.executeWithLock(automation, triggerContext);
76
+ }
77
+ finally {
78
+ // Compare-and-delete: only release the lock if we still own it.
79
+ // If the TTL expired and another trigger acquired the lock, we must NOT
80
+ // delete that trigger's lock. Use a Lua script for atomic compare+delete.
81
+ const luaScript = `if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end`;
82
+ await this.redis.getClient().eval(luaScript, 1, lockKey, lockToken);
83
+ }
84
+ }
85
+ async executeWithLock(automation, triggerContext) {
86
+ // 1. Check concurrent — findActiveRun + create run
87
+ // Wrapped in try-catch so database errors are logged (lock release
88
+ // is handled by the finally block in execute()).
89
+ let run;
90
+ try {
91
+ const activeRun = this.automationRepo.findActiveRun(automation.id);
92
+ if (activeRun) {
93
+ // Create SKIPPED run
94
+ const actualTriggerType = triggerContext.trigger ?? automation.triggerType;
95
+ const skippedRun = this.automationRepo.createRun({
96
+ automationId: automation.id,
97
+ triggerType: actualTriggerType,
98
+ triggerContext,
99
+ status: protocol_1.AutomationRunStatus.SKIPPED,
100
+ });
101
+ this.automationRepo.updateRun(skippedRun.id, {
102
+ inboxStatus: 'archived',
103
+ completedAt: new Date().toISOString(),
104
+ });
105
+ this.logger.log(`Automation #${automation.id} skipped — previous run #${activeRun.id} still active`);
106
+ const refreshedSkipped = this.automationRepo.findRunById(skippedRun.id);
107
+ if (!refreshedSkipped) {
108
+ this.logger.error(`Automation #${automation.id}: skipped run #${skippedRun.id} not found after create`);
109
+ throw new Error(`Automation run #${skippedRun.id} not found after create`);
110
+ }
111
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_SKIPPED, {
112
+ runId: refreshedSkipped.id,
113
+ automationId: automation.id,
114
+ projectKey: automation.projectKey,
115
+ reason: `previous run #${activeRun.id} still active`,
116
+ });
117
+ return refreshedSkipped;
118
+ }
119
+ // 2. Create PENDING run — use actual trigger type from context (e.g. 'manual')
120
+ const actualTrigger = triggerContext.trigger ?? automation.triggerType;
121
+ run = this.automationRepo.createRun({
122
+ automationId: automation.id,
123
+ triggerType: actualTrigger,
124
+ triggerContext,
125
+ });
126
+ }
127
+ catch (err) {
128
+ this.logger.error(`Automation #${automation.id} failed during active-run check or run creation: ${err instanceof Error ? err.message : String(err)}`);
129
+ throw err;
130
+ }
131
+ // 3. Substitute template variables in description
132
+ const tz = automation.triggerConfig?.timezone || 'UTC';
133
+ const now = new Date();
134
+ const dateFormatter = new Intl.DateTimeFormat('en-CA', { timeZone: tz, year: 'numeric', month: '2-digit', day: '2-digit' });
135
+ const timeFormatter = new Intl.DateTimeFormat('en-GB', { timeZone: tz, hour: '2-digit', minute: '2-digit', hour12: false });
136
+ const weekdayFormatter = new Intl.DateTimeFormat('en-US', { timeZone: tz, weekday: 'long' });
137
+ const description = this.substituteTemplateVars(automation.description, {
138
+ date: dateFormatter.format(now),
139
+ time: timeFormatter.format(now),
140
+ weekday: weekdayFormatter.format(now),
141
+ project_name: automation.projectKey,
142
+ trigger_event: triggerContext.event ?? '',
143
+ source_task_id: String(triggerContext.sourceTaskId ?? ''),
144
+ });
145
+ // 4. Build createTask args
146
+ const taskConfig = automation.taskConfig ?? {};
147
+ const createRequest = {
148
+ description,
149
+ projectKey: automation.projectKey,
150
+ taskType: taskConfig.taskType ?? undefined,
151
+ agentType: taskConfig.agentType ?? undefined,
152
+ targetBranch: taskConfig.targetBranch ?? undefined,
153
+ taskMode: automation.executionMode === 'readonly' ? 'automation' : 'develop',
154
+ };
155
+ try {
156
+ // 5. Create task with run linkage
157
+ const taskCreatedAt = new Date().toISOString();
158
+ const task = await this.taskCreationService.createTaskInternal(createRequest, automation.createdBy, undefined, true, // skipDedup — each automation run is intentionally a separate execution
159
+ undefined, undefined, run.id);
160
+ // Update run with task linkage — but only if still PENDING
161
+ // (a fast worker failure could have already marked it terminal via onTaskStatusChanged)
162
+ const currentRun = this.automationRepo.findRunById(run.id);
163
+ if (currentRun && currentRun.status === protocol_1.AutomationRunStatus.PENDING) {
164
+ this.automationRepo.updateRun(run.id, {
165
+ taskId: task.id,
166
+ status: protocol_1.AutomationRunStatus.RUNNING,
167
+ startedAt: taskCreatedAt,
168
+ });
169
+ }
170
+ else if (currentRun) {
171
+ // Run already moved to terminal state — just link the task
172
+ this.automationRepo.updateRun(run.id, { taskId: task.id });
173
+ }
174
+ // 6. Update automation timestamps
175
+ this.automationRepo.update(automation.id, {
176
+ lastRunAt: taskCreatedAt,
177
+ });
178
+ // 7. Emit start event
179
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_STARTED, {
180
+ runId: run.id,
181
+ automationId: automation.id,
182
+ taskId: task.id,
183
+ projectKey: automation.projectKey,
184
+ });
185
+ this.logger.log(`Automation #${automation.id} triggered — run #${run.id}, task #${task.id}`);
186
+ const refreshedRun = this.automationRepo.findRunById(run.id);
187
+ if (!refreshedRun) {
188
+ this.logger.error(`Automation #${automation.id}: run #${run.id} not found after update`);
189
+ throw new Error(`Automation run #${run.id} not found after update`);
190
+ }
191
+ return refreshedRun;
192
+ }
193
+ catch (err) {
194
+ // Mark run as failed if task creation fails
195
+ const errorMsg = err instanceof Error ? err.message : String(err);
196
+ this.automationRepo.updateRun(run.id, {
197
+ status: protocol_1.AutomationRunStatus.FAILED,
198
+ completedAt: new Date().toISOString(),
199
+ inboxStatus: 'archived',
200
+ });
201
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_FAILED, {
202
+ runId: run.id,
203
+ automationId: automation.id,
204
+ taskId: null,
205
+ projectKey: automation.projectKey,
206
+ error: errorMsg,
207
+ });
208
+ this.logger.error(`Automation #${automation.id} run #${run.id} failed: ${errorMsg}`);
209
+ const refreshedRun = this.automationRepo.findRunById(run.id);
210
+ if (!refreshedRun) {
211
+ this.logger.error(`Automation #${automation.id}: run #${run.id} not found after failure update`);
212
+ throw new Error(`Automation run #${run.id} not found after failure update`);
213
+ }
214
+ return refreshedRun;
215
+ }
216
+ }
217
+ async onTaskStatusChanged(payload) {
218
+ try {
219
+ // Only handle terminal statuses
220
+ if (payload.status !== protocol_1.TaskStatus.COMPLETED &&
221
+ payload.status !== protocol_1.TaskStatus.FAILED &&
222
+ payload.status !== protocol_1.TaskStatus.CANCELLED) {
223
+ return;
224
+ }
225
+ // Find task and check if it's an automation task
226
+ const task = this.taskRepo.findById(payload.taskId);
227
+ if (!task || !task.automationRunId)
228
+ return;
229
+ // Find run — if already in terminal state, return (idempotent)
230
+ const run = this.automationRepo.findRunById(task.automationRunId);
231
+ if (!run)
232
+ return;
233
+ if (run.status === protocol_1.AutomationRunStatus.COMPLETED ||
234
+ run.status === protocol_1.AutomationRunStatus.FAILED ||
235
+ run.status === protocol_1.AutomationRunStatus.SKIPPED) {
236
+ return;
237
+ }
238
+ const automation = this.automationRepo.findById(run.automationId);
239
+ if (!automation)
240
+ return;
241
+ const now = new Date().toISOString();
242
+ if (payload.status === protocol_1.TaskStatus.COMPLETED) {
243
+ // Re-read run to pick up findings that handleAutomationReport may have
244
+ // written between the initial read and this status change event.
245
+ const freshRun = this.automationRepo.findRunById(run.id) ?? run;
246
+ // For writable mode: check if MR was created
247
+ const hasFindings = automation.executionMode === 'writable'
248
+ ? !!task.mrUrl
249
+ : (freshRun.hasFindings || false);
250
+ const findings = automation.executionMode === 'writable' && task.mrUrl
251
+ ? [{ severity: 'info', title: 'Merge Request Created', detail: task.mrUrl }]
252
+ : freshRun.findings;
253
+ this.automationRepo.updateRun(run.id, {
254
+ status: protocol_1.AutomationRunStatus.COMPLETED,
255
+ completedAt: now,
256
+ hasFindings,
257
+ findings,
258
+ inboxStatus: hasFindings ? 'unread' : 'archived',
259
+ });
260
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_COMPLETED, {
261
+ runId: run.id,
262
+ automationId: automation.id,
263
+ taskId: task.id,
264
+ projectKey: automation.projectKey,
265
+ hasFindings,
266
+ findingsCount: findings?.length ?? 0,
267
+ });
268
+ }
269
+ else {
270
+ // FAILED or CANCELLED
271
+ this.automationRepo.updateRun(run.id, {
272
+ status: protocol_1.AutomationRunStatus.FAILED,
273
+ completedAt: now,
274
+ inboxStatus: 'archived',
275
+ });
276
+ this.eventEmitter.emit(event_types_1.DomainEvents.AUTOMATION_RUN_FAILED, {
277
+ runId: run.id,
278
+ automationId: automation.id,
279
+ taskId: task.id,
280
+ projectKey: automation.projectKey,
281
+ error: task.errorMessage ?? `Task ${payload.status}`,
282
+ });
283
+ }
284
+ }
285
+ catch (err) {
286
+ const task = this.taskRepo.findById(payload.taskId);
287
+ const automationRunId = task?.automationRunId ?? 'unknown';
288
+ this.logger.error(`Error in onTaskStatusChanged for taskId=${payload.taskId}, automationRunId=${automationRunId}: ${err}`);
289
+ }
290
+ }
291
+ async handleAutomationReport(taskId, findings) {
292
+ const task = this.taskRepo.findById(taskId);
293
+ if (!task?.automationRunId)
294
+ return;
295
+ const run = this.automationRepo.findRunById(task.automationRunId);
296
+ if (!run)
297
+ return;
298
+ const hasFindings = findings.length > 0;
299
+ this.automationRepo.updateRun(run.id, {
300
+ hasFindings,
301
+ findings,
302
+ });
303
+ this.logger.log(`Automation run #${run.id} received ${findings.length} findings from task #${taskId}`);
304
+ }
305
+ async reconcile() {
306
+ const staleRuns = this.automationRepo.findStaleRuns();
307
+ for (const run of staleRuns) {
308
+ try {
309
+ if (run.taskId) {
310
+ const task = this.taskRepo.findById(run.taskId);
311
+ if (task && (task.status === protocol_1.TaskStatus.COMPLETED ||
312
+ task.status === protocol_1.TaskStatus.FAILED ||
313
+ task.status === protocol_1.TaskStatus.CANCELLED)) {
314
+ // Task already terminal, fix the run
315
+ await this.onTaskStatusChanged({
316
+ taskId: task.id,
317
+ status: task.status,
318
+ previousStatus: protocol_1.TaskStatus.RUNNING,
319
+ });
320
+ this.logger.warn(`Reconciled run #${run.id} — task #${task.id} was ${task.status}`);
321
+ }
322
+ }
323
+ else if (run.status === protocol_1.AutomationRunStatus.PENDING) {
324
+ // PENDING with no task, check if stale (>10 min)
325
+ const createdAt = new Date(run.createdAt).getTime();
326
+ const tenMinAgo = Date.now() - 10 * 60 * 1000;
327
+ if (createdAt < tenMinAgo) {
328
+ this.automationRepo.updateRun(run.id, {
329
+ status: protocol_1.AutomationRunStatus.FAILED,
330
+ completedAt: new Date().toISOString(),
331
+ inboxStatus: 'archived',
332
+ });
333
+ this.logger.warn(`Reconciled stale PENDING run #${run.id} — marked as FAILED`);
334
+ }
335
+ }
336
+ }
337
+ catch (err) {
338
+ this.logger.error(`Reconciliation error for run #${run.id}: ${err}`);
339
+ }
340
+ }
341
+ }
342
+ substituteTemplateVars(template, vars) {
343
+ // Use [^}]+ instead of \w+ to support variable names with hyphens and dots
344
+ // (e.g. {{my-var}}, {{config.key}})
345
+ return template.replace(/\{\{([^}]+)\}\}/g, (_match, key) => {
346
+ return vars[key.trim()] ?? '';
347
+ });
348
+ }
349
+ };
350
+ exports.AutomationExecutor = AutomationExecutor;
351
+ __decorate([
352
+ (0, event_emitter_1.OnEvent)(event_types_1.DomainEvents.TASK_STATUS_CHANGED),
353
+ __metadata("design:type", Function),
354
+ __metadata("design:paramtypes", [Object]),
355
+ __metadata("design:returntype", Promise)
356
+ ], AutomationExecutor.prototype, "onTaskStatusChanged", null);
357
+ exports.AutomationExecutor = AutomationExecutor = AutomationExecutor_1 = __decorate([
358
+ (0, common_1.Injectable)(),
359
+ __metadata("design:paramtypes", [automation_repository_1.AutomationRepository,
360
+ task_repository_1.TaskRepository,
361
+ task_creation_service_1.TaskCreationService,
362
+ event_emitter_1.EventEmitter2,
363
+ redis_service_1.RedisService])
364
+ ], AutomationExecutor);
365
+ //# sourceMappingURL=automation-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation-executor.js","sourceRoot":"","sources":["../../src/automation/automation-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
2
+ import { AutomationRepository } from '../database/repositories/automation.repository';
3
+ import { AutomationExecutor } from './automation-executor';
4
+ export declare class AutomationScheduler implements OnModuleInit, OnModuleDestroy {
5
+ private readonly automationRepo;
6
+ private readonly executor;
7
+ private readonly logger;
8
+ private queue;
9
+ private worker;
10
+ constructor(automationRepo: AutomationRepository, executor: AutomationExecutor);
11
+ onModuleInit(): Promise<void>;
12
+ onModuleDestroy(): Promise<void>;
13
+ registerJob(automationId: number, triggerConfig: {
14
+ cron: string;
15
+ timezone?: string;
16
+ }): Promise<void>;
17
+ removeJob(automationId: number): Promise<void>;
18
+ updateNextRunAt(automationId: number, cron: string, timezone?: string): void;
19
+ private processJob;
20
+ }
21
+ //# sourceMappingURL=automation-scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation-scheduler.d.ts","sourceRoot":"","sources":["../../src/automation/automation-scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGxG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,qBACa,mBAAoB,YAAW,YAAY,EAAE,eAAe;IAMrE,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAN3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAc;gBAGT,cAAc,EAAE,oBAAoB,EACpC,QAAQ,EAAE,kBAAkB;IAGzC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAKhC,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpG,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpD,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;YAa9D,UAAU;CA6BzB"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var AutomationScheduler_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AutomationScheduler = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const bullmq_1 = require("bullmq");
16
+ const config_1 = require("../common/config");
17
+ const automation_repository_1 = require("../database/repositories/automation.repository");
18
+ const automation_executor_1 = require("./automation-executor");
19
+ let AutomationScheduler = AutomationScheduler_1 = class AutomationScheduler {
20
+ constructor(automationRepo, executor) {
21
+ this.automationRepo = automationRepo;
22
+ this.executor = executor;
23
+ this.logger = new common_1.Logger(AutomationScheduler_1.name);
24
+ }
25
+ async onModuleInit() {
26
+ const connection = { url: (0, config_1.getRedisUrl)(), maxRetriesPerRequest: null };
27
+ this.queue = new bullmq_1.Queue('automation', { connection });
28
+ this.worker = new bullmq_1.Worker('automation', (job) => this.processJob(job), {
29
+ connection,
30
+ concurrency: 5,
31
+ });
32
+ this.worker.on('failed', (job, err) => {
33
+ this.logger.error(`Automation job failed: ${job?.id} - ${err.message}`);
34
+ });
35
+ // Register all enabled cron automations
36
+ const cronAutomations = this.automationRepo.findEnabledCron();
37
+ for (const automation of cronAutomations) {
38
+ await this.registerJob(automation.id, automation.triggerConfig);
39
+ }
40
+ // Register reconciliation job (every 30 min)
41
+ await this.queue.add('reconciliation', {}, {
42
+ repeat: { pattern: '*/30 * * * *' },
43
+ removeOnComplete: true,
44
+ removeOnFail: true,
45
+ });
46
+ // Register cleanup job (daily 3am)
47
+ await this.queue.add('cleanup', {}, {
48
+ repeat: { pattern: '0 3 * * *' },
49
+ removeOnComplete: true,
50
+ removeOnFail: true,
51
+ });
52
+ this.logger.log(`Automation scheduler started with ${cronAutomations.length} cron jobs`);
53
+ }
54
+ async onModuleDestroy() {
55
+ await this.worker?.close();
56
+ await this.queue?.close();
57
+ }
58
+ async registerJob(automationId, triggerConfig) {
59
+ const jobKey = `automation:${automationId}`;
60
+ await this.queue.add(jobKey, { automationId }, {
61
+ repeat: {
62
+ pattern: triggerConfig.cron,
63
+ tz: triggerConfig.timezone,
64
+ },
65
+ jobId: jobKey,
66
+ removeOnComplete: true,
67
+ removeOnFail: true,
68
+ });
69
+ // Update next_run_at
70
+ this.updateNextRunAt(automationId, triggerConfig.cron, triggerConfig.timezone);
71
+ }
72
+ async removeJob(automationId) {
73
+ const jobKey = `automation:${automationId}`;
74
+ const repeatableJobs = await this.queue.getRepeatableJobs();
75
+ for (const job of repeatableJobs) {
76
+ if (job.id === jobKey || job.name === jobKey) {
77
+ await this.queue.removeRepeatableByKey(job.key);
78
+ }
79
+ }
80
+ }
81
+ updateNextRunAt(automationId, cron, timezone) {
82
+ try {
83
+ const parser = require('cron-parser');
84
+ const interval = parser.parseExpression(cron, { tz: timezone });
85
+ const next = interval.next().toISOString();
86
+ this.automationRepo.update(automationId, { nextRunAt: next });
87
+ }
88
+ catch (err) {
89
+ this.logger.warn(`Failed to compute next_run_at for automation #${automationId}: ${err}`);
90
+ }
91
+ }
92
+ async processJob(job) {
93
+ if (job.name === 'reconciliation') {
94
+ await this.executor.reconcile();
95
+ return;
96
+ }
97
+ if (job.name === 'cleanup') {
98
+ const deleted = this.automationRepo.cleanupExpiredRuns();
99
+ if (deleted > 0) {
100
+ this.logger.log(`Cleaned up ${deleted} expired automation runs`);
101
+ }
102
+ return;
103
+ }
104
+ const { automationId } = job.data;
105
+ const automation = this.automationRepo.findById(automationId);
106
+ if (!automation || !automation.enabled) {
107
+ this.logger.warn(`Automation #${automationId} not found or disabled — skipping`);
108
+ return;
109
+ }
110
+ await this.executor.execute(automation, { trigger: 'cron', scheduledAt: new Date().toISOString() });
111
+ // Update next_run_at after execution
112
+ const triggerConfig = automation.triggerConfig;
113
+ if (triggerConfig.cron) {
114
+ this.updateNextRunAt(automationId, triggerConfig.cron, triggerConfig.timezone);
115
+ }
116
+ }
117
+ };
118
+ exports.AutomationScheduler = AutomationScheduler;
119
+ exports.AutomationScheduler = AutomationScheduler = AutomationScheduler_1 = __decorate([
120
+ (0, common_1.Injectable)(),
121
+ __metadata("design:paramtypes", [automation_repository_1.AutomationRepository,
122
+ automation_executor_1.AutomationExecutor])
123
+ ], AutomationScheduler);
124
+ //# sourceMappingURL=automation-scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation-scheduler.js","sourceRoot":"","sources":["../../src/automation/automation-scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { AutomationTemplate } from '@overlordai/protocol';
2
+ import { AutomationRepository } from '../database/repositories/automation.repository';
3
+ export declare class AutomationTemplateService {
4
+ private readonly automationRepo;
5
+ constructor(automationRepo: AutomationRepository);
6
+ findAll(query: {
7
+ category?: string;
8
+ isBuiltin?: boolean;
9
+ projectKey?: string;
10
+ }): AutomationTemplate[];
11
+ findAllForProjects(query: {
12
+ category?: string;
13
+ isBuiltin?: boolean;
14
+ projectKeys?: string[] | null;
15
+ }): AutomationTemplate[];
16
+ findById(id: number): AutomationTemplate | null;
17
+ create(data: {
18
+ name: string;
19
+ description: string;
20
+ category: string;
21
+ triggerType: string;
22
+ triggerConfig: Record<string, unknown>;
23
+ executionMode: string;
24
+ taskDescription: string;
25
+ taskConfig: Record<string, unknown>;
26
+ projectKey?: string;
27
+ }, createdBy: number): AutomationTemplate;
28
+ delete(id: number): boolean;
29
+ }
30
+ //# sourceMappingURL=automation-template.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automation-template.service.d.ts","sourceRoot":"","sources":["../../src/automation/automation-template.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAOtF,qBACa,yBAAyB;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,oBAAoB;IAEjE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,kBAAkB,EAAE;IAIrG,kBAAkB,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;KAAE,GAAG,kBAAkB,EAAE;IAI1H,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAI/C,MAAM,CAAC,IAAI,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvC,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB;IA4BzC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAM5B"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AutomationTemplateService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const protocol_1 = require("@overlordai/protocol");
15
+ const automation_repository_1 = require("../database/repositories/automation.repository");
16
+ const automation_validation_1 = require("./automation-validation");
17
+ const VALID_TRIGGER_TYPES = Object.values(protocol_1.AutomationTriggerType);
18
+ const VALID_EXECUTION_MODES = Object.values(protocol_1.AutomationExecutionMode);
19
+ const VALID_CATEGORIES = Object.values(protocol_1.AutomationTemplateCategory);
20
+ let AutomationTemplateService = class AutomationTemplateService {
21
+ constructor(automationRepo) {
22
+ this.automationRepo = automationRepo;
23
+ }
24
+ findAll(query) {
25
+ return this.automationRepo.findTemplates(query);
26
+ }
27
+ findAllForProjects(query) {
28
+ return this.automationRepo.findTemplatesForProjects(query);
29
+ }
30
+ findById(id) {
31
+ return this.automationRepo.findTemplateById(id);
32
+ }
33
+ create(data, createdBy) {
34
+ if (!VALID_CATEGORIES.includes(data.category)) {
35
+ throw new common_1.BadRequestException(`Invalid category '${data.category}'. Must be one of: ${VALID_CATEGORIES.join(', ')}`);
36
+ }
37
+ if (!VALID_TRIGGER_TYPES.includes(data.triggerType)) {
38
+ throw new common_1.BadRequestException(`Invalid triggerType '${data.triggerType}'. Must be one of: ${VALID_TRIGGER_TYPES.join(', ')}`);
39
+ }
40
+ if (!VALID_EXECUTION_MODES.includes(data.executionMode)) {
41
+ throw new common_1.BadRequestException(`Invalid executionMode '${data.executionMode}'. Must be one of: ${VALID_EXECUTION_MODES.join(', ')}`);
42
+ }
43
+ // Validate triggerConfig structure (cron expression, event filter, etc.)
44
+ (0, automation_validation_1.validateTriggerConfig)(data.triggerType, data.triggerConfig);
45
+ return this.automationRepo.createTemplate({
46
+ ...data,
47
+ isBuiltin: false,
48
+ createdBy,
49
+ projectKey: data.projectKey,
50
+ });
51
+ }
52
+ delete(id) {
53
+ const template = this.automationRepo.findTemplateById(id);
54
+ if (!template)
55
+ throw new common_1.NotFoundException(`Template #${id} not found`);
56
+ if (template.isBuiltin)
57
+ throw new common_1.BadRequestException('Cannot delete builtin templates');
58
+ return this.automationRepo.deleteTemplate(id);
59
+ }
60
+ };
61
+ exports.AutomationTemplateService = AutomationTemplateService;
62
+ exports.AutomationTemplateService = AutomationTemplateService = __decorate([
63
+ (0, common_1.Injectable)(),
64
+ __metadata("design:paramtypes", [automation_repository_1.AutomationRepository])
65
+ ], AutomationTemplateService);
66
+ //# sourceMappingURL=automation-template.service.js.map