@evermore.work/server 2026.509.0-canary.0

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 (1045) hide show
  1. package/dist/adapters/builtin-adapter-types.d.ts +5 -0
  2. package/dist/adapters/builtin-adapter-types.d.ts.map +1 -0
  3. package/dist/adapters/builtin-adapter-types.js +17 -0
  4. package/dist/adapters/builtin-adapter-types.js.map +1 -0
  5. package/dist/adapters/codex-models.d.ts +5 -0
  6. package/dist/adapters/codex-models.d.ts.map +1 -0
  7. package/dist/adapters/codex-models.js +105 -0
  8. package/dist/adapters/codex-models.js.map +1 -0
  9. package/dist/adapters/cursor-models.d.ts +13 -0
  10. package/dist/adapters/cursor-models.d.ts.map +1 -0
  11. package/dist/adapters/cursor-models.js +148 -0
  12. package/dist/adapters/cursor-models.js.map +1 -0
  13. package/dist/adapters/http/execute.d.ts +3 -0
  14. package/dist/adapters/http/execute.d.ts.map +1 -0
  15. package/dist/adapters/http/execute.js +51 -0
  16. package/dist/adapters/http/execute.js.map +1 -0
  17. package/dist/adapters/http/execute.test.d.ts +2 -0
  18. package/dist/adapters/http/execute.test.d.ts.map +1 -0
  19. package/dist/adapters/http/execute.test.js +40 -0
  20. package/dist/adapters/http/execute.test.js.map +1 -0
  21. package/dist/adapters/http/index.d.ts +3 -0
  22. package/dist/adapters/http/index.d.ts.map +1 -0
  23. package/dist/adapters/http/index.js +20 -0
  24. package/dist/adapters/http/index.js.map +1 -0
  25. package/dist/adapters/http/test.d.ts +3 -0
  26. package/dist/adapters/http/test.d.ts.map +1 -0
  27. package/dist/adapters/http/test.js +106 -0
  28. package/dist/adapters/http/test.js.map +1 -0
  29. package/dist/adapters/index.d.ts +4 -0
  30. package/dist/adapters/index.d.ts.map +1 -0
  31. package/dist/adapters/index.js +3 -0
  32. package/dist/adapters/index.js.map +1 -0
  33. package/dist/adapters/plugin-loader.d.ts +28 -0
  34. package/dist/adapters/plugin-loader.d.ts.map +1 -0
  35. package/dist/adapters/plugin-loader.js +196 -0
  36. package/dist/adapters/plugin-loader.js.map +1 -0
  37. package/dist/adapters/process/execute.d.ts +3 -0
  38. package/dist/adapters/process/execute.d.ts.map +1 -0
  39. package/dist/adapters/process/execute.js +70 -0
  40. package/dist/adapters/process/execute.js.map +1 -0
  41. package/dist/adapters/process/index.d.ts +3 -0
  42. package/dist/adapters/process/index.d.ts.map +1 -0
  43. package/dist/adapters/process/index.js +23 -0
  44. package/dist/adapters/process/index.js.map +1 -0
  45. package/dist/adapters/process/test.d.ts +3 -0
  46. package/dist/adapters/process/test.d.ts.map +1 -0
  47. package/dist/adapters/process/test.js +77 -0
  48. package/dist/adapters/process/test.js.map +1 -0
  49. package/dist/adapters/registry.d.ts +69 -0
  50. package/dist/adapters/registry.d.ts.map +1 -0
  51. package/dist/adapters/registry.js +566 -0
  52. package/dist/adapters/registry.js.map +1 -0
  53. package/dist/adapters/types.d.ts +2 -0
  54. package/dist/adapters/types.d.ts.map +1 -0
  55. package/dist/adapters/types.js +2 -0
  56. package/dist/adapters/types.js.map +1 -0
  57. package/dist/adapters/utils.d.ts +43 -0
  58. package/dist/adapters/utils.d.ts.map +1 -0
  59. package/dist/adapters/utils.js +52 -0
  60. package/dist/adapters/utils.js.map +1 -0
  61. package/dist/agent-auth-jwt.d.ts +14 -0
  62. package/dist/agent-auth-jwt.d.ts.map +1 -0
  63. package/dist/agent-auth-jwt.js +117 -0
  64. package/dist/agent-auth-jwt.js.map +1 -0
  65. package/dist/app.d.ts +43 -0
  66. package/dist/app.d.ts.map +1 -0
  67. package/dist/app.js +373 -0
  68. package/dist/app.js.map +1 -0
  69. package/dist/attachment-types.d.ts +23 -0
  70. package/dist/attachment-types.d.ts.map +1 -0
  71. package/dist/attachment-types.js +91 -0
  72. package/dist/attachment-types.js.map +1 -0
  73. package/dist/auth/better-auth.d.ts +33 -0
  74. package/dist/auth/better-auth.d.ts.map +1 -0
  75. package/dist/auth/better-auth.js +133 -0
  76. package/dist/auth/better-auth.js.map +1 -0
  77. package/dist/board-claim.d.ts +23 -0
  78. package/dist/board-claim.d.ts.map +1 -0
  79. package/dist/board-claim.js +115 -0
  80. package/dist/board-claim.js.map +1 -0
  81. package/dist/config-file.d.ts +3 -0
  82. package/dist/config-file.d.ts.map +1 -0
  83. package/dist/config-file.js +16 -0
  84. package/dist/config-file.js.map +1 -0
  85. package/dist/config.d.ts +44 -0
  86. package/dist/config.d.ts.map +1 -0
  87. package/dist/config.js +226 -0
  88. package/dist/config.js.map +1 -0
  89. package/dist/dev-runner-worktree.d.ts +15 -0
  90. package/dist/dev-runner-worktree.d.ts.map +1 -0
  91. package/dist/dev-runner-worktree.js +68 -0
  92. package/dist/dev-runner-worktree.js.map +1 -0
  93. package/dist/dev-server-status.d.ts +27 -0
  94. package/dist/dev-server-status.d.ts.map +1 -0
  95. package/dist/dev-server-status.js +74 -0
  96. package/dist/dev-server-status.js.map +1 -0
  97. package/dist/dev-watch-ignore.d.ts +2 -0
  98. package/dist/dev-watch-ignore.d.ts.map +1 -0
  99. package/dist/dev-watch-ignore.js +36 -0
  100. package/dist/dev-watch-ignore.js.map +1 -0
  101. package/dist/errors.d.ts +12 -0
  102. package/dist/errors.d.ts.map +1 -0
  103. package/dist/errors.js +28 -0
  104. package/dist/errors.js.map +1 -0
  105. package/dist/home-paths.d.ts +17 -0
  106. package/dist/home-paths.d.ts.map +1 -0
  107. package/dist/home-paths.js +75 -0
  108. package/dist/home-paths.js.map +1 -0
  109. package/dist/index.d.ts +10 -0
  110. package/dist/index.d.ts.map +1 -0
  111. package/dist/index.js +753 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/lib/join-request-dedupe.d.ts +11 -0
  114. package/dist/lib/join-request-dedupe.d.ts.map +1 -0
  115. package/dist/lib/join-request-dedupe.js +49 -0
  116. package/dist/lib/join-request-dedupe.js.map +1 -0
  117. package/dist/log-redaction.d.ts +11 -0
  118. package/dist/log-redaction.d.ts.map +1 -0
  119. package/dist/log-redaction.js +122 -0
  120. package/dist/log-redaction.js.map +1 -0
  121. package/dist/middleware/auth.d.ts +12 -0
  122. package/dist/middleware/auth.d.ts.map +1 -0
  123. package/dist/middleware/auth.js +302 -0
  124. package/dist/middleware/auth.js.map +1 -0
  125. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  126. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  127. package/dist/middleware/board-mutation-guard.js +67 -0
  128. package/dist/middleware/board-mutation-guard.js.map +1 -0
  129. package/dist/middleware/error-handler.d.ts +17 -0
  130. package/dist/middleware/error-handler.d.ts.map +1 -0
  131. package/dist/middleware/error-handler.js +45 -0
  132. package/dist/middleware/error-handler.js.map +1 -0
  133. package/dist/middleware/http-log-policy.d.ts +2 -0
  134. package/dist/middleware/http-log-policy.d.ts.map +1 -0
  135. package/dist/middleware/http-log-policy.js +52 -0
  136. package/dist/middleware/http-log-policy.js.map +1 -0
  137. package/dist/middleware/index.d.ts +4 -0
  138. package/dist/middleware/index.d.ts.map +1 -0
  139. package/dist/middleware/index.js +4 -0
  140. package/dist/middleware/index.js.map +1 -0
  141. package/dist/middleware/logger.d.ts +4 -0
  142. package/dist/middleware/logger.d.ts.map +1 -0
  143. package/dist/middleware/logger.js +92 -0
  144. package/dist/middleware/logger.js.map +1 -0
  145. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  146. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  147. package/dist/middleware/private-hostname-guard.js +78 -0
  148. package/dist/middleware/private-hostname-guard.js.map +1 -0
  149. package/dist/middleware/validate.d.ts +4 -0
  150. package/dist/middleware/validate.d.ts.map +1 -0
  151. package/dist/middleware/validate.js +7 -0
  152. package/dist/middleware/validate.js.map +1 -0
  153. package/dist/onboarding-assets/ceo/AGENTS.md +59 -0
  154. package/dist/onboarding-assets/ceo/HEARTBEAT.md +85 -0
  155. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  156. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  157. package/dist/onboarding-assets/default/AGENTS.md +17 -0
  158. package/dist/paths.d.ts +3 -0
  159. package/dist/paths.d.ts.map +1 -0
  160. package/dist/paths.js +31 -0
  161. package/dist/paths.js.map +1 -0
  162. package/dist/realtime/live-events-ws.d.ts +28 -0
  163. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  164. package/dist/realtime/live-events-ws.js +187 -0
  165. package/dist/realtime/live-events-ws.js.map +1 -0
  166. package/dist/redaction.d.ts +5 -0
  167. package/dist/redaction.d.ts.map +1 -0
  168. package/dist/redaction.js +98 -0
  169. package/dist/redaction.js.map +1 -0
  170. package/dist/routes/access.d.ts +82 -0
  171. package/dist/routes/access.d.ts.map +1 -0
  172. package/dist/routes/access.js +3411 -0
  173. package/dist/routes/access.js.map +1 -0
  174. package/dist/routes/activity.d.ts +3 -0
  175. package/dist/routes/activity.d.ts.map +1 -0
  176. package/dist/routes/activity.js +90 -0
  177. package/dist/routes/activity.js.map +1 -0
  178. package/dist/routes/adapters.d.ts +16 -0
  179. package/dist/routes/adapters.d.ts.map +1 -0
  180. package/dist/routes/adapters.js +527 -0
  181. package/dist/routes/adapters.js.map +1 -0
  182. package/dist/routes/agents.d.ts +6 -0
  183. package/dist/routes/agents.d.ts.map +1 -0
  184. package/dist/routes/agents.js +2753 -0
  185. package/dist/routes/agents.js.map +1 -0
  186. package/dist/routes/approvals.d.ts +6 -0
  187. package/dist/routes/approvals.d.ts.map +1 -0
  188. package/dist/routes/approvals.js +300 -0
  189. package/dist/routes/approvals.js.map +1 -0
  190. package/dist/routes/assets.d.ts +4 -0
  191. package/dist/routes/assets.d.ts.map +1 -0
  192. package/dist/routes/assets.js +309 -0
  193. package/dist/routes/assets.js.map +1 -0
  194. package/dist/routes/auth.d.ts +3 -0
  195. package/dist/routes/auth.d.ts.map +1 -0
  196. package/dist/routes/auth.js +82 -0
  197. package/dist/routes/auth.js.map +1 -0
  198. package/dist/routes/authz.d.ts +19 -0
  199. package/dist/routes/authz.d.ts.map +1 -0
  200. package/dist/routes/authz.js +75 -0
  201. package/dist/routes/authz.js.map +1 -0
  202. package/dist/routes/companies.d.ts +4 -0
  203. package/dist/routes/companies.d.ts.map +1 -0
  204. package/dist/routes/companies.js +359 -0
  205. package/dist/routes/companies.js.map +1 -0
  206. package/dist/routes/company-skills.d.ts +3 -0
  207. package/dist/routes/company-skills.d.ts.map +1 -0
  208. package/dist/routes/company-skills.js +258 -0
  209. package/dist/routes/company-skills.js.map +1 -0
  210. package/dist/routes/costs.d.ts +11 -0
  211. package/dist/routes/costs.d.ts.map +1 -0
  212. package/dist/routes/costs.js +285 -0
  213. package/dist/routes/costs.js.map +1 -0
  214. package/dist/routes/dashboard.d.ts +3 -0
  215. package/dist/routes/dashboard.d.ts.map +1 -0
  216. package/dist/routes/dashboard.js +15 -0
  217. package/dist/routes/dashboard.js.map +1 -0
  218. package/dist/routes/environment-selection.d.ts +13 -0
  219. package/dist/routes/environment-selection.d.ts.map +1 -0
  220. package/dist/routes/environment-selection.js +30 -0
  221. package/dist/routes/environment-selection.js.map +1 -0
  222. package/dist/routes/environments.d.ts +6 -0
  223. package/dist/routes/environments.d.ts.map +1 -0
  224. package/dist/routes/environments.js +401 -0
  225. package/dist/routes/environments.js.map +1 -0
  226. package/dist/routes/execution-workspaces.d.ts +3 -0
  227. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  228. package/dist/routes/execution-workspaces.js +536 -0
  229. package/dist/routes/execution-workspaces.js.map +1 -0
  230. package/dist/routes/goals.d.ts +3 -0
  231. package/dist/routes/goals.d.ts.map +1 -0
  232. package/dist/routes/goals.js +101 -0
  233. package/dist/routes/goals.js.map +1 -0
  234. package/dist/routes/health.d.ts +9 -0
  235. package/dist/routes/health.d.ts.map +1 -0
  236. package/dist/routes/health.js +114 -0
  237. package/dist/routes/health.js.map +1 -0
  238. package/dist/routes/inbox-dismissals.d.ts +3 -0
  239. package/dist/routes/inbox-dismissals.d.ts.map +1 -0
  240. package/dist/routes/inbox-dismissals.js +58 -0
  241. package/dist/routes/inbox-dismissals.js.map +1 -0
  242. package/dist/routes/index.d.ts +22 -0
  243. package/dist/routes/index.d.ts.map +1 -0
  244. package/dist/routes/index.js +22 -0
  245. package/dist/routes/index.js.map +1 -0
  246. package/dist/routes/instance-database-backups.d.ts +15 -0
  247. package/dist/routes/instance-database-backups.d.ts.map +1 -0
  248. package/dist/routes/instance-database-backups.js +12 -0
  249. package/dist/routes/instance-database-backups.js.map +1 -0
  250. package/dist/routes/instance-settings.d.ts +3 -0
  251. package/dist/routes/instance-settings.d.ts.map +1 -0
  252. package/dist/routes/instance-settings.js +110 -0
  253. package/dist/routes/instance-settings.js.map +1 -0
  254. package/dist/routes/issue-tree-control.d.ts +3 -0
  255. package/dist/routes/issue-tree-control.d.ts.map +1 -0
  256. package/dist/routes/issue-tree-control.js +363 -0
  257. package/dist/routes/issue-tree-control.js.map +1 -0
  258. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  259. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  260. package/dist/routes/issues-checkout-wakeup.js +12 -0
  261. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  262. package/dist/routes/issues.d.ts +23 -0
  263. package/dist/routes/issues.d.ts.map +1 -0
  264. package/dist/routes/issues.js +3886 -0
  265. package/dist/routes/issues.js.map +1 -0
  266. package/dist/routes/llms.d.ts +3 -0
  267. package/dist/routes/llms.d.ts.map +1 -0
  268. package/dist/routes/llms.js +80 -0
  269. package/dist/routes/llms.js.map +1 -0
  270. package/dist/routes/org-chart-svg.d.ts +25 -0
  271. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  272. package/dist/routes/org-chart-svg.js +656 -0
  273. package/dist/routes/org-chart-svg.js.map +1 -0
  274. package/dist/routes/plugin-ui-static.d.ts +69 -0
  275. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  276. package/dist/routes/plugin-ui-static.js +411 -0
  277. package/dist/routes/plugin-ui-static.js.map +1 -0
  278. package/dist/routes/plugins.d.ts +121 -0
  279. package/dist/routes/plugins.d.ts.map +1 -0
  280. package/dist/routes/plugins.js +2192 -0
  281. package/dist/routes/plugins.js.map +1 -0
  282. package/dist/routes/projects.d.ts +3 -0
  283. package/dist/routes/projects.d.ts.map +1 -0
  284. package/dist/routes/projects.js +566 -0
  285. package/dist/routes/projects.js.map +1 -0
  286. package/dist/routes/routines.d.ts +6 -0
  287. package/dist/routes/routines.d.ts.map +1 -0
  288. package/dist/routes/routines.js +417 -0
  289. package/dist/routes/routines.js.map +1 -0
  290. package/dist/routes/secrets.d.ts +3 -0
  291. package/dist/routes/secrets.d.ts.map +1 -0
  292. package/dist/routes/secrets.js +128 -0
  293. package/dist/routes/secrets.js.map +1 -0
  294. package/dist/routes/sidebar-badges.d.ts +3 -0
  295. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  296. package/dist/routes/sidebar-badges.js +68 -0
  297. package/dist/routes/sidebar-badges.js.map +1 -0
  298. package/dist/routes/sidebar-preferences.d.ts +3 -0
  299. package/dist/routes/sidebar-preferences.d.ts.map +1 -0
  300. package/dist/routes/sidebar-preferences.js +63 -0
  301. package/dist/routes/sidebar-preferences.js.map +1 -0
  302. package/dist/routes/user-profiles.d.ts +3 -0
  303. package/dist/routes/user-profiles.d.ts.map +1 -0
  304. package/dist/routes/user-profiles.js +337 -0
  305. package/dist/routes/user-profiles.js.map +1 -0
  306. package/dist/routes/workspace-command-authz.d.ts +14 -0
  307. package/dist/routes/workspace-command-authz.d.ts.map +1 -0
  308. package/dist/routes/workspace-command-authz.js +83 -0
  309. package/dist/routes/workspace-command-authz.js.map +1 -0
  310. package/dist/routes/workspace-runtime-service-authz.d.ts +12 -0
  311. package/dist/routes/workspace-runtime-service-authz.d.ts.map +1 -0
  312. package/dist/routes/workspace-runtime-service-authz.js +96 -0
  313. package/dist/routes/workspace-runtime-service-authz.js.map +1 -0
  314. package/dist/runtime-api.d.ts +19 -0
  315. package/dist/runtime-api.d.ts.map +1 -0
  316. package/dist/runtime-api.js +137 -0
  317. package/dist/runtime-api.js.map +1 -0
  318. package/dist/secrets/external-stub-providers.d.ts +5 -0
  319. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  320. package/dist/secrets/external-stub-providers.js +21 -0
  321. package/dist/secrets/external-stub-providers.js.map +1 -0
  322. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  323. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  324. package/dist/secrets/local-encrypted-provider.js +116 -0
  325. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  326. package/dist/secrets/provider-registry.d.ts +5 -0
  327. package/dist/secrets/provider-registry.d.ts.map +1 -0
  328. package/dist/secrets/provider-registry.js +20 -0
  329. package/dist/secrets/provider-registry.js.map +1 -0
  330. package/dist/secrets/types.d.ts +21 -0
  331. package/dist/secrets/types.d.ts.map +1 -0
  332. package/dist/secrets/types.js +2 -0
  333. package/dist/secrets/types.js.map +1 -0
  334. package/dist/services/access.d.ts +171 -0
  335. package/dist/services/access.d.ts.map +1 -0
  336. package/dist/services/access.js +522 -0
  337. package/dist/services/access.js.map +1 -0
  338. package/dist/services/activity-log.d.ts +19 -0
  339. package/dist/services/activity-log.d.ts.map +1 -0
  340. package/dist/services/activity-log.js +99 -0
  341. package/dist/services/activity-log.js.map +1 -0
  342. package/dist/services/activity.d.ts +462 -0
  343. package/dist/services/activity.d.ts.map +1 -0
  344. package/dist/services/activity.js +443 -0
  345. package/dist/services/activity.js.map +1 -0
  346. package/dist/services/adapter-plugin-store.d.ts +36 -0
  347. package/dist/services/adapter-plugin-store.d.ts.map +1 -0
  348. package/dist/services/adapter-plugin-store.js +154 -0
  349. package/dist/services/adapter-plugin-store.js.map +1 -0
  350. package/dist/services/agent-instructions.d.ts +91 -0
  351. package/dist/services/agent-instructions.d.ts.map +1 -0
  352. package/dist/services/agent-instructions.js +580 -0
  353. package/dist/services/agent-instructions.js.map +1 -0
  354. package/dist/services/agent-permissions.d.ts +6 -0
  355. package/dist/services/agent-permissions.d.ts.map +1 -0
  356. package/dist/services/agent-permissions.js +18 -0
  357. package/dist/services/agent-permissions.js.map +1 -0
  358. package/dist/services/agent-start-lock.d.ts +2 -0
  359. package/dist/services/agent-start-lock.d.ts.map +1 -0
  360. package/dist/services/agent-start-lock.js +43 -0
  361. package/dist/services/agent-start-lock.js.map +1 -0
  362. package/dist/services/agents.d.ts +2253 -0
  363. package/dist/services/agents.d.ts.map +1 -0
  364. package/dist/services/agents.js +609 -0
  365. package/dist/services/agents.js.map +1 -0
  366. package/dist/services/approvals.d.ts +546 -0
  367. package/dist/services/approvals.d.ts.map +1 -0
  368. package/dist/services/approvals.js +212 -0
  369. package/dist/services/approvals.js.map +1 -0
  370. package/dist/services/assets.d.ts +33 -0
  371. package/dist/services/assets.d.ts.map +1 -0
  372. package/dist/services/assets.js +17 -0
  373. package/dist/services/assets.js.map +1 -0
  374. package/dist/services/board-auth.d.ts +239 -0
  375. package/dist/services/board-auth.d.ts.map +1 -0
  376. package/dist/services/board-auth.js +300 -0
  377. package/dist/services/board-auth.js.map +1 -0
  378. package/dist/services/budgets.d.ts +38 -0
  379. package/dist/services/budgets.d.ts.map +1 -0
  380. package/dist/services/budgets.js +784 -0
  381. package/dist/services/budgets.js.map +1 -0
  382. package/dist/services/companies.d.ts +154 -0
  383. package/dist/services/companies.d.ts.map +1 -0
  384. package/dist/services/companies.js +267 -0
  385. package/dist/services/companies.js.map +1 -0
  386. package/dist/services/company-export-readme.d.ts +17 -0
  387. package/dist/services/company-export-readme.d.ts.map +1 -0
  388. package/dist/services/company-export-readme.js +148 -0
  389. package/dist/services/company-export-readme.js.map +1 -0
  390. package/dist/services/company-member-roles.d.ts +9 -0
  391. package/dist/services/company-member-roles.d.ts.map +1 -0
  392. package/dist/services/company-member-roles.js +46 -0
  393. package/dist/services/company-member-roles.js.map +1 -0
  394. package/dist/services/company-portability.d.ts +24 -0
  395. package/dist/services/company-portability.d.ts.map +1 -0
  396. package/dist/services/company-portability.js +4076 -0
  397. package/dist/services/company-portability.js.map +1 -0
  398. package/dist/services/company-search-rate-limit.d.ts +22 -0
  399. package/dist/services/company-search-rate-limit.d.ts.map +1 -0
  400. package/dist/services/company-search-rate-limit.js +38 -0
  401. package/dist/services/company-search-rate-limit.js.map +1 -0
  402. package/dist/services/company-search.d.ts +8 -0
  403. package/dist/services/company-search.d.ts.map +1 -0
  404. package/dist/services/company-search.js +626 -0
  405. package/dist/services/company-search.js.map +1 -0
  406. package/dist/services/company-skills.d.ts +77 -0
  407. package/dist/services/company-skills.d.ts.map +1 -0
  408. package/dist/services/company-skills.js +2120 -0
  409. package/dist/services/company-skills.js.map +1 -0
  410. package/dist/services/costs.d.ts +127 -0
  411. package/dist/services/costs.d.ts.map +1 -0
  412. package/dist/services/costs.js +409 -0
  413. package/dist/services/costs.js.map +1 -0
  414. package/dist/services/cron.d.ts +80 -0
  415. package/dist/services/cron.d.ts.map +1 -0
  416. package/dist/services/cron.js +300 -0
  417. package/dist/services/cron.js.map +1 -0
  418. package/dist/services/dashboard.d.ts +34 -0
  419. package/dist/services/dashboard.d.ts.map +1 -0
  420. package/dist/services/dashboard.js +142 -0
  421. package/dist/services/dashboard.js.map +1 -0
  422. package/dist/services/default-agent-instructions.d.ts +9 -0
  423. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  424. package/dist/services/default-agent-instructions.js +20 -0
  425. package/dist/services/default-agent-instructions.js.map +1 -0
  426. package/dist/services/documents.d.ts +199 -0
  427. package/dist/services/documents.d.ts.map +1 -0
  428. package/dist/services/documents.js +411 -0
  429. package/dist/services/documents.js.map +1 -0
  430. package/dist/services/environment-config.d.ts +43 -0
  431. package/dist/services/environment-config.d.ts.map +1 -0
  432. package/dist/services/environment-config.js +388 -0
  433. package/dist/services/environment-config.js.map +1 -0
  434. package/dist/services/environment-execution-target.d.ts +21 -0
  435. package/dist/services/environment-execution-target.d.ts.map +1 -0
  436. package/dist/services/environment-execution-target.js +119 -0
  437. package/dist/services/environment-execution-target.js.map +1 -0
  438. package/dist/services/environment-probe.d.ts +9 -0
  439. package/dist/services/environment-probe.d.ts.map +1 -0
  440. package/dist/services/environment-probe.js +106 -0
  441. package/dist/services/environment-probe.js.map +1 -0
  442. package/dist/services/environment-run-orchestrator.d.ts +124 -0
  443. package/dist/services/environment-run-orchestrator.d.ts.map +1 -0
  444. package/dist/services/environment-run-orchestrator.js +392 -0
  445. package/dist/services/environment-run-orchestrator.js.map +1 -0
  446. package/dist/services/environment-runtime.d.ts +90 -0
  447. package/dist/services/environment-runtime.d.ts.map +1 -0
  448. package/dist/services/environment-runtime.js +934 -0
  449. package/dist/services/environment-runtime.js.map +1 -0
  450. package/dist/services/environments.d.ts +36 -0
  451. package/dist/services/environments.d.ts.map +1 -0
  452. package/dist/services/environments.js +260 -0
  453. package/dist/services/environments.js.map +1 -0
  454. package/dist/services/execution-workspace-policy.d.ts +30 -0
  455. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  456. package/dist/services/execution-workspace-policy.js +195 -0
  457. package/dist/services/execution-workspace-policy.js.map +1 -0
  458. package/dist/services/execution-workspaces.d.ts +30 -0
  459. package/dist/services/execution-workspaces.d.ts.map +1 -0
  460. package/dist/services/execution-workspaces.js +635 -0
  461. package/dist/services/execution-workspaces.js.map +1 -0
  462. package/dist/services/feedback-redaction.d.ts +23 -0
  463. package/dist/services/feedback-redaction.d.ts.map +1 -0
  464. package/dist/services/feedback-redaction.js +150 -0
  465. package/dist/services/feedback-redaction.js.map +1 -0
  466. package/dist/services/feedback-share-client.d.ts +9 -0
  467. package/dist/services/feedback-share-client.d.ts.map +1 -0
  468. package/dist/services/feedback-share-client.js +46 -0
  469. package/dist/services/feedback-share-client.js.map +1 -0
  470. package/dist/services/feedback.d.ts +93 -0
  471. package/dist/services/feedback.d.ts.map +1 -0
  472. package/dist/services/feedback.js +1717 -0
  473. package/dist/services/feedback.js.map +1 -0
  474. package/dist/services/finance.d.ts +93 -0
  475. package/dist/services/finance.d.ts.map +1 -0
  476. package/dist/services/finance.js +120 -0
  477. package/dist/services/finance.js.map +1 -0
  478. package/dist/services/github-fetch.d.ts +4 -0
  479. package/dist/services/github-fetch.d.ts.map +1 -0
  480. package/dist/services/github-fetch.js +23 -0
  481. package/dist/services/github-fetch.js.map +1 -0
  482. package/dist/services/goals.d.ts +433 -0
  483. package/dist/services/goals.d.ts.map +1 -0
  484. package/dist/services/goals.js +54 -0
  485. package/dist/services/goals.js.map +1 -0
  486. package/dist/services/heartbeat-run-summary.d.ts +7 -0
  487. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  488. package/dist/services/heartbeat-run-summary.js +84 -0
  489. package/dist/services/heartbeat-run-summary.js.map +1 -0
  490. package/dist/services/heartbeat-stop-metadata.d.ts +28 -0
  491. package/dist/services/heartbeat-stop-metadata.d.ts.map +1 -0
  492. package/dist/services/heartbeat-stop-metadata.js +86 -0
  493. package/dist/services/heartbeat-stop-metadata.js.map +1 -0
  494. package/dist/services/heartbeat-stop-metadata.test.d.ts +2 -0
  495. package/dist/services/heartbeat-stop-metadata.test.d.ts.map +1 -0
  496. package/dist/services/heartbeat-stop-metadata.test.js +93 -0
  497. package/dist/services/heartbeat-stop-metadata.test.js.map +1 -0
  498. package/dist/services/heartbeat.d.ts +1484 -0
  499. package/dist/services/heartbeat.d.ts.map +1 -0
  500. package/dist/services/heartbeat.js +7557 -0
  501. package/dist/services/heartbeat.js.map +1 -0
  502. package/dist/services/hire-hook.d.ts +14 -0
  503. package/dist/services/hire-hook.d.ts.map +1 -0
  504. package/dist/services/hire-hook.js +85 -0
  505. package/dist/services/hire-hook.js.map +1 -0
  506. package/dist/services/inbox-dismissals.d.ts +22 -0
  507. package/dist/services/inbox-dismissals.d.ts.map +1 -0
  508. package/dist/services/inbox-dismissals.js +33 -0
  509. package/dist/services/inbox-dismissals.js.map +1 -0
  510. package/dist/services/index.d.ts +44 -0
  511. package/dist/services/index.d.ts.map +1 -0
  512. package/dist/services/index.js +44 -0
  513. package/dist/services/index.js.map +1 -0
  514. package/dist/services/instance-settings.d.ts +11 -0
  515. package/dist/services/instance-settings.d.ts.map +1 -0
  516. package/dist/services/instance-settings.js +138 -0
  517. package/dist/services/instance-settings.js.map +1 -0
  518. package/dist/services/invite-grants.d.ts +15 -0
  519. package/dist/services/invite-grants.d.ts.map +1 -0
  520. package/dist/services/invite-grants.js +50 -0
  521. package/dist/services/invite-grants.js.map +1 -0
  522. package/dist/services/issue-approvals.d.ts +56 -0
  523. package/dist/services/issue-approvals.d.ts.map +1 -0
  524. package/dist/services/issue-approvals.js +153 -0
  525. package/dist/services/issue-approvals.js.map +1 -0
  526. package/dist/services/issue-assignment-wakeup.d.ts +29 -0
  527. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  528. package/dist/services/issue-assignment-wakeup.js +22 -0
  529. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  530. package/dist/services/issue-continuation-summary.d.ts +66 -0
  531. package/dist/services/issue-continuation-summary.d.ts.map +1 -0
  532. package/dist/services/issue-continuation-summary.js +212 -0
  533. package/dist/services/issue-continuation-summary.js.map +1 -0
  534. package/dist/services/issue-execution-policy.d.ts +93 -0
  535. package/dist/services/issue-execution-policy.d.ts.map +1 -0
  536. package/dist/services/issue-execution-policy.js +838 -0
  537. package/dist/services/issue-execution-policy.js.map +1 -0
  538. package/dist/services/issue-goal-fallback.d.ts +18 -0
  539. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  540. package/dist/services/issue-goal-fallback.js +33 -0
  541. package/dist/services/issue-goal-fallback.js.map +1 -0
  542. package/dist/services/issue-liveness.d.ts +3 -0
  543. package/dist/services/issue-liveness.d.ts.map +1 -0
  544. package/dist/services/issue-liveness.js +2 -0
  545. package/dist/services/issue-liveness.js.map +1 -0
  546. package/dist/services/issue-references.d.ts +21 -0
  547. package/dist/services/issue-references.d.ts.map +1 -0
  548. package/dist/services/issue-references.js +318 -0
  549. package/dist/services/issue-references.js.map +1 -0
  550. package/dist/services/issue-thread-interactions.d.ts +76 -0
  551. package/dist/services/issue-thread-interactions.d.ts.map +1 -0
  552. package/dist/services/issue-thread-interactions.js +923 -0
  553. package/dist/services/issue-thread-interactions.js.map +1 -0
  554. package/dist/services/issue-thread-interactions.test.d.ts +2 -0
  555. package/dist/services/issue-thread-interactions.test.d.ts.map +1 -0
  556. package/dist/services/issue-thread-interactions.test.js +195 -0
  557. package/dist/services/issue-thread-interactions.test.js.map +1 -0
  558. package/dist/services/issue-tree-control.d.ts +89 -0
  559. package/dist/services/issue-tree-control.d.ts.map +1 -0
  560. package/dist/services/issue-tree-control.js +933 -0
  561. package/dist/services/issue-tree-control.js.map +1 -0
  562. package/dist/services/issues.d.ts +710 -0
  563. package/dist/services/issues.d.ts.map +1 -0
  564. package/dist/services/issues.js +3199 -0
  565. package/dist/services/issues.js.map +1 -0
  566. package/dist/services/json-schema-secret-refs.d.ts +5 -0
  567. package/dist/services/json-schema-secret-refs.d.ts.map +1 -0
  568. package/dist/services/json-schema-secret-refs.js +67 -0
  569. package/dist/services/json-schema-secret-refs.js.map +1 -0
  570. package/dist/services/live-events.d.ts +17 -0
  571. package/dist/services/live-events.d.ts.map +1 -0
  572. package/dist/services/live-events.js +33 -0
  573. package/dist/services/live-events.js.map +1 -0
  574. package/dist/services/local-service-supervisor.d.ts +56 -0
  575. package/dist/services/local-service-supervisor.d.ts.map +1 -0
  576. package/dist/services/local-service-supervisor.js +284 -0
  577. package/dist/services/local-service-supervisor.js.map +1 -0
  578. package/dist/services/plugin-capability-validator.d.ts +108 -0
  579. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  580. package/dist/services/plugin-capability-validator.js +313 -0
  581. package/dist/services/plugin-capability-validator.js.map +1 -0
  582. package/dist/services/plugin-config-validator.d.ts +26 -0
  583. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  584. package/dist/services/plugin-config-validator.js +41 -0
  585. package/dist/services/plugin-config-validator.js.map +1 -0
  586. package/dist/services/plugin-database.d.ts +49 -0
  587. package/dist/services/plugin-database.d.ts.map +1 -0
  588. package/dist/services/plugin-database.js +440 -0
  589. package/dist/services/plugin-database.js.map +1 -0
  590. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  591. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  592. package/dist/services/plugin-dev-watcher.js +241 -0
  593. package/dist/services/plugin-dev-watcher.js.map +1 -0
  594. package/dist/services/plugin-environment-driver.d.ts +124 -0
  595. package/dist/services/plugin-environment-driver.d.ts.map +1 -0
  596. package/dist/services/plugin-environment-driver.js +224 -0
  597. package/dist/services/plugin-environment-driver.js.map +1 -0
  598. package/dist/services/plugin-event-bus.d.ts +149 -0
  599. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  600. package/dist/services/plugin-event-bus.js +258 -0
  601. package/dist/services/plugin-event-bus.js.map +1 -0
  602. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  603. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  604. package/dist/services/plugin-host-service-cleanup.js +37 -0
  605. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  606. package/dist/services/plugin-host-services.d.ts +17 -0
  607. package/dist/services/plugin-host-services.d.ts.map +1 -0
  608. package/dist/services/plugin-host-services.js +1861 -0
  609. package/dist/services/plugin-host-services.js.map +1 -0
  610. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  611. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  612. package/dist/services/plugin-job-coordinator.js +172 -0
  613. package/dist/services/plugin-job-coordinator.js.map +1 -0
  614. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  615. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  616. package/dist/services/plugin-job-scheduler.js +454 -0
  617. package/dist/services/plugin-job-scheduler.js.map +1 -0
  618. package/dist/services/plugin-job-store.d.ts +208 -0
  619. package/dist/services/plugin-job-store.d.ts.map +1 -0
  620. package/dist/services/plugin-job-store.js +350 -0
  621. package/dist/services/plugin-job-store.js.map +1 -0
  622. package/dist/services/plugin-lifecycle.d.ts +203 -0
  623. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  624. package/dist/services/plugin-lifecycle.js +476 -0
  625. package/dist/services/plugin-lifecycle.js.map +1 -0
  626. package/dist/services/plugin-loader.d.ts +445 -0
  627. package/dist/services/plugin-loader.d.ts.map +1 -0
  628. package/dist/services/plugin-loader.js +1273 -0
  629. package/dist/services/plugin-loader.js.map +1 -0
  630. package/dist/services/plugin-local-folders.d.ts +48 -0
  631. package/dist/services/plugin-local-folders.d.ts.map +1 -0
  632. package/dist/services/plugin-local-folders.js +461 -0
  633. package/dist/services/plugin-local-folders.js.map +1 -0
  634. package/dist/services/plugin-log-retention.d.ts +20 -0
  635. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  636. package/dist/services/plugin-log-retention.js +63 -0
  637. package/dist/services/plugin-log-retention.js.map +1 -0
  638. package/dist/services/plugin-managed-agents.d.ts +15 -0
  639. package/dist/services/plugin-managed-agents.d.ts.map +1 -0
  640. package/dist/services/plugin-managed-agents.js +414 -0
  641. package/dist/services/plugin-managed-agents.js.map +1 -0
  642. package/dist/services/plugin-managed-routines.d.ts +41 -0
  643. package/dist/services/plugin-managed-routines.d.ts.map +1 -0
  644. package/dist/services/plugin-managed-routines.js +416 -0
  645. package/dist/services/plugin-managed-routines.js.map +1 -0
  646. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  647. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  648. package/dist/services/plugin-manifest-validator.js +84 -0
  649. package/dist/services/plugin-manifest-validator.js.map +1 -0
  650. package/dist/services/plugin-registry.d.ts +2550 -0
  651. package/dist/services/plugin-registry.d.ts.map +1 -0
  652. package/dist/services/plugin-registry.js +581 -0
  653. package/dist/services/plugin-registry.js.map +1 -0
  654. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  655. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  656. package/dist/services/plugin-runtime-sandbox.js +154 -0
  657. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  658. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  659. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  660. package/dist/services/plugin-secrets-handler.js +231 -0
  661. package/dist/services/plugin-secrets-handler.js.map +1 -0
  662. package/dist/services/plugin-state-store.d.ts +92 -0
  663. package/dist/services/plugin-state-store.d.ts.map +1 -0
  664. package/dist/services/plugin-state-store.js +190 -0
  665. package/dist/services/plugin-state-store.js.map +1 -0
  666. package/dist/services/plugin-stream-bus.d.ts +29 -0
  667. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  668. package/dist/services/plugin-stream-bus.js +48 -0
  669. package/dist/services/plugin-stream-bus.js.map +1 -0
  670. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  671. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  672. package/dist/services/plugin-tool-dispatcher.js +224 -0
  673. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  674. package/dist/services/plugin-tool-registry.d.ts +192 -0
  675. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  676. package/dist/services/plugin-tool-registry.js +224 -0
  677. package/dist/services/plugin-tool-registry.js.map +1 -0
  678. package/dist/services/plugin-worker-manager.d.ts +262 -0
  679. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  680. package/dist/services/plugin-worker-manager.js +836 -0
  681. package/dist/services/plugin-worker-manager.js.map +1 -0
  682. package/dist/services/productivity-review.d.ts +83 -0
  683. package/dist/services/productivity-review.d.ts.map +1 -0
  684. package/dist/services/productivity-review.js +652 -0
  685. package/dist/services/productivity-review.js.map +1 -0
  686. package/dist/services/project-workspace-runtime-config.d.ts +4 -0
  687. package/dist/services/project-workspace-runtime-config.d.ts.map +1 -0
  688. package/dist/services/project-workspace-runtime-config.js +54 -0
  689. package/dist/services/project-workspace-runtime-config.js.map +1 -0
  690. package/dist/services/projects.d.ts +99 -0
  691. package/dist/services/projects.d.ts.map +1 -0
  692. package/dist/services/projects.js +879 -0
  693. package/dist/services/projects.js.map +1 -0
  694. package/dist/services/quota-windows.d.ts +9 -0
  695. package/dist/services/quota-windows.d.ts.map +1 -0
  696. package/dist/services/quota-windows.js +56 -0
  697. package/dist/services/quota-windows.js.map +1 -0
  698. package/dist/services/recovery/index.d.ts +10 -0
  699. package/dist/services/recovery/index.d.ts.map +1 -0
  700. package/dist/services/recovery/index.js +6 -0
  701. package/dist/services/recovery/index.js.map +1 -0
  702. package/dist/services/recovery/issue-graph-liveness.d.ts +85 -0
  703. package/dist/services/recovery/issue-graph-liveness.d.ts.map +1 -0
  704. package/dist/services/recovery/issue-graph-liveness.js +343 -0
  705. package/dist/services/recovery/issue-graph-liveness.js.map +1 -0
  706. package/dist/services/recovery/model-profile-hint.d.ts +8 -0
  707. package/dist/services/recovery/model-profile-hint.d.ts.map +1 -0
  708. package/dist/services/recovery/model-profile-hint.js +11 -0
  709. package/dist/services/recovery/model-profile-hint.js.map +1 -0
  710. package/dist/services/recovery/origins.d.ts +36 -0
  711. package/dist/services/recovery/origins.d.ts.map +1 -0
  712. package/dist/services/recovery/origins.js +45 -0
  713. package/dist/services/recovery/origins.js.map +1 -0
  714. package/dist/services/recovery/pause-hold-guard.d.ts +6 -0
  715. package/dist/services/recovery/pause-hold-guard.d.ts.map +1 -0
  716. package/dist/services/recovery/pause-hold-guard.js +6 -0
  717. package/dist/services/recovery/pause-hold-guard.js.map +1 -0
  718. package/dist/services/recovery/run-liveness-continuations.d.ts +50 -0
  719. package/dist/services/recovery/run-liveness-continuations.d.ts.map +1 -0
  720. package/dist/services/recovery/run-liveness-continuations.js +117 -0
  721. package/dist/services/recovery/run-liveness-continuations.js.map +1 -0
  722. package/dist/services/recovery/service.d.ts +195 -0
  723. package/dist/services/recovery/service.d.ts.map +1 -0
  724. package/dist/services/recovery/service.js +2210 -0
  725. package/dist/services/recovery/service.js.map +1 -0
  726. package/dist/services/recovery/successful-run-handoff.d.ts +87 -0
  727. package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -0
  728. package/dist/services/recovery/successful-run-handoff.js +297 -0
  729. package/dist/services/recovery/successful-run-handoff.js.map +1 -0
  730. package/dist/services/recovery/successful-run-handoff.test.d.ts +2 -0
  731. package/dist/services/recovery/successful-run-handoff.test.d.ts.map +1 -0
  732. package/dist/services/recovery/successful-run-handoff.test.js +267 -0
  733. package/dist/services/recovery/successful-run-handoff.test.js.map +1 -0
  734. package/dist/services/routines.d.ts +166 -0
  735. package/dist/services/routines.d.ts.map +1 -0
  736. package/dist/services/routines.js +1937 -0
  737. package/dist/services/routines.js.map +1 -0
  738. package/dist/services/run-continuations.d.ts +3 -0
  739. package/dist/services/run-continuations.d.ts.map +1 -0
  740. package/dist/services/run-continuations.js +2 -0
  741. package/dist/services/run-continuations.js.map +1 -0
  742. package/dist/services/run-liveness.d.ts +46 -0
  743. package/dist/services/run-liveness.d.ts.map +1 -0
  744. package/dist/services/run-liveness.js +275 -0
  745. package/dist/services/run-liveness.js.map +1 -0
  746. package/dist/services/run-log-store.d.ts +34 -0
  747. package/dist/services/run-log-store.d.ts.map +1 -0
  748. package/dist/services/run-log-store.js +111 -0
  749. package/dist/services/run-log-store.js.map +1 -0
  750. package/dist/services/sandbox-provider-runtime.d.ts +132 -0
  751. package/dist/services/sandbox-provider-runtime.d.ts.map +1 -0
  752. package/dist/services/sandbox-provider-runtime.js +216 -0
  753. package/dist/services/sandbox-provider-runtime.js.map +1 -0
  754. package/dist/services/secrets.d.ts +515 -0
  755. package/dist/services/secrets.d.ts.map +1 -0
  756. package/dist/services/secrets.js +290 -0
  757. package/dist/services/secrets.js.map +1 -0
  758. package/dist/services/sidebar-badges.d.ts +14 -0
  759. package/dist/services/sidebar-badges.d.ts.map +1 -0
  760. package/dist/services/sidebar-badges.js +48 -0
  761. package/dist/services/sidebar-badges.js.map +1 -0
  762. package/dist/services/sidebar-preferences.d.ts +9 -0
  763. package/dist/services/sidebar-preferences.d.ts.map +1 -0
  764. package/dist/services/sidebar-preferences.js +82 -0
  765. package/dist/services/sidebar-preferences.js.map +1 -0
  766. package/dist/services/work-products.d.ts +14 -0
  767. package/dist/services/work-products.d.ts.map +1 -0
  768. package/dist/services/work-products.js +100 -0
  769. package/dist/services/work-products.js.map +1 -0
  770. package/dist/services/workspace-operation-log-store.d.ts +33 -0
  771. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  772. package/dist/services/workspace-operation-log-store.js +110 -0
  773. package/dist/services/workspace-operation-log-store.js.map +1 -0
  774. package/dist/services/workspace-operations.d.ts +44 -0
  775. package/dist/services/workspace-operations.d.ts.map +1 -0
  776. package/dist/services/workspace-operations.js +211 -0
  777. package/dist/services/workspace-operations.js.map +1 -0
  778. package/dist/services/workspace-realization.d.ts +33 -0
  779. package/dist/services/workspace-realization.d.ts.map +1 -0
  780. package/dist/services/workspace-realization.js +221 -0
  781. package/dist/services/workspace-realization.js.map +1 -0
  782. package/dist/services/workspace-runtime-read-model.d.ts +92 -0
  783. package/dist/services/workspace-runtime-read-model.d.ts.map +1 -0
  784. package/dist/services/workspace-runtime-read-model.js +67 -0
  785. package/dist/services/workspace-runtime-read-model.js.map +1 -0
  786. package/dist/services/workspace-runtime.d.ts +238 -0
  787. package/dist/services/workspace-runtime.d.ts.map +1 -0
  788. package/dist/services/workspace-runtime.js +2388 -0
  789. package/dist/services/workspace-runtime.js.map +1 -0
  790. package/dist/startup-banner.d.ts +32 -0
  791. package/dist/startup-banner.d.ts.map +1 -0
  792. package/dist/startup-banner.js +118 -0
  793. package/dist/startup-banner.js.map +1 -0
  794. package/dist/storage/index.d.ts +6 -0
  795. package/dist/storage/index.d.ts.map +1 -0
  796. package/dist/storage/index.js +29 -0
  797. package/dist/storage/index.js.map +1 -0
  798. package/dist/storage/local-disk-provider.d.ts +3 -0
  799. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  800. package/dist/storage/local-disk-provider.js +79 -0
  801. package/dist/storage/local-disk-provider.js.map +1 -0
  802. package/dist/storage/provider-registry.d.ts +4 -0
  803. package/dist/storage/provider-registry.d.ts.map +1 -0
  804. package/dist/storage/provider-registry.js +15 -0
  805. package/dist/storage/provider-registry.js.map +1 -0
  806. package/dist/storage/s3-provider.d.ts +11 -0
  807. package/dist/storage/s3-provider.d.ts.map +1 -0
  808. package/dist/storage/s3-provider.js +123 -0
  809. package/dist/storage/s3-provider.js.map +1 -0
  810. package/dist/storage/service.d.ts +3 -0
  811. package/dist/storage/service.d.ts.map +1 -0
  812. package/dist/storage/service.js +120 -0
  813. package/dist/storage/service.js.map +1 -0
  814. package/dist/storage/types.d.ts +55 -0
  815. package/dist/storage/types.d.ts.map +1 -0
  816. package/dist/storage/types.js +2 -0
  817. package/dist/storage/types.js.map +1 -0
  818. package/dist/telemetry.d.ts +6 -0
  819. package/dist/telemetry.d.ts.map +1 -0
  820. package/dist/telemetry.js +20 -0
  821. package/dist/telemetry.js.map +1 -0
  822. package/dist/ui-branding.d.ts +13 -0
  823. package/dist/ui-branding.d.ts.map +1 -0
  824. package/dist/ui-branding.js +187 -0
  825. package/dist/ui-branding.js.map +1 -0
  826. package/dist/version.d.ts +2 -0
  827. package/dist/version.d.ts.map +1 -0
  828. package/dist/version.js +5 -0
  829. package/dist/version.js.map +1 -0
  830. package/dist/vite-html-renderer.d.ts +18 -0
  831. package/dist/vite-html-renderer.d.ts.map +1 -0
  832. package/dist/vite-html-renderer.js +61 -0
  833. package/dist/vite-html-renderer.js.map +1 -0
  834. package/dist/worktree-config.d.ts +19 -0
  835. package/dist/worktree-config.d.ts.map +1 -0
  836. package/dist/worktree-config.js +368 -0
  837. package/dist/worktree-config.js.map +1 -0
  838. package/package.json +90 -0
  839. package/skills/diagnose-why-work-stopped/SKILL.md +161 -0
  840. package/skills/evermore/SKILL.md +366 -0
  841. package/skills/evermore/references/api-reference.md +899 -0
  842. package/skills/evermore/references/company-skills.md +193 -0
  843. package/skills/evermore/references/issue-workspaces.md +80 -0
  844. package/skills/evermore/references/routines.md +187 -0
  845. package/skills/evermore/references/workflows.md +141 -0
  846. package/skills/evermore-converting-plans-to-tasks/SKILL.md +42 -0
  847. package/skills/evermore-create-agent/SKILL.md +163 -0
  848. package/skills/evermore-create-agent/references/agent-instruction-templates.md +123 -0
  849. package/skills/evermore-create-agent/references/agents/coder.md +64 -0
  850. package/skills/evermore-create-agent/references/agents/qa.md +88 -0
  851. package/skills/evermore-create-agent/references/agents/securityengineer.md +135 -0
  852. package/skills/evermore-create-agent/references/agents/uxdesigner.md +115 -0
  853. package/skills/evermore-create-agent/references/api-reference.md +110 -0
  854. package/skills/evermore-create-agent/references/baseline-role-guide.md +168 -0
  855. package/skills/evermore-create-agent/references/draft-review-checklist.md +95 -0
  856. package/skills/evermore-create-plugin/SKILL.md +101 -0
  857. package/skills/evermore-dev/SKILL.md +267 -0
  858. package/skills/para-memory-files/SKILL.md +104 -0
  859. package/skills/para-memory-files/references/schemas.md +35 -0
  860. package/skills/terminal-bench-loop/SKILL.md +236 -0
  861. package/ui-dist/android-chrome-192x192.png +0 -0
  862. package/ui-dist/android-chrome-512x512.png +0 -0
  863. package/ui-dist/apple-touch-icon.png +0 -0
  864. package/ui-dist/assets/_basePickBy-Ds9oHp1_.js +1 -0
  865. package/ui-dist/assets/_baseUniq-CHYwQyJ_.js +1 -0
  866. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  867. package/ui-dist/assets/arc-CiUKtBzk.js +1 -0
  868. package/ui-dist/assets/architectureDiagram-VXUJARFQ-CAW2b6pT.js +36 -0
  869. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  870. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  871. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  872. package/ui-dist/assets/blockDiagram-VD42YOAC-1Rk6YCcn.js +122 -0
  873. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  874. package/ui-dist/assets/c4Diagram-YG6GDRKO-DF5RJtyZ.js +10 -0
  875. package/ui-dist/assets/channel-D7SqxhNi.js +1 -0
  876. package/ui-dist/assets/chunk-4BX2VUAB-BSZDJAxk.js +1 -0
  877. package/ui-dist/assets/chunk-55IACEB6-DgVOW-V3.js +1 -0
  878. package/ui-dist/assets/chunk-B4BG7PRW-C1sGAq6t.js +165 -0
  879. package/ui-dist/assets/chunk-DI55MBZ5-DZyfq3VK.js +220 -0
  880. package/ui-dist/assets/chunk-FMBD7UC4-D6K9nYXi.js +15 -0
  881. package/ui-dist/assets/chunk-QN33PNHL-BJ0Ni2l9.js +1 -0
  882. package/ui-dist/assets/chunk-QZHKN3VN-Cwjr0vxG.js +1 -0
  883. package/ui-dist/assets/chunk-TZMSLE5B-C2RGCkyV.js +1 -0
  884. package/ui-dist/assets/classDiagram-2ON5EDUG-Cx1PlXXb.js +1 -0
  885. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-Cx1PlXXb.js +1 -0
  886. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  887. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  888. package/ui-dist/assets/clone-5ZE-SRxk.js +1 -0
  889. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  890. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  891. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  892. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  893. package/ui-dist/assets/cose-bilkent-S5V4N54A-CW0Mh3DC.js +1 -0
  894. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  895. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  896. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  897. package/ui-dist/assets/cytoscape.esm-jbPEKk2Y.js +321 -0
  898. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  899. package/ui-dist/assets/dagre-6UL2VRFP-BXDbyGyw.js +4 -0
  900. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  901. package/ui-dist/assets/diagram-PSM6KHXK-BHW-b3P9.js +24 -0
  902. package/ui-dist/assets/diagram-QEK2KX5R-vjGsaMmX.js +43 -0
  903. package/ui-dist/assets/diagram-S2PKOQOG-BHVhRqBj.js +24 -0
  904. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  905. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  906. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  907. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  908. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  909. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  910. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  911. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  912. package/ui-dist/assets/erDiagram-Q2GNP2WA-DwsdEDB2.js +60 -0
  913. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  914. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  915. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  916. package/ui-dist/assets/flowDiagram-NV44I4VS-Bv7drkZu.js +162 -0
  917. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  918. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  919. package/ui-dist/assets/ganttDiagram-JELNMOA3-DyYAGyjV.js +267 -0
  920. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  921. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  922. package/ui-dist/assets/gitGraphDiagram-V2S2FVAM-DmKJJ2X0.js +65 -0
  923. package/ui-dist/assets/graph-BI12oqz9.js +1 -0
  924. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  925. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  926. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  927. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  928. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  929. package/ui-dist/assets/index-B1YmgKZD.js +1 -0
  930. package/ui-dist/assets/index-B5EG1mbW.js +1 -0
  931. package/ui-dist/assets/index-B63DPkk7.js +2 -0
  932. package/ui-dist/assets/index-BAalUM2u.js +1 -0
  933. package/ui-dist/assets/index-BCyQqUEQ.js +1 -0
  934. package/ui-dist/assets/index-BSRsyahM.js +1 -0
  935. package/ui-dist/assets/index-B_Iu4zUd.js +1 -0
  936. package/ui-dist/assets/index-C-BdZUIH.js +1 -0
  937. package/ui-dist/assets/index-CGgUnSQj.js +6 -0
  938. package/ui-dist/assets/index-COTIEysQ.js +1 -0
  939. package/ui-dist/assets/index-ChSqseHR.js +1 -0
  940. package/ui-dist/assets/index-Ckf1hADU.js +534 -0
  941. package/ui-dist/assets/index-D4M1TSCO.js +3 -0
  942. package/ui-dist/assets/index-DCTk2CN-.js +7 -0
  943. package/ui-dist/assets/index-DI-wyUUr.js +1 -0
  944. package/ui-dist/assets/index-DNtLqZ-D.js +1 -0
  945. package/ui-dist/assets/index-DSRR_614.css +1 -0
  946. package/ui-dist/assets/index-DarmgkJv.js +1 -0
  947. package/ui-dist/assets/index-DdcxF71a.js +1 -0
  948. package/ui-dist/assets/index-DfwWaMga.js +1 -0
  949. package/ui-dist/assets/index-SzUviW57.js +13 -0
  950. package/ui-dist/assets/index-VjZhELb6.js +1 -0
  951. package/ui-dist/assets/index-mEcmy8wG.js +1 -0
  952. package/ui-dist/assets/index-q7ldlDv6.js +1 -0
  953. package/ui-dist/assets/infoDiagram-HS3SLOUP-CqAxMRbC.js +2 -0
  954. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  955. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  956. package/ui-dist/assets/journeyDiagram-XKPGCS4Q-DUJiudtY.js +139 -0
  957. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  958. package/ui-dist/assets/kanban-definition-3W4ZIXB7-CiRgJ4X2.js +89 -0
  959. package/ui-dist/assets/katex-B95LWT_Q.js +261 -0
  960. package/ui-dist/assets/layout-DJ8V2pqt.js +1 -0
  961. package/ui-dist/assets/linear-BwnNUuyZ.js +1 -0
  962. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  963. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  964. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  965. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  966. package/ui-dist/assets/mermaid.core-DLCiCWj4.js +250 -0
  967. package/ui-dist/assets/mindmap-definition-VGOIOE7T-epIiGA01.js +68 -0
  968. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  969. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  970. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  971. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  972. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  973. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  974. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  975. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  976. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  977. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  978. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  979. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  980. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  981. package/ui-dist/assets/pieDiagram-ADFJNKIX-CHx4pJ9Y.js +30 -0
  982. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  983. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  984. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  985. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  986. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  987. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  988. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  989. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  990. package/ui-dist/assets/quadrantDiagram-AYHSOK5B-D0tXmGxE.js +7 -0
  991. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  992. package/ui-dist/assets/requirementDiagram-UZGBJVZJ-BgFc9Xc4.js +64 -0
  993. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  994. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  995. package/ui-dist/assets/sankeyDiagram-TZEHDZUN-DqntX5wV.js +10 -0
  996. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  997. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  998. package/ui-dist/assets/sequenceDiagram-WL72ISMW-BfIJeGAT.js +145 -0
  999. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  1000. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  1001. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  1002. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  1003. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  1004. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  1005. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  1006. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  1007. package/ui-dist/assets/stateDiagram-FKZM4ZOC-CBlsmcoW.js +1 -0
  1008. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-DJtH2tCS.js +1 -0
  1009. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  1010. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  1011. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  1012. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  1013. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  1014. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  1015. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  1016. package/ui-dist/assets/timeline-definition-IT6M3QCI-C2XyT4Lo.js +61 -0
  1017. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  1018. package/ui-dist/assets/treemap-GDKQZRPO-DvTrxs0e.js +154 -0
  1019. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  1020. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  1021. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  1022. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  1023. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  1024. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  1025. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  1026. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  1027. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  1028. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  1029. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  1030. package/ui-dist/assets/xychartDiagram-PRI3JC2R-pTizTbG0.js +7 -0
  1031. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  1032. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  1033. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  1034. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  1035. package/ui-dist/favicon-16x16.png +0 -0
  1036. package/ui-dist/favicon-32x32.png +0 -0
  1037. package/ui-dist/favicon.ico +0 -0
  1038. package/ui-dist/favicon.svg +9 -0
  1039. package/ui-dist/index.html +49 -0
  1040. package/ui-dist/site.webmanifest +30 -0
  1041. package/ui-dist/sw.js +42 -0
  1042. package/ui-dist/worktree-favicon-16x16.png +0 -0
  1043. package/ui-dist/worktree-favicon-32x32.png +0 -0
  1044. package/ui-dist/worktree-favicon.ico +0 -0
  1045. package/ui-dist/worktree-favicon.svg +9 -0
@@ -0,0 +1,1937 @@
1
+ import crypto from "node:crypto";
2
+ import { and, asc, desc, eq, inArray, isNotNull, isNull, lte, not, or, sql } from "drizzle-orm";
3
+ import { agents, companySecretVersions, companySecrets, executionWorkspaces, goals, heartbeatRuns, issueInboxArchives, issueReadStates, issues, pluginManagedResources, plugins, projects, routineRevisions, routineRuns, routines, routineTriggers, } from "@evermore.work/db";
4
+ import { WORKSPACE_BRANCH_ROUTINE_VARIABLE, getBuiltinRoutineVariableValues, extractRoutineVariableNames, interpolateRoutineTemplate, pluginOperationIssueOriginKind, stringifyRoutineVariableValue, syncRoutineVariablesWithTemplate, } from "@evermore.work/shared";
5
+ import { trackRoutineRun } from "@evermore.work/shared/telemetry";
6
+ import { conflict, forbidden, notFound, unauthorized, unprocessable } from "../errors.js";
7
+ import { logger } from "../middleware/logger.js";
8
+ import { getTelemetryClient } from "../telemetry.js";
9
+ import { issueService } from "./issues.js";
10
+ import { secretService } from "./secrets.js";
11
+ import { getSecretProvider } from "../secrets/provider-registry.js";
12
+ import { parseCron, validateCron } from "./cron.js";
13
+ import { heartbeatService } from "./heartbeat.js";
14
+ import { queueIssueAssignmentWakeup } from "./issue-assignment-wakeup.js";
15
+ import { logActivity } from "./activity-log.js";
16
+ const OPEN_ISSUE_STATUSES = ["backlog", "todo", "in_progress", "in_review", "blocked"];
17
+ const LIVE_HEARTBEAT_RUN_STATUSES = ["queued", "running", "scheduled_retry"];
18
+ const TERMINAL_ISSUE_STATUSES = new Set(["done", "cancelled"]);
19
+ const MAX_CATCH_UP_RUNS = 25;
20
+ const MAX_ROUTINE_REVISIONS = 100;
21
+ const WEEKDAY_INDEX = {
22
+ Sun: 0,
23
+ Mon: 1,
24
+ Tue: 2,
25
+ Wed: 3,
26
+ Thu: 4,
27
+ Fri: 5,
28
+ Sat: 6,
29
+ };
30
+ function assertTimeZone(timeZone) {
31
+ try {
32
+ new Intl.DateTimeFormat("en-US", { timeZone }).format(new Date());
33
+ }
34
+ catch {
35
+ throw unprocessable(`Invalid timezone: ${timeZone}`);
36
+ }
37
+ }
38
+ function floorToMinute(date) {
39
+ const copy = new Date(date.getTime());
40
+ copy.setUTCSeconds(0, 0);
41
+ return copy;
42
+ }
43
+ function getZonedMinuteParts(date, timeZone) {
44
+ const formatter = new Intl.DateTimeFormat("en-US", {
45
+ timeZone,
46
+ hour12: false,
47
+ year: "numeric",
48
+ month: "numeric",
49
+ day: "numeric",
50
+ hour: "numeric",
51
+ minute: "numeric",
52
+ weekday: "short",
53
+ });
54
+ const parts = formatter.formatToParts(date);
55
+ const map = Object.fromEntries(parts.map((part) => [part.type, part.value]));
56
+ const weekday = WEEKDAY_INDEX[map.weekday ?? ""];
57
+ if (weekday == null) {
58
+ throw new Error(`Unable to resolve weekday for timezone ${timeZone}`);
59
+ }
60
+ return {
61
+ year: Number(map.year),
62
+ month: Number(map.month),
63
+ day: Number(map.day),
64
+ hour: Number(map.hour),
65
+ minute: Number(map.minute),
66
+ weekday,
67
+ };
68
+ }
69
+ function matchesCronMinute(expression, timeZone, date) {
70
+ const cron = parseCron(expression);
71
+ const parts = getZonedMinuteParts(date, timeZone);
72
+ return (cron.minutes.includes(parts.minute) &&
73
+ cron.hours.includes(parts.hour) &&
74
+ cron.daysOfMonth.includes(parts.day) &&
75
+ cron.months.includes(parts.month) &&
76
+ cron.daysOfWeek.includes(parts.weekday));
77
+ }
78
+ function nextCronTickInTimeZone(expression, timeZone, after) {
79
+ const trimmed = expression.trim();
80
+ assertTimeZone(timeZone);
81
+ const error = validateCron(trimmed);
82
+ if (error) {
83
+ throw unprocessable(error);
84
+ }
85
+ const cursor = floorToMinute(after);
86
+ cursor.setUTCMinutes(cursor.getUTCMinutes() + 1);
87
+ const limit = 366 * 24 * 60 * 5;
88
+ for (let i = 0; i < limit; i += 1) {
89
+ if (matchesCronMinute(trimmed, timeZone, cursor)) {
90
+ return new Date(cursor.getTime());
91
+ }
92
+ cursor.setUTCMinutes(cursor.getUTCMinutes() + 1);
93
+ }
94
+ return null;
95
+ }
96
+ function nextResultText(status, issueId) {
97
+ if (status === "issue_created" && issueId)
98
+ return `Created execution issue ${issueId}`;
99
+ if (status === "coalesced")
100
+ return "Coalesced into an existing live execution issue";
101
+ if (status === "skipped")
102
+ return "Skipped because a live execution issue already exists";
103
+ if (status === "completed")
104
+ return "Execution issue completed";
105
+ if (status === "failed")
106
+ return "Execution failed";
107
+ return status;
108
+ }
109
+ function normalizeWebhookTimestampMs(rawTimestamp) {
110
+ const parsed = Number(rawTimestamp);
111
+ if (!Number.isFinite(parsed))
112
+ return null;
113
+ return parsed > 1e12 ? parsed : parsed * 1000;
114
+ }
115
+ function isPlainRecord(value) {
116
+ return typeof value === "object" && value !== null && !Array.isArray(value);
117
+ }
118
+ function parseBooleanVariableValue(name, raw) {
119
+ if (typeof raw === "boolean")
120
+ return raw;
121
+ if (typeof raw === "number" && (raw === 0 || raw === 1))
122
+ return raw === 1;
123
+ if (typeof raw === "string") {
124
+ const normalized = raw.trim().toLowerCase();
125
+ if (["true", "1", "yes", "y", "on"].includes(normalized))
126
+ return true;
127
+ if (["false", "0", "no", "n", "off"].includes(normalized))
128
+ return false;
129
+ }
130
+ throw unprocessable(`Variable "${name}" must be a boolean`);
131
+ }
132
+ function parseNumberVariableValue(name, raw) {
133
+ if (typeof raw === "number" && Number.isFinite(raw))
134
+ return raw;
135
+ if (typeof raw === "string" && raw.trim().length > 0) {
136
+ const parsed = Number(raw);
137
+ if (Number.isFinite(parsed))
138
+ return parsed;
139
+ }
140
+ throw unprocessable(`Variable "${name}" must be a number`);
141
+ }
142
+ function normalizeRoutineVariableValue(variable, raw) {
143
+ if (raw == null)
144
+ return null;
145
+ if (variable.type === "boolean")
146
+ return parseBooleanVariableValue(variable.name, raw);
147
+ if (variable.type === "number")
148
+ return parseNumberVariableValue(variable.name, raw);
149
+ const normalized = stringifyRoutineVariableValue(raw);
150
+ if (variable.type === "select") {
151
+ if (!variable.options.includes(normalized)) {
152
+ throw unprocessable(`Variable "${variable.name}" must match one of: ${variable.options.join(", ")}`);
153
+ }
154
+ }
155
+ return normalized;
156
+ }
157
+ function isMissingRoutineVariableValue(value) {
158
+ return value == null || (typeof value === "string" && value.trim().length === 0);
159
+ }
160
+ function assertRoutineVariableDefinitions(variables) {
161
+ for (const variable of variables) {
162
+ if (variable.defaultValue != null) {
163
+ normalizeRoutineVariableValue(variable, variable.defaultValue);
164
+ }
165
+ if (variable.type === "select" && variable.options.length === 0) {
166
+ throw unprocessable(`Variable "${variable.name}" must define at least one option`);
167
+ }
168
+ }
169
+ }
170
+ function sanitizeRoutineVariableInputs(variables) {
171
+ return (variables ?? []).map((variable) => ({
172
+ name: variable.name,
173
+ label: variable.label ?? null,
174
+ type: variable.type ?? "text",
175
+ defaultValue: variable.defaultValue ?? null,
176
+ required: variable.required ?? true,
177
+ options: variable.options ?? [],
178
+ }));
179
+ }
180
+ function assertScheduleCompatibleVariables(variables) {
181
+ const missingDefaults = variables
182
+ .filter((variable) => variable.required)
183
+ .filter((variable) => {
184
+ try {
185
+ return isMissingRoutineVariableValue(normalizeRoutineVariableValue(variable, variable.defaultValue));
186
+ }
187
+ catch {
188
+ return true;
189
+ }
190
+ })
191
+ .map((variable) => variable.name);
192
+ if (missingDefaults.length > 0) {
193
+ throw unprocessable(`Scheduled routines require defaults for required variables: ${missingDefaults.join(", ")}`);
194
+ }
195
+ }
196
+ function statusRequiresDefaultAgent(status) {
197
+ return status === "active";
198
+ }
199
+ function normalizeDraftRoutineStatus(status, assigneeAgentId) {
200
+ if (statusRequiresDefaultAgent(status) && !assigneeAgentId) {
201
+ return "paused";
202
+ }
203
+ return status;
204
+ }
205
+ function assertRoutineCanEnable(status, assigneeAgentId) {
206
+ if (statusRequiresDefaultAgent(status) && !assigneeAgentId) {
207
+ throw unprocessable("Default agent required");
208
+ }
209
+ }
210
+ function collectProvidedRoutineVariables(source, payload, variables) {
211
+ const nestedVariables = isPlainRecord(payload) && isPlainRecord(payload.variables) ? payload.variables : {};
212
+ const provided = {
213
+ ...(source === "webhook" && payload ? payload : {}),
214
+ ...nestedVariables,
215
+ ...(variables ?? {}),
216
+ };
217
+ delete provided.variables;
218
+ return provided;
219
+ }
220
+ function resolveRoutineVariableValues(variables, input) {
221
+ if (variables.length === 0)
222
+ return {};
223
+ const provided = collectProvidedRoutineVariables(input.source, input.payload, input.variables);
224
+ const automaticVariables = input.automaticVariables ?? {};
225
+ const resolved = {};
226
+ const missing = [];
227
+ for (const variable of variables) {
228
+ // Workspace-derived automatic values are authoritative for variables that
229
+ // Evermore manages from execution context, so callers cannot override them.
230
+ const candidate = automaticVariables[variable.name] !== undefined
231
+ ? automaticVariables[variable.name]
232
+ : provided[variable.name] !== undefined
233
+ ? provided[variable.name]
234
+ : variable.defaultValue;
235
+ const normalized = normalizeRoutineVariableValue(variable, candidate);
236
+ if (normalized == null || (typeof normalized === "string" && normalized.trim().length === 0)) {
237
+ if (variable.required)
238
+ missing.push(variable.name);
239
+ continue;
240
+ }
241
+ resolved[variable.name] = normalized;
242
+ }
243
+ if (missing.length > 0) {
244
+ throw unprocessable(`Missing routine variables: ${missing.join(", ")}`);
245
+ }
246
+ return resolved;
247
+ }
248
+ function mergeRoutineRunPayload(payload, variables) {
249
+ if (Object.keys(variables).length === 0)
250
+ return payload ?? null;
251
+ if (!payload)
252
+ return { variables };
253
+ const existingVariables = isPlainRecord(payload.variables) ? payload.variables : {};
254
+ return {
255
+ ...payload,
256
+ variables: {
257
+ ...existingVariables,
258
+ ...variables,
259
+ },
260
+ };
261
+ }
262
+ function normalizeRoutineDispatchFingerprintValue(value) {
263
+ if (value === undefined)
264
+ return null;
265
+ if (value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
266
+ return value;
267
+ }
268
+ if (value instanceof Date)
269
+ return value.toISOString();
270
+ if (Array.isArray(value))
271
+ return value.map((item) => normalizeRoutineDispatchFingerprintValue(item));
272
+ if (isPlainRecord(value)) {
273
+ return Object.fromEntries(Object.keys(value)
274
+ .sort()
275
+ .map((key) => [key, normalizeRoutineDispatchFingerprintValue(value[key])]));
276
+ }
277
+ return String(value);
278
+ }
279
+ function createRoutineDispatchFingerprint(input) {
280
+ const canonical = JSON.stringify(normalizeRoutineDispatchFingerprintValue(input));
281
+ return crypto.createHash("sha256").update(canonical).digest("hex");
282
+ }
283
+ function readManagedRoutineIssueTemplate(defaultsJson) {
284
+ const value = defaultsJson?.issueTemplate;
285
+ if (!isPlainRecord(value))
286
+ return null;
287
+ return {
288
+ surfaceVisibility: typeof value.surfaceVisibility === "string" ? value.surfaceVisibility : null,
289
+ originId: typeof value.originId === "string" && value.originId.trim() ? value.originId.trim() : null,
290
+ billingCode: typeof value.billingCode === "string" && value.billingCode.trim() ? value.billingCode.trim() : null,
291
+ };
292
+ }
293
+ function routineUsesWorkspaceBranch(routine) {
294
+ return (routine.variables ?? []).some((variable) => variable.name === WORKSPACE_BRANCH_ROUTINE_VARIABLE)
295
+ || extractRoutineVariableNames([routine.title, routine.description]).includes(WORKSPACE_BRANCH_ROUTINE_VARIABLE);
296
+ }
297
+ function routineRevisionSnapshotRoutine(routine) {
298
+ return {
299
+ id: routine.id,
300
+ companyId: routine.companyId,
301
+ projectId: routine.projectId,
302
+ goalId: routine.goalId,
303
+ parentIssueId: routine.parentIssueId,
304
+ title: routine.title,
305
+ description: routine.description,
306
+ assigneeAgentId: routine.assigneeAgentId,
307
+ priority: routine.priority,
308
+ status: routine.status,
309
+ concurrencyPolicy: routine.concurrencyPolicy,
310
+ catchUpPolicy: routine.catchUpPolicy,
311
+ variables: routine.variables ?? [],
312
+ };
313
+ }
314
+ function routineRevisionSnapshotTrigger(trigger) {
315
+ return {
316
+ id: trigger.id,
317
+ kind: trigger.kind,
318
+ label: trigger.label,
319
+ enabled: trigger.enabled,
320
+ cronExpression: trigger.cronExpression,
321
+ timezone: trigger.timezone,
322
+ publicId: trigger.publicId,
323
+ signingMode: trigger.signingMode,
324
+ replayWindowSec: trigger.replayWindowSec,
325
+ };
326
+ }
327
+ async function buildRoutineRevisionSnapshot(executor, routine) {
328
+ const triggers = await executor
329
+ .select()
330
+ .from(routineTriggers)
331
+ .where(and(eq(routineTriggers.companyId, routine.companyId), eq(routineTriggers.routineId, routine.id)))
332
+ .orderBy(asc(routineTriggers.createdAt), asc(routineTriggers.id));
333
+ return {
334
+ version: 1,
335
+ routine: routineRevisionSnapshotRoutine(routine),
336
+ triggers: triggers.map(routineRevisionSnapshotTrigger),
337
+ };
338
+ }
339
+ function canonicalSnapshot(value) {
340
+ return JSON.stringify(value);
341
+ }
342
+ function snapshotsMatch(left, right) {
343
+ return canonicalSnapshot(left) === canonicalSnapshot(right);
344
+ }
345
+ function routineCurrentFieldsMatch(left, right) {
346
+ return snapshotsMatch({ version: 1, routine: routineRevisionSnapshotRoutine(left), triggers: [] }, { version: 1, routine: routineRevisionSnapshotRoutine(right), triggers: [] });
347
+ }
348
+ function mapRoutineRevision(row) {
349
+ return {
350
+ ...row,
351
+ snapshot: row.snapshot,
352
+ };
353
+ }
354
+ export function routineService(db, deps = {}) {
355
+ const issueSvc = issueService(db);
356
+ const secretsSvc = secretService(db);
357
+ const heartbeat = deps.heartbeat ?? heartbeatService(db, {
358
+ pluginWorkerManager: deps.pluginWorkerManager,
359
+ });
360
+ async function getRoutineById(id) {
361
+ return db
362
+ .select()
363
+ .from(routines)
364
+ .where(eq(routines.id, id))
365
+ .then((rows) => rows[0] ?? null);
366
+ }
367
+ async function getManagedRoutineBinding(routine) {
368
+ return db
369
+ .select({
370
+ pluginKey: pluginManagedResources.pluginKey,
371
+ defaultsJson: pluginManagedResources.defaultsJson,
372
+ manifestJson: plugins.manifestJson,
373
+ })
374
+ .from(pluginManagedResources)
375
+ .innerJoin(plugins, eq(pluginManagedResources.pluginId, plugins.id))
376
+ .where(and(eq(pluginManagedResources.companyId, routine.companyId), eq(pluginManagedResources.resourceKind, "routine"), eq(pluginManagedResources.resourceId, routine.id)))
377
+ .then((rows) => rows[0] ?? null);
378
+ }
379
+ async function listManagedRoutineMetadata(routineIds) {
380
+ if (routineIds.length === 0)
381
+ return new Map();
382
+ const rows = await db
383
+ .select({
384
+ id: pluginManagedResources.id,
385
+ pluginId: pluginManagedResources.pluginId,
386
+ pluginKey: pluginManagedResources.pluginKey,
387
+ manifestJson: plugins.manifestJson,
388
+ resourceKey: pluginManagedResources.resourceKey,
389
+ resourceId: pluginManagedResources.resourceId,
390
+ defaultsJson: pluginManagedResources.defaultsJson,
391
+ createdAt: pluginManagedResources.createdAt,
392
+ updatedAt: pluginManagedResources.updatedAt,
393
+ })
394
+ .from(pluginManagedResources)
395
+ .innerJoin(plugins, eq(pluginManagedResources.pluginId, plugins.id))
396
+ .where(and(eq(pluginManagedResources.resourceKind, "routine"), inArray(pluginManagedResources.resourceId, routineIds)));
397
+ return new Map(rows.map((row) => [
398
+ row.resourceId,
399
+ {
400
+ id: row.id,
401
+ pluginId: row.pluginId,
402
+ pluginKey: row.pluginKey,
403
+ pluginDisplayName: row.manifestJson.displayName ?? row.pluginKey,
404
+ resourceKind: "routine",
405
+ resourceKey: row.resourceKey,
406
+ defaultsJson: row.defaultsJson,
407
+ createdAt: row.createdAt,
408
+ updatedAt: row.updatedAt,
409
+ },
410
+ ]));
411
+ }
412
+ async function getTriggerById(id) {
413
+ return db
414
+ .select()
415
+ .from(routineTriggers)
416
+ .where(eq(routineTriggers.id, id))
417
+ .then((rows) => rows[0] ?? null);
418
+ }
419
+ async function appendRoutineRevision(executor, routine, actor, options = {}) {
420
+ const snapshot = await buildRoutineRevisionSnapshot(executor, routine);
421
+ const nextRevisionNumber = routine.latestRevisionId ? routine.latestRevisionNumber + 1 : 1;
422
+ const now = new Date();
423
+ const [revision] = await executor
424
+ .insert(routineRevisions)
425
+ .values({
426
+ companyId: routine.companyId,
427
+ routineId: routine.id,
428
+ revisionNumber: nextRevisionNumber,
429
+ title: snapshot.routine.title,
430
+ description: snapshot.routine.description,
431
+ snapshot,
432
+ changeSummary: options.changeSummary ?? null,
433
+ restoredFromRevisionId: options.restoredFromRevisionId ?? null,
434
+ createdByAgentId: actor.agentId ?? null,
435
+ createdByUserId: actor.userId ?? null,
436
+ createdByRunId: actor.runId ?? null,
437
+ createdAt: now,
438
+ })
439
+ .returning();
440
+ const [updatedRoutine] = await executor
441
+ .update(routines)
442
+ .set({
443
+ latestRevisionId: revision.id,
444
+ latestRevisionNumber: nextRevisionNumber,
445
+ updatedAt: now,
446
+ })
447
+ .where(eq(routines.id, routine.id))
448
+ .returning();
449
+ return {
450
+ routine: updatedRoutine ?? { ...routine, latestRevisionId: revision.id, latestRevisionNumber: nextRevisionNumber, updatedAt: now },
451
+ revision: mapRoutineRevision(revision),
452
+ };
453
+ }
454
+ async function assertRoutineAccess(companyId, routineId) {
455
+ const routine = await getRoutineById(routineId);
456
+ if (!routine)
457
+ throw notFound("Routine not found");
458
+ if (routine.companyId !== companyId)
459
+ throw forbidden("Routine must belong to same company");
460
+ return routine;
461
+ }
462
+ async function assertAssignableAgent(companyId, agentId) {
463
+ if (!agentId)
464
+ return;
465
+ const agent = await db
466
+ .select({ id: agents.id, companyId: agents.companyId, status: agents.status })
467
+ .from(agents)
468
+ .where(eq(agents.id, agentId))
469
+ .then((rows) => rows[0] ?? null);
470
+ if (!agent)
471
+ throw notFound("Assignee agent not found");
472
+ if (agent.companyId !== companyId)
473
+ throw unprocessable("Assignee must belong to same company");
474
+ if (agent.status === "pending_approval")
475
+ throw conflict("Cannot assign routines to pending approval agents");
476
+ if (agent.status === "terminated")
477
+ throw conflict("Cannot assign routines to terminated agents");
478
+ }
479
+ async function assertRestorableAssignee(companyId, assigneeAgentId, actor) {
480
+ await assertAssignableAgent(companyId, assigneeAgentId);
481
+ if (actor.agentId && assigneeAgentId !== actor.agentId) {
482
+ throw forbidden("Agents can only restore routine revisions assigned to themselves");
483
+ }
484
+ }
485
+ async function assertProject(companyId, projectId) {
486
+ if (!projectId)
487
+ return;
488
+ const project = await db
489
+ .select({ id: projects.id, companyId: projects.companyId })
490
+ .from(projects)
491
+ .where(eq(projects.id, projectId))
492
+ .then((rows) => rows[0] ?? null);
493
+ if (!project)
494
+ throw notFound("Project not found");
495
+ if (project.companyId !== companyId)
496
+ throw unprocessable("Project must belong to same company");
497
+ }
498
+ async function assertGoal(companyId, goalId) {
499
+ const goal = await db
500
+ .select({ id: goals.id, companyId: goals.companyId })
501
+ .from(goals)
502
+ .where(eq(goals.id, goalId))
503
+ .then((rows) => rows[0] ?? null);
504
+ if (!goal)
505
+ throw notFound("Goal not found");
506
+ if (goal.companyId !== companyId)
507
+ throw unprocessable("Goal must belong to same company");
508
+ }
509
+ async function assertParentIssue(companyId, issueId) {
510
+ const parentIssue = await db
511
+ .select({ id: issues.id, companyId: issues.companyId })
512
+ .from(issues)
513
+ .where(eq(issues.id, issueId))
514
+ .then((rows) => rows[0] ?? null);
515
+ if (!parentIssue)
516
+ throw notFound("Parent issue not found");
517
+ if (parentIssue.companyId !== companyId)
518
+ throw unprocessable("Parent issue must belong to same company");
519
+ }
520
+ async function listTriggersForRoutineIds(companyId, routineIds) {
521
+ if (routineIds.length === 0)
522
+ return new Map();
523
+ const rows = await db
524
+ .select()
525
+ .from(routineTriggers)
526
+ .where(and(eq(routineTriggers.companyId, companyId), inArray(routineTriggers.routineId, routineIds)))
527
+ .orderBy(asc(routineTriggers.createdAt), asc(routineTriggers.id));
528
+ const map = new Map();
529
+ for (const row of rows) {
530
+ const list = map.get(row.routineId) ?? [];
531
+ list.push(row);
532
+ map.set(row.routineId, list);
533
+ }
534
+ return map;
535
+ }
536
+ async function listLatestRunByRoutineIds(companyId, routineIds) {
537
+ if (routineIds.length === 0)
538
+ return new Map();
539
+ const rows = await db
540
+ .selectDistinctOn([routineRuns.routineId], {
541
+ id: routineRuns.id,
542
+ companyId: routineRuns.companyId,
543
+ routineId: routineRuns.routineId,
544
+ triggerId: routineRuns.triggerId,
545
+ source: routineRuns.source,
546
+ status: routineRuns.status,
547
+ triggeredAt: routineRuns.triggeredAt,
548
+ idempotencyKey: routineRuns.idempotencyKey,
549
+ triggerPayload: routineRuns.triggerPayload,
550
+ dispatchFingerprint: routineRuns.dispatchFingerprint,
551
+ linkedIssueId: routineRuns.linkedIssueId,
552
+ coalescedIntoRunId: routineRuns.coalescedIntoRunId,
553
+ failureReason: routineRuns.failureReason,
554
+ completedAt: routineRuns.completedAt,
555
+ createdAt: routineRuns.createdAt,
556
+ updatedAt: routineRuns.updatedAt,
557
+ triggerKind: routineTriggers.kind,
558
+ triggerLabel: routineTriggers.label,
559
+ issueIdentifier: issues.identifier,
560
+ issueTitle: issues.title,
561
+ issueStatus: issues.status,
562
+ issuePriority: issues.priority,
563
+ issueUpdatedAt: issues.updatedAt,
564
+ })
565
+ .from(routineRuns)
566
+ .leftJoin(routineTriggers, eq(routineRuns.triggerId, routineTriggers.id))
567
+ .leftJoin(issues, eq(routineRuns.linkedIssueId, issues.id))
568
+ .where(and(eq(routineRuns.companyId, companyId), inArray(routineRuns.routineId, routineIds)))
569
+ .orderBy(routineRuns.routineId, desc(routineRuns.createdAt), desc(routineRuns.id));
570
+ const map = new Map();
571
+ for (const row of rows) {
572
+ map.set(row.routineId, {
573
+ id: row.id,
574
+ companyId: row.companyId,
575
+ routineId: row.routineId,
576
+ triggerId: row.triggerId,
577
+ source: row.source,
578
+ status: row.status,
579
+ triggeredAt: row.triggeredAt,
580
+ idempotencyKey: row.idempotencyKey,
581
+ triggerPayload: row.triggerPayload,
582
+ dispatchFingerprint: row.dispatchFingerprint,
583
+ linkedIssueId: row.linkedIssueId,
584
+ coalescedIntoRunId: row.coalescedIntoRunId,
585
+ failureReason: row.failureReason,
586
+ completedAt: row.completedAt,
587
+ createdAt: row.createdAt,
588
+ updatedAt: row.updatedAt,
589
+ linkedIssue: row.linkedIssueId
590
+ ? {
591
+ id: row.linkedIssueId,
592
+ identifier: row.issueIdentifier,
593
+ title: row.issueTitle ?? "Routine execution",
594
+ status: row.issueStatus ?? "todo",
595
+ priority: row.issuePriority ?? "medium",
596
+ updatedAt: row.issueUpdatedAt ?? row.updatedAt,
597
+ }
598
+ : null,
599
+ trigger: row.triggerId
600
+ ? {
601
+ id: row.triggerId,
602
+ kind: row.triggerKind,
603
+ label: row.triggerLabel,
604
+ }
605
+ : null,
606
+ });
607
+ }
608
+ return map;
609
+ }
610
+ async function listLiveIssueByRoutineIds(companyId, routineIds) {
611
+ if (routineIds.length === 0)
612
+ return new Map();
613
+ const executionBoundRows = await db
614
+ .selectDistinctOn([issues.originId], {
615
+ originId: issues.originId,
616
+ id: issues.id,
617
+ identifier: issues.identifier,
618
+ title: issues.title,
619
+ status: issues.status,
620
+ priority: issues.priority,
621
+ updatedAt: issues.updatedAt,
622
+ })
623
+ .from(issues)
624
+ .innerJoin(heartbeatRuns, and(eq(heartbeatRuns.id, issues.executionRunId), inArray(heartbeatRuns.status, LIVE_HEARTBEAT_RUN_STATUSES)))
625
+ .where(and(eq(issues.companyId, companyId), eq(issues.originKind, "routine_execution"), inArray(issues.originId, routineIds), inArray(issues.status, OPEN_ISSUE_STATUSES), isNull(issues.hiddenAt)))
626
+ .orderBy(issues.originId, desc(issues.updatedAt), desc(issues.createdAt));
627
+ const rowsByOriginId = new Map();
628
+ for (const row of executionBoundRows) {
629
+ if (!row.originId)
630
+ continue;
631
+ rowsByOriginId.set(row.originId, row);
632
+ }
633
+ const missingRoutineIds = routineIds.filter((routineId) => !rowsByOriginId.has(routineId));
634
+ if (missingRoutineIds.length > 0) {
635
+ const legacyRows = await db
636
+ .selectDistinctOn([issues.originId], {
637
+ originId: issues.originId,
638
+ id: issues.id,
639
+ identifier: issues.identifier,
640
+ title: issues.title,
641
+ status: issues.status,
642
+ priority: issues.priority,
643
+ updatedAt: issues.updatedAt,
644
+ })
645
+ .from(issues)
646
+ .innerJoin(heartbeatRuns, and(eq(heartbeatRuns.companyId, issues.companyId), inArray(heartbeatRuns.status, LIVE_HEARTBEAT_RUN_STATUSES), sql `${heartbeatRuns.contextSnapshot} ->> 'issueId' = cast(${issues.id} as text)`))
647
+ .where(and(eq(issues.companyId, companyId), eq(issues.originKind, "routine_execution"), inArray(issues.originId, missingRoutineIds), inArray(issues.status, OPEN_ISSUE_STATUSES), isNull(issues.hiddenAt)))
648
+ .orderBy(issues.originId, desc(issues.updatedAt), desc(issues.createdAt));
649
+ for (const row of legacyRows) {
650
+ if (!row.originId)
651
+ continue;
652
+ rowsByOriginId.set(row.originId, row);
653
+ }
654
+ }
655
+ const map = new Map();
656
+ for (const row of rowsByOriginId.values()) {
657
+ if (!row.originId)
658
+ continue;
659
+ map.set(row.originId, {
660
+ id: row.id,
661
+ identifier: row.identifier,
662
+ title: row.title,
663
+ status: row.status,
664
+ priority: row.priority,
665
+ updatedAt: row.updatedAt,
666
+ });
667
+ }
668
+ return map;
669
+ }
670
+ async function updateRoutineTouchedState(input, executor = db) {
671
+ await executor
672
+ .update(routines)
673
+ .set({
674
+ lastTriggeredAt: input.triggeredAt,
675
+ lastEnqueuedAt: input.issueId ? input.triggeredAt : undefined,
676
+ updatedAt: new Date(),
677
+ })
678
+ .where(eq(routines.id, input.routineId));
679
+ if (input.triggerId) {
680
+ await executor
681
+ .update(routineTriggers)
682
+ .set({
683
+ lastFiredAt: input.triggeredAt,
684
+ lastResult: nextResultText(input.status, input.issueId),
685
+ nextRunAt: input.nextRunAt === undefined ? undefined : input.nextRunAt,
686
+ updatedAt: new Date(),
687
+ })
688
+ .where(eq(routineTriggers.id, input.triggerId));
689
+ }
690
+ }
691
+ function routineExecutionFingerprintCondition(dispatchFingerprint) {
692
+ if (!dispatchFingerprint)
693
+ return null;
694
+ // The "default" arm preserves coalescing against pre-migration open issues.
695
+ // It becomes inert once those legacy routine execution issues drain out.
696
+ return or(eq(issues.originFingerprint, dispatchFingerprint), eq(issues.originFingerprint, "default"));
697
+ }
698
+ async function findLiveExecutionIssue(routine, executor = db, dispatchFingerprint, origin) {
699
+ const fingerprintCondition = routineExecutionFingerprintCondition(dispatchFingerprint);
700
+ const originKind = origin?.kind ?? "routine_execution";
701
+ const originId = origin?.id ?? routine.id;
702
+ const executionBoundIssue = await executor
703
+ .select()
704
+ .from(issues)
705
+ .innerJoin(heartbeatRuns, and(eq(heartbeatRuns.id, issues.executionRunId), inArray(heartbeatRuns.status, LIVE_HEARTBEAT_RUN_STATUSES)))
706
+ .where(and(eq(issues.companyId, routine.companyId), eq(issues.originKind, originKind), eq(issues.originId, originId), inArray(issues.status, OPEN_ISSUE_STATUSES), isNull(issues.hiddenAt), ...(fingerprintCondition ? [fingerprintCondition] : [])))
707
+ .orderBy(desc(issues.updatedAt), desc(issues.createdAt))
708
+ .limit(1)
709
+ .then((rows) => rows[0]?.issues ?? null);
710
+ if (executionBoundIssue)
711
+ return executionBoundIssue;
712
+ return executor
713
+ .select()
714
+ .from(issues)
715
+ .innerJoin(heartbeatRuns, and(eq(heartbeatRuns.companyId, issues.companyId), inArray(heartbeatRuns.status, LIVE_HEARTBEAT_RUN_STATUSES), sql `${heartbeatRuns.contextSnapshot} ->> 'issueId' = cast(${issues.id} as text)`))
716
+ .where(and(eq(issues.companyId, routine.companyId), eq(issues.originKind, originKind), eq(issues.originId, originId), inArray(issues.status, OPEN_ISSUE_STATUSES), isNull(issues.hiddenAt), ...(fingerprintCondition ? [fingerprintCondition] : [])))
717
+ .orderBy(desc(issues.updatedAt), desc(issues.createdAt))
718
+ .limit(1)
719
+ .then((rows) => rows[0]?.issues ?? null);
720
+ }
721
+ async function finalizeRun(runId, patch, executor = db) {
722
+ return executor
723
+ .update(routineRuns)
724
+ .set({
725
+ ...patch,
726
+ updatedAt: new Date(),
727
+ })
728
+ .where(eq(routineRuns.id, runId))
729
+ .returning()
730
+ .then((rows) => rows[0] ?? null);
731
+ }
732
+ async function createWebhookSecret(companyId, routineId, actor, executor) {
733
+ const secretValue = crypto.randomBytes(24).toString("hex");
734
+ const input = {
735
+ name: `routine-${routineId}-${crypto.randomBytes(6).toString("hex")}`,
736
+ provider: "local_encrypted",
737
+ value: secretValue,
738
+ description: `Webhook auth for routine ${routineId}`,
739
+ };
740
+ const provider = getSecretProvider(input.provider);
741
+ const prepared = await provider.createVersion({
742
+ value: input.value,
743
+ externalRef: null,
744
+ });
745
+ const insertSecret = async (secretDb) => {
746
+ const secret = await secretDb
747
+ .insert(companySecrets)
748
+ .values({
749
+ companyId,
750
+ name: input.name,
751
+ provider: input.provider,
752
+ externalRef: prepared.externalRef,
753
+ latestVersion: 1,
754
+ description: input.description,
755
+ createdByAgentId: actor.agentId ?? null,
756
+ createdByUserId: actor.userId ?? null,
757
+ })
758
+ .returning()
759
+ .then((rows) => rows[0]);
760
+ await secretDb.insert(companySecretVersions).values({
761
+ secretId: secret.id,
762
+ version: 1,
763
+ material: prepared.material,
764
+ valueSha256: prepared.valueSha256,
765
+ createdByAgentId: actor.agentId ?? null,
766
+ createdByUserId: actor.userId ?? null,
767
+ });
768
+ return secret;
769
+ };
770
+ const secret = executor
771
+ ? await insertSecret(executor)
772
+ : await db.transaction(async (tx) => insertSecret(tx));
773
+ return { secret, secretValue };
774
+ }
775
+ async function resolveTriggerSecret(trigger, companyId) {
776
+ if (!trigger.secretId)
777
+ throw notFound("Routine trigger secret not found");
778
+ const secret = await db
779
+ .select()
780
+ .from(companySecrets)
781
+ .where(eq(companySecrets.id, trigger.secretId))
782
+ .then((rows) => rows[0] ?? null);
783
+ if (!secret || secret.companyId !== companyId)
784
+ throw notFound("Routine trigger secret not found");
785
+ const value = await secretsSvc.resolveSecretValue(companyId, trigger.secretId, "latest");
786
+ return value;
787
+ }
788
+ async function touchIssueForUserInbox(executor, input) {
789
+ await executor
790
+ .insert(issueReadStates)
791
+ .values({
792
+ companyId: input.companyId,
793
+ issueId: input.issueId,
794
+ userId: input.userId,
795
+ lastReadAt: input.touchedAt,
796
+ updatedAt: input.touchedAt,
797
+ })
798
+ .onConflictDoUpdate({
799
+ target: [issueReadStates.companyId, issueReadStates.issueId, issueReadStates.userId],
800
+ set: {
801
+ lastReadAt: input.touchedAt,
802
+ updatedAt: input.touchedAt,
803
+ },
804
+ });
805
+ await executor
806
+ .delete(issueInboxArchives)
807
+ .where(and(eq(issueInboxArchives.companyId, input.companyId), eq(issueInboxArchives.issueId, input.issueId), eq(issueInboxArchives.userId, input.userId)));
808
+ }
809
+ async function dispatchRoutineRun(input) {
810
+ const projectId = input.projectId ?? input.routine.projectId ?? null;
811
+ const assigneeAgentId = input.assigneeAgentId ?? input.routine.assigneeAgentId ?? null;
812
+ if (!assigneeAgentId) {
813
+ throw unprocessable("Default agent required");
814
+ }
815
+ const automaticVariables = {};
816
+ if (input.executionWorkspaceId && routineUsesWorkspaceBranch(input.routine)) {
817
+ const workspace = await db
818
+ .select({
819
+ branchName: executionWorkspaces.branchName,
820
+ mode: executionWorkspaces.mode,
821
+ })
822
+ .from(executionWorkspaces)
823
+ .where(and(eq(executionWorkspaces.id, input.executionWorkspaceId), eq(executionWorkspaces.companyId, input.routine.companyId)))
824
+ .then((rows) => rows[0] ?? null);
825
+ const branchName = workspace?.branchName?.trim();
826
+ if (workspace && workspace.mode !== "shared_workspace" && branchName) {
827
+ automaticVariables[WORKSPACE_BRANCH_ROUTINE_VARIABLE] = branchName;
828
+ }
829
+ }
830
+ const resolvedVariables = resolveRoutineVariableValues(input.routine.variables ?? [], {
831
+ ...input,
832
+ automaticVariables,
833
+ });
834
+ const allVariables = { ...getBuiltinRoutineVariableValues(), ...automaticVariables, ...resolvedVariables };
835
+ const title = interpolateRoutineTemplate(input.routine.title, allVariables) ?? input.routine.title;
836
+ const description = interpolateRoutineTemplate(input.routine.description, allVariables);
837
+ const triggerPayload = mergeRoutineRunPayload(input.payload, { ...automaticVariables, ...resolvedVariables });
838
+ const managedRoutineBinding = await getManagedRoutineBinding(input.routine);
839
+ const managedIssueTemplate = readManagedRoutineIssueTemplate(managedRoutineBinding?.defaultsJson);
840
+ const issueOriginKind = managedIssueTemplate?.surfaceVisibility === "plugin_operation" && managedRoutineBinding
841
+ ? pluginOperationIssueOriginKind(managedRoutineBinding.pluginKey)
842
+ : "routine_execution";
843
+ const issueOriginId = managedIssueTemplate?.originId ?? input.routine.id;
844
+ const issueBillingCode = managedIssueTemplate?.billingCode ?? null;
845
+ const dispatchFingerprint = createRoutineDispatchFingerprint({
846
+ payload: triggerPayload,
847
+ projectId,
848
+ assigneeAgentId,
849
+ executionWorkspaceId: input.executionWorkspaceId ?? null,
850
+ executionWorkspacePreference: input.executionWorkspacePreference ?? null,
851
+ executionWorkspaceSettings: input.executionWorkspaceSettings ?? null,
852
+ title,
853
+ description,
854
+ });
855
+ const run = await db.transaction(async (tx) => {
856
+ const txDb = tx;
857
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${input.routine.id} and ${routines.companyId} = ${input.routine.companyId} for update`);
858
+ if (input.idempotencyKey) {
859
+ const existing = await txDb
860
+ .select()
861
+ .from(routineRuns)
862
+ .where(and(eq(routineRuns.companyId, input.routine.companyId), eq(routineRuns.routineId, input.routine.id), eq(routineRuns.source, input.source), eq(routineRuns.idempotencyKey, input.idempotencyKey), input.trigger ? eq(routineRuns.triggerId, input.trigger.id) : isNull(routineRuns.triggerId)))
863
+ .orderBy(desc(routineRuns.createdAt))
864
+ .limit(1)
865
+ .then((rows) => rows[0] ?? null);
866
+ if (existing)
867
+ return existing;
868
+ }
869
+ const triggeredAt = new Date();
870
+ const manualRunnerUserId = input.source === "manual" ? input.actor?.userId ?? null : null;
871
+ const [createdRun] = await txDb
872
+ .insert(routineRuns)
873
+ .values({
874
+ companyId: input.routine.companyId,
875
+ routineId: input.routine.id,
876
+ triggerId: input.trigger?.id ?? null,
877
+ source: input.source,
878
+ status: "received",
879
+ triggeredAt,
880
+ idempotencyKey: input.idempotencyKey ?? null,
881
+ triggerPayload,
882
+ dispatchFingerprint,
883
+ })
884
+ .returning();
885
+ const nextRunAt = input.trigger?.kind === "schedule" && input.trigger.cronExpression && input.trigger.timezone
886
+ ? nextCronTickInTimeZone(input.trigger.cronExpression, input.trigger.timezone, triggeredAt)
887
+ : undefined;
888
+ let createdIssue = null;
889
+ try {
890
+ const activeIssue = await findLiveExecutionIssue(input.routine, txDb, dispatchFingerprint, {
891
+ kind: issueOriginKind,
892
+ id: issueOriginId,
893
+ });
894
+ if (activeIssue && input.routine.concurrencyPolicy !== "always_enqueue") {
895
+ const status = input.routine.concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";
896
+ if (manualRunnerUserId) {
897
+ await touchIssueForUserInbox(txDb, {
898
+ companyId: input.routine.companyId,
899
+ issueId: activeIssue.id,
900
+ userId: manualRunnerUserId,
901
+ touchedAt: triggeredAt,
902
+ });
903
+ }
904
+ const updated = await finalizeRun(createdRun.id, {
905
+ status,
906
+ linkedIssueId: activeIssue.id,
907
+ coalescedIntoRunId: activeIssue.originRunId,
908
+ completedAt: triggeredAt,
909
+ }, txDb);
910
+ await updateRoutineTouchedState({
911
+ routineId: input.routine.id,
912
+ triggerId: input.trigger?.id ?? null,
913
+ triggeredAt,
914
+ status,
915
+ issueId: activeIssue.id,
916
+ nextRunAt,
917
+ }, txDb);
918
+ return updated ?? createdRun;
919
+ }
920
+ try {
921
+ createdIssue = await issueSvc.create(input.routine.companyId, {
922
+ projectId,
923
+ goalId: input.routine.goalId,
924
+ parentId: input.routine.parentIssueId,
925
+ title,
926
+ description,
927
+ status: "todo",
928
+ priority: input.routine.priority,
929
+ assigneeAgentId,
930
+ createdByAgentId: input.source === "manual" ? input.actor?.agentId ?? null : null,
931
+ createdByUserId: manualRunnerUserId,
932
+ originKind: issueOriginKind,
933
+ originId: issueOriginId,
934
+ originRunId: createdRun.id,
935
+ originFingerprint: dispatchFingerprint,
936
+ billingCode: issueBillingCode,
937
+ executionWorkspaceId: input.executionWorkspaceId ?? null,
938
+ executionWorkspacePreference: input.executionWorkspacePreference ?? null,
939
+ executionWorkspaceSettings: input.executionWorkspaceSettings ?? null,
940
+ });
941
+ }
942
+ catch (error) {
943
+ const isOpenExecutionConflict = !!error &&
944
+ typeof error === "object" &&
945
+ "code" in error &&
946
+ error.code === "23505" &&
947
+ "constraint" in error &&
948
+ error.constraint === "issues_open_routine_execution_uq";
949
+ if (!isOpenExecutionConflict || input.routine.concurrencyPolicy === "always_enqueue") {
950
+ throw error;
951
+ }
952
+ const existingIssue = await findLiveExecutionIssue(input.routine, txDb, dispatchFingerprint, {
953
+ kind: issueOriginKind,
954
+ id: issueOriginId,
955
+ });
956
+ if (!existingIssue)
957
+ throw error;
958
+ const status = input.routine.concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";
959
+ if (manualRunnerUserId) {
960
+ await touchIssueForUserInbox(txDb, {
961
+ companyId: input.routine.companyId,
962
+ issueId: existingIssue.id,
963
+ userId: manualRunnerUserId,
964
+ touchedAt: triggeredAt,
965
+ });
966
+ }
967
+ const updated = await finalizeRun(createdRun.id, {
968
+ status,
969
+ linkedIssueId: existingIssue.id,
970
+ coalescedIntoRunId: existingIssue.originRunId,
971
+ completedAt: triggeredAt,
972
+ }, txDb);
973
+ await updateRoutineTouchedState({
974
+ routineId: input.routine.id,
975
+ triggerId: input.trigger?.id ?? null,
976
+ triggeredAt,
977
+ status,
978
+ issueId: existingIssue.id,
979
+ nextRunAt,
980
+ }, txDb);
981
+ return updated ?? createdRun;
982
+ }
983
+ // Keep the dispatch lock until the issue is linked to a queued heartbeat run.
984
+ await queueIssueAssignmentWakeup({
985
+ heartbeat,
986
+ issue: createdIssue,
987
+ reason: "issue_assigned",
988
+ mutation: "create",
989
+ contextSource: "routine.dispatch",
990
+ requestedByActorType: input.source === "schedule" ? "system" : undefined,
991
+ rethrowOnError: true,
992
+ });
993
+ const updated = await finalizeRun(createdRun.id, {
994
+ status: "issue_created",
995
+ linkedIssueId: createdIssue.id,
996
+ }, txDb);
997
+ await updateRoutineTouchedState({
998
+ routineId: input.routine.id,
999
+ triggerId: input.trigger?.id ?? null,
1000
+ triggeredAt,
1001
+ status: "issue_created",
1002
+ issueId: createdIssue.id,
1003
+ nextRunAt,
1004
+ }, txDb);
1005
+ return updated ?? createdRun;
1006
+ }
1007
+ catch (error) {
1008
+ if (createdIssue) {
1009
+ await txDb.delete(issues).where(eq(issues.id, createdIssue.id));
1010
+ }
1011
+ const failureReason = error instanceof Error ? error.message : String(error);
1012
+ const failed = await finalizeRun(createdRun.id, {
1013
+ status: "failed",
1014
+ failureReason,
1015
+ completedAt: new Date(),
1016
+ }, txDb);
1017
+ await updateRoutineTouchedState({
1018
+ routineId: input.routine.id,
1019
+ triggerId: input.trigger?.id ?? null,
1020
+ triggeredAt,
1021
+ status: "failed",
1022
+ nextRunAt,
1023
+ }, txDb);
1024
+ return failed ?? createdRun;
1025
+ }
1026
+ });
1027
+ if (input.source === "schedule" || input.source === "webhook") {
1028
+ const actorId = input.source === "schedule" ? "routine-scheduler" : "routine-webhook";
1029
+ try {
1030
+ await logActivity(db, {
1031
+ companyId: input.routine.companyId,
1032
+ actorType: "system",
1033
+ actorId,
1034
+ action: "routine.run_triggered",
1035
+ entityType: "routine_run",
1036
+ entityId: run.id,
1037
+ details: {
1038
+ routineId: input.routine.id,
1039
+ triggerId: input.trigger?.id ?? null,
1040
+ source: run.source,
1041
+ status: run.status,
1042
+ },
1043
+ });
1044
+ }
1045
+ catch (err) {
1046
+ logger.warn({ err, routineId: input.routine.id, runId: run.id }, "failed to log automated routine run");
1047
+ }
1048
+ }
1049
+ const telemetryClient = getTelemetryClient();
1050
+ if (telemetryClient) {
1051
+ trackRoutineRun(telemetryClient, {
1052
+ source: run.source,
1053
+ status: run.status,
1054
+ });
1055
+ }
1056
+ return run;
1057
+ }
1058
+ return {
1059
+ get: getRoutineById,
1060
+ getTrigger: getTriggerById,
1061
+ list: async (companyId, filters) => {
1062
+ const conditions = [eq(routines.companyId, companyId)];
1063
+ if (filters?.projectId)
1064
+ conditions.push(eq(routines.projectId, filters.projectId));
1065
+ const rows = await db
1066
+ .select()
1067
+ .from(routines)
1068
+ .where(and(...conditions))
1069
+ .orderBy(desc(routines.updatedAt), asc(routines.title));
1070
+ const routineIds = rows.map((row) => row.id);
1071
+ const [triggersByRoutine, latestRunByRoutine, activeIssueByRoutine, managedByRoutine] = await Promise.all([
1072
+ listTriggersForRoutineIds(companyId, routineIds),
1073
+ listLatestRunByRoutineIds(companyId, routineIds),
1074
+ listLiveIssueByRoutineIds(companyId, routineIds),
1075
+ listManagedRoutineMetadata(routineIds),
1076
+ ]);
1077
+ return rows.map((row) => ({
1078
+ ...row,
1079
+ managedByPlugin: managedByRoutine.get(row.id) ?? null,
1080
+ triggers: (triggersByRoutine.get(row.id) ?? []).map((trigger) => ({
1081
+ id: trigger.id,
1082
+ kind: trigger.kind,
1083
+ label: trigger.label,
1084
+ enabled: trigger.enabled,
1085
+ cronExpression: trigger.cronExpression,
1086
+ timezone: trigger.timezone,
1087
+ nextRunAt: trigger.nextRunAt,
1088
+ lastFiredAt: trigger.lastFiredAt,
1089
+ lastResult: trigger.lastResult,
1090
+ })),
1091
+ lastRun: latestRunByRoutine.get(row.id) ?? null,
1092
+ activeIssue: activeIssueByRoutine.get(row.id) ?? null,
1093
+ }));
1094
+ },
1095
+ getDetail: async (id) => {
1096
+ const row = await getRoutineById(id);
1097
+ if (!row)
1098
+ return null;
1099
+ const [project, assignee, parentIssue, triggers, recentRuns, activeIssue, managedByRoutine] = await Promise.all([
1100
+ row.projectId
1101
+ ? db.select().from(projects).where(eq(projects.id, row.projectId)).then((rows) => rows[0] ?? null)
1102
+ : null,
1103
+ row.assigneeAgentId
1104
+ ? db.select().from(agents).where(eq(agents.id, row.assigneeAgentId)).then((rows) => rows[0] ?? null)
1105
+ : null,
1106
+ row.parentIssueId ? issueSvc.getById(row.parentIssueId) : null,
1107
+ db.select().from(routineTriggers).where(eq(routineTriggers.routineId, row.id)).orderBy(asc(routineTriggers.createdAt)),
1108
+ db
1109
+ .select({
1110
+ id: routineRuns.id,
1111
+ companyId: routineRuns.companyId,
1112
+ routineId: routineRuns.routineId,
1113
+ triggerId: routineRuns.triggerId,
1114
+ source: routineRuns.source,
1115
+ status: routineRuns.status,
1116
+ triggeredAt: routineRuns.triggeredAt,
1117
+ idempotencyKey: routineRuns.idempotencyKey,
1118
+ triggerPayload: routineRuns.triggerPayload,
1119
+ dispatchFingerprint: routineRuns.dispatchFingerprint,
1120
+ linkedIssueId: routineRuns.linkedIssueId,
1121
+ coalescedIntoRunId: routineRuns.coalescedIntoRunId,
1122
+ failureReason: routineRuns.failureReason,
1123
+ completedAt: routineRuns.completedAt,
1124
+ createdAt: routineRuns.createdAt,
1125
+ updatedAt: routineRuns.updatedAt,
1126
+ triggerKind: routineTriggers.kind,
1127
+ triggerLabel: routineTriggers.label,
1128
+ issueIdentifier: issues.identifier,
1129
+ issueTitle: issues.title,
1130
+ issueStatus: issues.status,
1131
+ issuePriority: issues.priority,
1132
+ issueUpdatedAt: issues.updatedAt,
1133
+ })
1134
+ .from(routineRuns)
1135
+ .leftJoin(routineTriggers, eq(routineRuns.triggerId, routineTriggers.id))
1136
+ .leftJoin(issues, eq(routineRuns.linkedIssueId, issues.id))
1137
+ .where(eq(routineRuns.routineId, row.id))
1138
+ .orderBy(desc(routineRuns.createdAt))
1139
+ .limit(25)
1140
+ .then((runs) => runs.map((run) => ({
1141
+ id: run.id,
1142
+ companyId: run.companyId,
1143
+ routineId: run.routineId,
1144
+ triggerId: run.triggerId,
1145
+ source: run.source,
1146
+ status: run.status,
1147
+ triggeredAt: run.triggeredAt,
1148
+ idempotencyKey: run.idempotencyKey,
1149
+ triggerPayload: run.triggerPayload,
1150
+ dispatchFingerprint: run.dispatchFingerprint,
1151
+ linkedIssueId: run.linkedIssueId,
1152
+ coalescedIntoRunId: run.coalescedIntoRunId,
1153
+ failureReason: run.failureReason,
1154
+ completedAt: run.completedAt,
1155
+ createdAt: run.createdAt,
1156
+ updatedAt: run.updatedAt,
1157
+ linkedIssue: run.linkedIssueId
1158
+ ? {
1159
+ id: run.linkedIssueId,
1160
+ identifier: run.issueIdentifier,
1161
+ title: run.issueTitle ?? "Routine execution",
1162
+ status: run.issueStatus ?? "todo",
1163
+ priority: run.issuePriority ?? "medium",
1164
+ updatedAt: run.issueUpdatedAt ?? run.updatedAt,
1165
+ }
1166
+ : null,
1167
+ trigger: run.triggerId
1168
+ ? {
1169
+ id: run.triggerId,
1170
+ kind: run.triggerKind,
1171
+ label: run.triggerLabel,
1172
+ }
1173
+ : null,
1174
+ }))),
1175
+ findLiveExecutionIssue(row),
1176
+ listManagedRoutineMetadata([row.id]),
1177
+ ]);
1178
+ return {
1179
+ ...row,
1180
+ managedByPlugin: managedByRoutine.get(row.id) ?? null,
1181
+ project,
1182
+ assignee,
1183
+ parentIssue,
1184
+ triggers: triggers,
1185
+ recentRuns,
1186
+ activeIssue,
1187
+ };
1188
+ },
1189
+ create: async (companyId, input, actor) => {
1190
+ await assertProject(companyId, input.projectId ?? null);
1191
+ await assertAssignableAgent(companyId, input.assigneeAgentId ?? null);
1192
+ if (input.goalId)
1193
+ await assertGoal(companyId, input.goalId);
1194
+ if (input.parentIssueId)
1195
+ await assertParentIssue(companyId, input.parentIssueId);
1196
+ const variables = syncRoutineVariablesWithTemplate([input.title, input.description], sanitizeRoutineVariableInputs(input.variables));
1197
+ assertRoutineVariableDefinitions(variables);
1198
+ const status = normalizeDraftRoutineStatus(input.status, input.assigneeAgentId);
1199
+ return db.transaction(async (tx) => {
1200
+ const txDb = tx;
1201
+ const [created] = await txDb
1202
+ .insert(routines)
1203
+ .values({
1204
+ companyId,
1205
+ projectId: input.projectId ?? null,
1206
+ goalId: input.goalId ?? null,
1207
+ parentIssueId: input.parentIssueId ?? null,
1208
+ title: input.title,
1209
+ description: input.description ?? null,
1210
+ assigneeAgentId: input.assigneeAgentId ?? null,
1211
+ priority: input.priority,
1212
+ status,
1213
+ concurrencyPolicy: input.concurrencyPolicy,
1214
+ catchUpPolicy: input.catchUpPolicy,
1215
+ variables,
1216
+ createdByAgentId: actor.agentId ?? null,
1217
+ createdByUserId: actor.userId ?? null,
1218
+ updatedByAgentId: actor.agentId ?? null,
1219
+ updatedByUserId: actor.userId ?? null,
1220
+ })
1221
+ .returning();
1222
+ const { routine } = await appendRoutineRevision(txDb, created, actor, {
1223
+ changeSummary: "Created routine",
1224
+ });
1225
+ return routine;
1226
+ });
1227
+ },
1228
+ update: async (id, patch, actor) => {
1229
+ const existing = await getRoutineById(id);
1230
+ if (!existing)
1231
+ return null;
1232
+ const nextProjectId = patch.projectId === undefined ? existing.projectId : patch.projectId;
1233
+ const nextAssigneeAgentId = patch.assigneeAgentId === undefined ? existing.assigneeAgentId : patch.assigneeAgentId;
1234
+ const nextTitle = patch.title ?? existing.title;
1235
+ const nextDescription = patch.description === undefined ? existing.description : patch.description;
1236
+ const requestedStatus = patch.status ?? existing.status;
1237
+ if (patch.status === "active") {
1238
+ assertRoutineCanEnable(patch.status, nextAssigneeAgentId);
1239
+ }
1240
+ const nextStatus = patch.assigneeAgentId === undefined
1241
+ ? requestedStatus
1242
+ : normalizeDraftRoutineStatus(requestedStatus, nextAssigneeAgentId);
1243
+ const nextVariables = syncRoutineVariablesWithTemplate([nextTitle, nextDescription], patch.variables === undefined ? existing.variables : sanitizeRoutineVariableInputs(patch.variables));
1244
+ if (patch.projectId !== undefined)
1245
+ await assertProject(existing.companyId, nextProjectId);
1246
+ if (patch.assigneeAgentId !== undefined)
1247
+ await assertAssignableAgent(existing.companyId, nextAssigneeAgentId);
1248
+ if (patch.goalId)
1249
+ await assertGoal(existing.companyId, patch.goalId);
1250
+ if (patch.parentIssueId)
1251
+ await assertParentIssue(existing.companyId, patch.parentIssueId);
1252
+ assertRoutineVariableDefinitions(nextVariables);
1253
+ const enabledScheduleTriggers = await db
1254
+ .select({ id: routineTriggers.id })
1255
+ .from(routineTriggers)
1256
+ .where(and(eq(routineTriggers.routineId, existing.id), eq(routineTriggers.kind, "schedule"), eq(routineTriggers.enabled, true)))
1257
+ .limit(1)
1258
+ .then((rows) => rows.length > 0);
1259
+ if (enabledScheduleTriggers) {
1260
+ assertScheduleCompatibleVariables(nextVariables);
1261
+ }
1262
+ return db.transaction(async (tx) => {
1263
+ const txDb = tx;
1264
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${id} for update`);
1265
+ const locked = await txDb
1266
+ .select()
1267
+ .from(routines)
1268
+ .where(eq(routines.id, id))
1269
+ .then((rows) => rows[0] ?? null);
1270
+ if (!locked)
1271
+ return null;
1272
+ if (patch.baseRevisionId && patch.baseRevisionId !== locked.latestRevisionId) {
1273
+ throw conflict("Routine was updated by someone else", {
1274
+ currentRevisionId: locked.latestRevisionId,
1275
+ });
1276
+ }
1277
+ const candidate = {
1278
+ ...locked,
1279
+ projectId: nextProjectId,
1280
+ goalId: patch.goalId === undefined ? locked.goalId : patch.goalId,
1281
+ parentIssueId: patch.parentIssueId === undefined ? locked.parentIssueId : patch.parentIssueId,
1282
+ title: nextTitle,
1283
+ description: nextDescription,
1284
+ assigneeAgentId: nextAssigneeAgentId,
1285
+ priority: patch.priority ?? locked.priority,
1286
+ status: nextStatus,
1287
+ concurrencyPolicy: patch.concurrencyPolicy ?? locked.concurrencyPolicy,
1288
+ catchUpPolicy: patch.catchUpPolicy ?? locked.catchUpPolicy,
1289
+ variables: nextVariables,
1290
+ updatedByAgentId: actor.agentId ?? null,
1291
+ updatedByUserId: actor.userId ?? null,
1292
+ };
1293
+ if (locked.latestRevisionId && routineCurrentFieldsMatch(locked, candidate)) {
1294
+ return locked;
1295
+ }
1296
+ const nextSnapshot = await buildRoutineRevisionSnapshot(txDb, candidate);
1297
+ if (locked.latestRevisionId) {
1298
+ const latestRevision = await txDb
1299
+ .select({ snapshot: routineRevisions.snapshot })
1300
+ .from(routineRevisions)
1301
+ .where(and(eq(routineRevisions.companyId, locked.companyId), eq(routineRevisions.routineId, locked.id), eq(routineRevisions.id, locked.latestRevisionId)))
1302
+ .then((rows) => rows[0] ?? null);
1303
+ if (latestRevision && snapshotsMatch(nextSnapshot, latestRevision.snapshot)) {
1304
+ return locked;
1305
+ }
1306
+ }
1307
+ const [updated] = await txDb
1308
+ .update(routines)
1309
+ .set({
1310
+ projectId: candidate.projectId,
1311
+ goalId: candidate.goalId,
1312
+ parentIssueId: candidate.parentIssueId,
1313
+ title: candidate.title,
1314
+ description: candidate.description,
1315
+ assigneeAgentId: candidate.assigneeAgentId,
1316
+ priority: candidate.priority,
1317
+ status: candidate.status,
1318
+ concurrencyPolicy: candidate.concurrencyPolicy,
1319
+ catchUpPolicy: candidate.catchUpPolicy,
1320
+ variables: candidate.variables,
1321
+ updatedByAgentId: actor.agentId ?? null,
1322
+ updatedByUserId: actor.userId ?? null,
1323
+ updatedAt: new Date(),
1324
+ })
1325
+ .where(eq(routines.id, id))
1326
+ .returning();
1327
+ if (!updated)
1328
+ return null;
1329
+ const { routine } = await appendRoutineRevision(txDb, updated, actor, {
1330
+ changeSummary: "Updated routine",
1331
+ });
1332
+ return routine;
1333
+ });
1334
+ },
1335
+ createTrigger: async (routineId, input, actor) => {
1336
+ const routine = await getRoutineById(routineId);
1337
+ if (!routine)
1338
+ throw notFound("Routine not found");
1339
+ let secretMaterial = null;
1340
+ let secretId = null;
1341
+ let publicId = null;
1342
+ let nextRunAt = null;
1343
+ if (input.kind === "schedule") {
1344
+ assertScheduleCompatibleVariables(routine.variables ?? []);
1345
+ const timeZone = input.timezone || "UTC";
1346
+ assertTimeZone(timeZone);
1347
+ const error = validateCron(input.cronExpression);
1348
+ if (error)
1349
+ throw unprocessable(error);
1350
+ nextRunAt = nextCronTickInTimeZone(input.cronExpression, timeZone, new Date());
1351
+ }
1352
+ if (input.kind === "webhook") {
1353
+ publicId = crypto.randomBytes(12).toString("hex");
1354
+ const created = await createWebhookSecret(routine.companyId, routine.id, actor);
1355
+ secretId = created.secret.id;
1356
+ secretMaterial = {
1357
+ webhookUrl: `${process.env.EVERMORE_API_URL}/api/routine-triggers/public/${publicId}/fire`,
1358
+ webhookSecret: created.secretValue,
1359
+ };
1360
+ }
1361
+ const { trigger, revision } = await db.transaction(async (tx) => {
1362
+ const txDb = tx;
1363
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${routine.id} for update`);
1364
+ const [createdTrigger] = await txDb
1365
+ .insert(routineTriggers)
1366
+ .values({
1367
+ companyId: routine.companyId,
1368
+ routineId: routine.id,
1369
+ kind: input.kind,
1370
+ label: input.label ?? null,
1371
+ enabled: input.enabled ?? true,
1372
+ cronExpression: input.kind === "schedule" ? input.cronExpression : null,
1373
+ timezone: input.kind === "schedule" ? (input.timezone || "UTC") : null,
1374
+ nextRunAt,
1375
+ publicId,
1376
+ secretId,
1377
+ signingMode: input.kind === "webhook" ? input.signingMode : null,
1378
+ replayWindowSec: input.kind === "webhook" ? input.replayWindowSec : null,
1379
+ lastRotatedAt: input.kind === "webhook" ? new Date() : null,
1380
+ createdByAgentId: actor.agentId ?? null,
1381
+ createdByUserId: actor.userId ?? null,
1382
+ updatedByAgentId: actor.agentId ?? null,
1383
+ updatedByUserId: actor.userId ?? null,
1384
+ })
1385
+ .returning();
1386
+ const latestRoutine = await txDb.select().from(routines).where(eq(routines.id, routine.id)).then((rows) => rows[0] ?? routine);
1387
+ const appended = await appendRoutineRevision(txDb, latestRoutine, actor, {
1388
+ changeSummary: `Created ${input.kind} trigger`,
1389
+ });
1390
+ return { trigger: createdTrigger, revision: appended.revision };
1391
+ });
1392
+ return {
1393
+ trigger: trigger,
1394
+ secretMaterial,
1395
+ revision,
1396
+ };
1397
+ },
1398
+ updateTrigger: async (id, patch, actor) => {
1399
+ const existing = await getTriggerById(id);
1400
+ if (!existing)
1401
+ return null;
1402
+ let nextRunAt = existing.nextRunAt;
1403
+ let cronExpression = existing.cronExpression;
1404
+ let timezone = existing.timezone;
1405
+ if (existing.kind === "schedule") {
1406
+ const routine = await getRoutineById(existing.routineId);
1407
+ if (!routine)
1408
+ throw notFound("Routine not found");
1409
+ if (patch.cronExpression !== undefined) {
1410
+ if (patch.cronExpression == null)
1411
+ throw unprocessable("Scheduled triggers require cronExpression");
1412
+ const error = validateCron(patch.cronExpression);
1413
+ if (error)
1414
+ throw unprocessable(error);
1415
+ cronExpression = patch.cronExpression;
1416
+ }
1417
+ if (patch.timezone !== undefined) {
1418
+ if (patch.timezone == null)
1419
+ throw unprocessable("Scheduled triggers require timezone");
1420
+ assertTimeZone(patch.timezone);
1421
+ timezone = patch.timezone;
1422
+ }
1423
+ if (cronExpression && timezone) {
1424
+ nextRunAt = nextCronTickInTimeZone(cronExpression, timezone, new Date());
1425
+ }
1426
+ if ((patch.enabled ?? existing.enabled) === true) {
1427
+ assertScheduleCompatibleVariables(routine.variables ?? []);
1428
+ }
1429
+ }
1430
+ return db.transaction(async (tx) => {
1431
+ const txDb = tx;
1432
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${existing.routineId} for update`);
1433
+ const [updated] = await txDb
1434
+ .update(routineTriggers)
1435
+ .set({
1436
+ label: patch.label === undefined ? existing.label : patch.label,
1437
+ enabled: patch.enabled ?? existing.enabled,
1438
+ cronExpression,
1439
+ timezone,
1440
+ nextRunAt,
1441
+ signingMode: patch.signingMode === undefined ? existing.signingMode : patch.signingMode,
1442
+ replayWindowSec: patch.replayWindowSec === undefined ? existing.replayWindowSec : patch.replayWindowSec,
1443
+ updatedByAgentId: actor.agentId ?? null,
1444
+ updatedByUserId: actor.userId ?? null,
1445
+ updatedAt: new Date(),
1446
+ })
1447
+ .where(eq(routineTriggers.id, id))
1448
+ .returning();
1449
+ if (!updated)
1450
+ return null;
1451
+ const routine = await txDb
1452
+ .select()
1453
+ .from(routines)
1454
+ .where(eq(routines.id, existing.routineId))
1455
+ .then((rows) => rows[0] ?? null);
1456
+ if (!routine)
1457
+ throw notFound("Routine not found");
1458
+ const appended = await appendRoutineRevision(txDb, routine, actor, {
1459
+ changeSummary: `Updated ${existing.kind} trigger`,
1460
+ });
1461
+ return { trigger: updated, revision: appended.revision };
1462
+ });
1463
+ },
1464
+ deleteTrigger: async (id, actor = {}) => {
1465
+ const existing = await getTriggerById(id);
1466
+ if (!existing)
1467
+ return { deleted: false, revision: null };
1468
+ return db.transaction(async (tx) => {
1469
+ const txDb = tx;
1470
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${existing.routineId} for update`);
1471
+ await txDb.delete(routineTriggers).where(eq(routineTriggers.id, id));
1472
+ const routine = await txDb
1473
+ .select()
1474
+ .from(routines)
1475
+ .where(eq(routines.id, existing.routineId))
1476
+ .then((rows) => rows[0] ?? null);
1477
+ if (!routine)
1478
+ throw notFound("Routine not found");
1479
+ const appended = await appendRoutineRevision(txDb, routine, actor, {
1480
+ changeSummary: `Deleted ${existing.kind} trigger`,
1481
+ });
1482
+ return { deleted: true, revision: appended.revision };
1483
+ });
1484
+ },
1485
+ rotateTriggerSecret: async (id, actor) => {
1486
+ const existing = await getTriggerById(id);
1487
+ if (!existing)
1488
+ throw notFound("Routine trigger not found");
1489
+ if (existing.kind !== "webhook" || !existing.publicId || !existing.secretId) {
1490
+ throw unprocessable("Only webhook triggers can rotate secrets");
1491
+ }
1492
+ const secretValue = crypto.randomBytes(24).toString("hex");
1493
+ await secretsSvc.rotate(existing.secretId, { value: secretValue }, actor);
1494
+ const { trigger, revision } = await db.transaction(async (tx) => {
1495
+ const txDb = tx;
1496
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${existing.routineId} for update`);
1497
+ const [updated] = await txDb
1498
+ .update(routineTriggers)
1499
+ .set({
1500
+ lastRotatedAt: new Date(),
1501
+ updatedByAgentId: actor.agentId ?? null,
1502
+ updatedByUserId: actor.userId ?? null,
1503
+ updatedAt: new Date(),
1504
+ })
1505
+ .where(eq(routineTriggers.id, id))
1506
+ .returning();
1507
+ const routine = await txDb
1508
+ .select()
1509
+ .from(routines)
1510
+ .where(eq(routines.id, existing.routineId))
1511
+ .then((rows) => rows[0] ?? null);
1512
+ if (!routine)
1513
+ throw notFound("Routine not found");
1514
+ const appended = await appendRoutineRevision(txDb, routine, actor, {
1515
+ changeSummary: "Rotated webhook trigger secret",
1516
+ });
1517
+ return { trigger: updated, revision: appended.revision };
1518
+ });
1519
+ return {
1520
+ trigger: trigger,
1521
+ secretMaterial: {
1522
+ webhookUrl: `${process.env.EVERMORE_API_URL}/api/routine-triggers/public/${existing.publicId}/fire`,
1523
+ webhookSecret: secretValue,
1524
+ },
1525
+ revision,
1526
+ };
1527
+ },
1528
+ listRevisions: async (routineId) => {
1529
+ const routine = await getRoutineById(routineId);
1530
+ if (!routine)
1531
+ throw notFound("Routine not found");
1532
+ const rows = await db
1533
+ .select()
1534
+ .from(routineRevisions)
1535
+ .where(and(eq(routineRevisions.companyId, routine.companyId), eq(routineRevisions.routineId, routine.id)))
1536
+ .orderBy(desc(routineRevisions.revisionNumber), desc(routineRevisions.createdAt))
1537
+ .limit(MAX_ROUTINE_REVISIONS);
1538
+ return rows.map(mapRoutineRevision);
1539
+ },
1540
+ restoreRevision: async (routineId, revisionId, actor) => {
1541
+ const existingRoutine = await getRoutineById(routineId);
1542
+ if (!existingRoutine)
1543
+ throw notFound("Routine not found");
1544
+ const targetRevision = await db
1545
+ .select()
1546
+ .from(routineRevisions)
1547
+ .where(and(eq(routineRevisions.companyId, existingRoutine.companyId), eq(routineRevisions.routineId, existingRoutine.id), eq(routineRevisions.id, revisionId)))
1548
+ .then((rows) => rows[0] ?? null);
1549
+ if (!targetRevision)
1550
+ throw notFound("Routine revision not found");
1551
+ const snapshot = targetRevision.snapshot;
1552
+ const routineSnapshot = snapshot.routine;
1553
+ await assertRestorableAssignee(existingRoutine.companyId, routineSnapshot.assigneeAgentId, actor);
1554
+ return db.transaction(async (tx) => {
1555
+ const txDb = tx;
1556
+ await tx.execute(sql `select id from ${routines} where ${routines.id} = ${existingRoutine.id} for update`);
1557
+ const locked = await txDb
1558
+ .select()
1559
+ .from(routines)
1560
+ .where(eq(routines.id, existingRoutine.id))
1561
+ .then((rows) => rows[0] ?? null);
1562
+ if (!locked)
1563
+ throw notFound("Routine not found");
1564
+ if (locked.latestRevisionId === targetRevision.id) {
1565
+ throw conflict("Selected revision is already the latest revision", {
1566
+ currentRevisionId: locked.latestRevisionId,
1567
+ });
1568
+ }
1569
+ const currentTriggers = await txDb
1570
+ .select({ id: routineTriggers.id })
1571
+ .from(routineTriggers)
1572
+ .where(and(eq(routineTriggers.companyId, locked.companyId), eq(routineTriggers.routineId, locked.id)));
1573
+ const currentTriggerIds = new Set(currentTriggers.map((trigger) => trigger.id));
1574
+ const missingWebhookTriggers = snapshot.triggers
1575
+ .filter((trigger) => trigger.kind === "webhook" && !currentTriggerIds.has(trigger.id));
1576
+ const recreatedWebhookSecrets = new Map();
1577
+ for (const trigger of missingWebhookTriggers) {
1578
+ const publicId = crypto.randomBytes(12).toString("hex");
1579
+ const created = await createWebhookSecret(locked.companyId, locked.id, actor, txDb);
1580
+ recreatedWebhookSecrets.set(trigger.id, {
1581
+ publicId,
1582
+ secretId: created.secret.id,
1583
+ secretMaterial: {
1584
+ triggerId: trigger.id,
1585
+ webhookUrl: `${process.env.EVERMORE_API_URL}/api/routine-triggers/public/${publicId}/fire`,
1586
+ webhookSecret: created.secretValue,
1587
+ },
1588
+ });
1589
+ }
1590
+ const now = new Date();
1591
+ const [restoredRoutine] = await txDb
1592
+ .update(routines)
1593
+ .set({
1594
+ projectId: routineSnapshot.projectId,
1595
+ goalId: routineSnapshot.goalId,
1596
+ parentIssueId: routineSnapshot.parentIssueId,
1597
+ title: routineSnapshot.title,
1598
+ description: routineSnapshot.description,
1599
+ assigneeAgentId: routineSnapshot.assigneeAgentId,
1600
+ priority: routineSnapshot.priority,
1601
+ status: routineSnapshot.status,
1602
+ concurrencyPolicy: routineSnapshot.concurrencyPolicy,
1603
+ catchUpPolicy: routineSnapshot.catchUpPolicy,
1604
+ variables: routineSnapshot.variables,
1605
+ updatedByAgentId: actor.agentId ?? null,
1606
+ updatedByUserId: actor.userId ?? null,
1607
+ updatedAt: now,
1608
+ })
1609
+ .where(eq(routines.id, locked.id))
1610
+ .returning();
1611
+ const snapshotTriggerIds = new Set(snapshot.triggers.map((trigger) => trigger.id));
1612
+ if (snapshotTriggerIds.size === 0) {
1613
+ await txDb
1614
+ .delete(routineTriggers)
1615
+ .where(and(eq(routineTriggers.companyId, locked.companyId), eq(routineTriggers.routineId, locked.id)));
1616
+ }
1617
+ else {
1618
+ await txDb
1619
+ .delete(routineTriggers)
1620
+ .where(and(eq(routineTriggers.companyId, locked.companyId), eq(routineTriggers.routineId, locked.id), not(inArray(routineTriggers.id, snapshot.triggers.map((trigger) => trigger.id)))));
1621
+ }
1622
+ for (const triggerSnapshot of snapshot.triggers) {
1623
+ const current = await txDb
1624
+ .select()
1625
+ .from(routineTriggers)
1626
+ .where(and(eq(routineTriggers.companyId, locked.companyId), eq(routineTriggers.id, triggerSnapshot.id)))
1627
+ .then((rows) => rows[0] ?? null);
1628
+ const webhookSecret = recreatedWebhookSecrets.get(triggerSnapshot.id);
1629
+ const restoredNextRunAt = triggerSnapshot.kind === "schedule" && triggerSnapshot.enabled
1630
+ && triggerSnapshot.cronExpression && triggerSnapshot.timezone
1631
+ ? nextCronTickInTimeZone(triggerSnapshot.cronExpression, triggerSnapshot.timezone, now)
1632
+ : null;
1633
+ const baseValues = {
1634
+ companyId: locked.companyId,
1635
+ routineId: locked.id,
1636
+ kind: triggerSnapshot.kind,
1637
+ label: triggerSnapshot.label,
1638
+ enabled: triggerSnapshot.enabled,
1639
+ cronExpression: triggerSnapshot.kind === "schedule" ? triggerSnapshot.cronExpression : null,
1640
+ timezone: triggerSnapshot.kind === "schedule" ? triggerSnapshot.timezone : null,
1641
+ publicId: triggerSnapshot.kind === "webhook" ? (current?.publicId ?? webhookSecret?.publicId ?? triggerSnapshot.publicId) : null,
1642
+ secretId: triggerSnapshot.kind === "webhook" ? (current?.secretId ?? webhookSecret?.secretId ?? null) : null,
1643
+ signingMode: triggerSnapshot.kind === "webhook" ? triggerSnapshot.signingMode : null,
1644
+ replayWindowSec: triggerSnapshot.kind === "webhook" ? triggerSnapshot.replayWindowSec : null,
1645
+ nextRunAt: restoredNextRunAt,
1646
+ updatedByAgentId: actor.agentId ?? null,
1647
+ updatedByUserId: actor.userId ?? null,
1648
+ updatedAt: now,
1649
+ };
1650
+ if (current) {
1651
+ await txDb.update(routineTriggers).set(baseValues).where(eq(routineTriggers.id, triggerSnapshot.id));
1652
+ }
1653
+ else {
1654
+ await txDb.insert(routineTriggers).values({
1655
+ id: triggerSnapshot.id,
1656
+ ...baseValues,
1657
+ createdByAgentId: actor.agentId ?? null,
1658
+ createdByUserId: actor.userId ?? null,
1659
+ createdAt: now,
1660
+ });
1661
+ }
1662
+ }
1663
+ const appended = await appendRoutineRevision(txDb, restoredRoutine ?? locked, actor, {
1664
+ changeSummary: `Restored from revision ${targetRevision.revisionNumber}`,
1665
+ restoredFromRevisionId: targetRevision.id,
1666
+ });
1667
+ return {
1668
+ routine: appended.routine,
1669
+ revision: appended.revision,
1670
+ restoredFromRevisionId: targetRevision.id,
1671
+ restoredFromRevisionNumber: targetRevision.revisionNumber,
1672
+ secretMaterials: [...recreatedWebhookSecrets.values()].map((entry) => entry.secretMaterial),
1673
+ };
1674
+ });
1675
+ },
1676
+ runRoutine: async (id, input, actor) => {
1677
+ const routine = await getRoutineById(id);
1678
+ if (!routine)
1679
+ throw notFound("Routine not found");
1680
+ if (routine.status === "archived")
1681
+ throw conflict("Routine is archived");
1682
+ await assertProject(routine.companyId, input.projectId ?? null);
1683
+ await assertAssignableAgent(routine.companyId, input.assigneeAgentId ?? null);
1684
+ const trigger = input.triggerId ? await getTriggerById(input.triggerId) : null;
1685
+ if (trigger && trigger.routineId !== routine.id)
1686
+ throw forbidden("Trigger does not belong to routine");
1687
+ if (trigger && !trigger.enabled)
1688
+ throw conflict("Routine trigger is not active");
1689
+ return dispatchRoutineRun({
1690
+ routine,
1691
+ trigger,
1692
+ source: input.source,
1693
+ payload: input.payload,
1694
+ variables: input.variables,
1695
+ projectId: input.projectId ?? null,
1696
+ assigneeAgentId: input.assigneeAgentId ?? null,
1697
+ idempotencyKey: input.idempotencyKey,
1698
+ executionWorkspaceId: input.executionWorkspaceId ?? null,
1699
+ executionWorkspacePreference: input.executionWorkspacePreference ?? null,
1700
+ executionWorkspaceSettings: input.executionWorkspaceSettings ?? null,
1701
+ actor,
1702
+ });
1703
+ },
1704
+ firePublicTrigger: async (publicId, input) => {
1705
+ const trigger = await db
1706
+ .select()
1707
+ .from(routineTriggers)
1708
+ .where(and(eq(routineTriggers.publicId, publicId), eq(routineTriggers.kind, "webhook")))
1709
+ .then((rows) => rows[0] ?? null);
1710
+ if (!trigger)
1711
+ throw notFound("Routine trigger not found");
1712
+ const routine = await getRoutineById(trigger.routineId);
1713
+ if (!routine)
1714
+ throw notFound("Routine not found");
1715
+ if (!trigger.enabled || routine.status !== "active")
1716
+ throw conflict("Routine trigger is not active");
1717
+ if (trigger.signingMode === "none") {
1718
+ // No authentication — the publicId in the URL acts as a shared secret.
1719
+ }
1720
+ else if (trigger.signingMode === "github_hmac") {
1721
+ const secretValue = await resolveTriggerSecret(trigger, routine.companyId);
1722
+ const rawBody = input.rawBody ?? Buffer.from(JSON.stringify(input.payload ?? {}));
1723
+ // Accept X-Hub-Signature-256 (GitHub/Sentry) or fall back to the
1724
+ // generic X-Evermore-Signature header so operators can use github_hmac
1725
+ // mode with either header convention.
1726
+ const providedSignature = (input.hubSignatureHeader ?? input.signatureHeader)?.trim() ?? "";
1727
+ if (!providedSignature)
1728
+ throw unauthorized();
1729
+ const expectedHmac = crypto
1730
+ .createHmac("sha256", secretValue)
1731
+ .update(rawBody)
1732
+ .digest("hex");
1733
+ const normalizedSignature = providedSignature.replace(/^sha256=/, "");
1734
+ const normalizedBuf = Buffer.from(normalizedSignature);
1735
+ const expectedBuf = Buffer.from(expectedHmac);
1736
+ const valid = normalizedBuf.length === expectedBuf.length &&
1737
+ crypto.timingSafeEqual(normalizedBuf, expectedBuf);
1738
+ if (!valid)
1739
+ throw unauthorized();
1740
+ }
1741
+ else if (trigger.signingMode === "bearer") {
1742
+ const secretValue = await resolveTriggerSecret(trigger, routine.companyId);
1743
+ const expected = `Bearer ${secretValue}`;
1744
+ const provided = input.authorizationHeader?.trim() ?? "";
1745
+ const expectedBuf = Buffer.from(expected);
1746
+ const providedBuf = Buffer.alloc(expectedBuf.length);
1747
+ providedBuf.write(provided.slice(0, expectedBuf.length));
1748
+ const valid = provided.length === expected.length &&
1749
+ crypto.timingSafeEqual(providedBuf, expectedBuf);
1750
+ if (!valid) {
1751
+ throw unauthorized();
1752
+ }
1753
+ }
1754
+ else {
1755
+ const secretValue = await resolveTriggerSecret(trigger, routine.companyId);
1756
+ const rawBody = input.rawBody ?? Buffer.from(JSON.stringify(input.payload ?? {}));
1757
+ const providedSignature = input.signatureHeader?.trim() ?? "";
1758
+ const providedTimestamp = input.timestampHeader?.trim() ?? "";
1759
+ if (!providedSignature || !providedTimestamp)
1760
+ throw unauthorized();
1761
+ const tsMillis = normalizeWebhookTimestampMs(providedTimestamp);
1762
+ if (tsMillis == null)
1763
+ throw unauthorized();
1764
+ const replayWindowSec = trigger.replayWindowSec ?? 300;
1765
+ if (Math.abs(Date.now() - tsMillis) > replayWindowSec * 1000) {
1766
+ throw unauthorized();
1767
+ }
1768
+ const expectedHmac = crypto
1769
+ .createHmac("sha256", secretValue)
1770
+ .update(`${providedTimestamp}.`)
1771
+ .update(rawBody)
1772
+ .digest("hex");
1773
+ const normalizedSignature = providedSignature.replace(/^sha256=/, "");
1774
+ const valid = normalizedSignature.length === expectedHmac.length &&
1775
+ crypto.timingSafeEqual(Buffer.from(normalizedSignature), Buffer.from(expectedHmac));
1776
+ if (!valid)
1777
+ throw unauthorized();
1778
+ }
1779
+ return dispatchRoutineRun({
1780
+ routine,
1781
+ trigger,
1782
+ source: "webhook",
1783
+ payload: input.payload,
1784
+ variables: isPlainRecord(input.payload) && isPlainRecord(input.payload.variables)
1785
+ ? input.payload.variables
1786
+ : null,
1787
+ idempotencyKey: input.idempotencyKey,
1788
+ });
1789
+ },
1790
+ listRuns: async (routineId, limit = 50) => {
1791
+ const cappedLimit = Math.max(1, Math.min(limit, 200));
1792
+ const rows = await db
1793
+ .select({
1794
+ id: routineRuns.id,
1795
+ companyId: routineRuns.companyId,
1796
+ routineId: routineRuns.routineId,
1797
+ triggerId: routineRuns.triggerId,
1798
+ source: routineRuns.source,
1799
+ status: routineRuns.status,
1800
+ triggeredAt: routineRuns.triggeredAt,
1801
+ idempotencyKey: routineRuns.idempotencyKey,
1802
+ triggerPayload: routineRuns.triggerPayload,
1803
+ dispatchFingerprint: routineRuns.dispatchFingerprint,
1804
+ linkedIssueId: routineRuns.linkedIssueId,
1805
+ coalescedIntoRunId: routineRuns.coalescedIntoRunId,
1806
+ failureReason: routineRuns.failureReason,
1807
+ completedAt: routineRuns.completedAt,
1808
+ createdAt: routineRuns.createdAt,
1809
+ updatedAt: routineRuns.updatedAt,
1810
+ triggerKind: routineTriggers.kind,
1811
+ triggerLabel: routineTriggers.label,
1812
+ issueIdentifier: issues.identifier,
1813
+ issueTitle: issues.title,
1814
+ issueStatus: issues.status,
1815
+ issuePriority: issues.priority,
1816
+ issueUpdatedAt: issues.updatedAt,
1817
+ })
1818
+ .from(routineRuns)
1819
+ .leftJoin(routineTriggers, eq(routineRuns.triggerId, routineTriggers.id))
1820
+ .leftJoin(issues, eq(routineRuns.linkedIssueId, issues.id))
1821
+ .where(eq(routineRuns.routineId, routineId))
1822
+ .orderBy(desc(routineRuns.createdAt))
1823
+ .limit(cappedLimit);
1824
+ return rows.map((row) => ({
1825
+ id: row.id,
1826
+ companyId: row.companyId,
1827
+ routineId: row.routineId,
1828
+ triggerId: row.triggerId,
1829
+ source: row.source,
1830
+ status: row.status,
1831
+ triggeredAt: row.triggeredAt,
1832
+ idempotencyKey: row.idempotencyKey,
1833
+ triggerPayload: row.triggerPayload,
1834
+ dispatchFingerprint: row.dispatchFingerprint,
1835
+ linkedIssueId: row.linkedIssueId,
1836
+ coalescedIntoRunId: row.coalescedIntoRunId,
1837
+ failureReason: row.failureReason,
1838
+ completedAt: row.completedAt,
1839
+ createdAt: row.createdAt,
1840
+ updatedAt: row.updatedAt,
1841
+ linkedIssue: row.linkedIssueId
1842
+ ? {
1843
+ id: row.linkedIssueId,
1844
+ identifier: row.issueIdentifier,
1845
+ title: row.issueTitle ?? "Routine execution",
1846
+ status: row.issueStatus ?? "todo",
1847
+ priority: row.issuePriority ?? "medium",
1848
+ updatedAt: row.issueUpdatedAt ?? row.updatedAt,
1849
+ }
1850
+ : null,
1851
+ trigger: row.triggerId
1852
+ ? {
1853
+ id: row.triggerId,
1854
+ kind: row.triggerKind,
1855
+ label: row.triggerLabel,
1856
+ }
1857
+ : null,
1858
+ }));
1859
+ },
1860
+ tickScheduledTriggers: async (now = new Date()) => {
1861
+ const due = await db
1862
+ .select({
1863
+ trigger: routineTriggers,
1864
+ routine: routines,
1865
+ })
1866
+ .from(routineTriggers)
1867
+ .innerJoin(routines, eq(routineTriggers.routineId, routines.id))
1868
+ .where(and(eq(routineTriggers.kind, "schedule"), eq(routineTriggers.enabled, true), eq(routines.status, "active"), isNotNull(routineTriggers.nextRunAt), lte(routineTriggers.nextRunAt, now)))
1869
+ .orderBy(asc(routineTriggers.nextRunAt), asc(routineTriggers.createdAt));
1870
+ let triggered = 0;
1871
+ for (const row of due) {
1872
+ if (!row.trigger.nextRunAt || !row.trigger.cronExpression || !row.trigger.timezone)
1873
+ continue;
1874
+ let runCount = 1;
1875
+ let claimedNextRunAt = nextCronTickInTimeZone(row.trigger.cronExpression, row.trigger.timezone, now);
1876
+ if (row.routine.catchUpPolicy === "enqueue_missed_with_cap") {
1877
+ let cursor = row.trigger.nextRunAt;
1878
+ runCount = 0;
1879
+ while (cursor && cursor <= now && runCount < MAX_CATCH_UP_RUNS) {
1880
+ runCount += 1;
1881
+ claimedNextRunAt = nextCronTickInTimeZone(row.trigger.cronExpression, row.trigger.timezone, cursor);
1882
+ cursor = claimedNextRunAt;
1883
+ }
1884
+ }
1885
+ const claimed = await db
1886
+ .update(routineTriggers)
1887
+ .set({
1888
+ nextRunAt: claimedNextRunAt,
1889
+ updatedAt: new Date(),
1890
+ })
1891
+ .where(and(eq(routineTriggers.id, row.trigger.id), eq(routineTriggers.enabled, true), eq(routineTriggers.nextRunAt, row.trigger.nextRunAt)))
1892
+ .returning({ id: routineTriggers.id })
1893
+ .then((rows) => rows[0] ?? null);
1894
+ if (!claimed)
1895
+ continue;
1896
+ for (let i = 0; i < runCount; i += 1) {
1897
+ await dispatchRoutineRun({
1898
+ routine: row.routine,
1899
+ trigger: row.trigger,
1900
+ source: "schedule",
1901
+ });
1902
+ triggered += 1;
1903
+ }
1904
+ }
1905
+ return { triggered };
1906
+ },
1907
+ syncRunStatusForIssue: async (issueId) => {
1908
+ const issue = await db
1909
+ .select({
1910
+ id: issues.id,
1911
+ status: issues.status,
1912
+ originKind: issues.originKind,
1913
+ originRunId: issues.originRunId,
1914
+ })
1915
+ .from(issues)
1916
+ .where(eq(issues.id, issueId))
1917
+ .then((rows) => rows[0] ?? null);
1918
+ if (!issue || issue.originKind !== "routine_execution" || !issue.originRunId)
1919
+ return null;
1920
+ if (issue.status === "done") {
1921
+ return finalizeRun(issue.originRunId, {
1922
+ status: "completed",
1923
+ completedAt: new Date(),
1924
+ });
1925
+ }
1926
+ if (issue.status === "blocked" || issue.status === "cancelled") {
1927
+ return finalizeRun(issue.originRunId, {
1928
+ status: "failed",
1929
+ failureReason: `Execution issue moved to ${issue.status}`,
1930
+ completedAt: new Date(),
1931
+ });
1932
+ }
1933
+ return null;
1934
+ },
1935
+ };
1936
+ }
1937
+ //# sourceMappingURL=routines.js.map