@desplega.ai/agent-swarm 1.20.0 → 1.51.2

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 (561) hide show
  1. package/README.md +271 -169
  2. package/openapi.json +5015 -0
  3. package/package.json +40 -7
  4. package/plugin/commands/close-issue.md +7 -3
  5. package/plugin/commands/create-pr.md +18 -12
  6. package/plugin/commands/implement-issue.md +7 -3
  7. package/plugin/commands/respond-github.md +8 -4
  8. package/plugin/commands/review-pr.md +44 -10
  9. package/plugin/commands/start-leader.md +1 -3
  10. package/plugin/commands/start-worker.md +1 -3
  11. package/plugin/commands/work-on-task.md +22 -3
  12. package/plugin/pi-skills/close-issue/SKILL.md +90 -0
  13. package/plugin/pi-skills/create-pr/SKILL.md +99 -0
  14. package/plugin/pi-skills/implement-issue/SKILL.md +135 -0
  15. package/plugin/pi-skills/investigate-sentry-issue/SKILL.md +138 -0
  16. package/plugin/pi-skills/respond-github/SKILL.md +98 -0
  17. package/plugin/pi-skills/review-offered-task/SKILL.md +45 -0
  18. package/plugin/pi-skills/review-pr/SKILL.md +261 -0
  19. package/plugin/pi-skills/start-leader/SKILL.md +121 -0
  20. package/plugin/pi-skills/start-worker/SKILL.md +60 -0
  21. package/plugin/pi-skills/swarm-chat/SKILL.md +82 -0
  22. package/plugin/pi-skills/todos/SKILL.md +66 -0
  23. package/plugin/pi-skills/work-on-task/SKILL.md +65 -0
  24. package/plugin/skills/artifacts/examples/approval-flow.ts +34 -0
  25. package/plugin/skills/artifacts/examples/hono-dashboard.ts +31 -0
  26. package/plugin/skills/artifacts/examples/multi-artifact.ts +20 -0
  27. package/plugin/skills/artifacts/examples/static-report.sh +17 -0
  28. package/plugin/skills/artifacts/skill.md +71 -0
  29. package/src/agentmail/app.ts +65 -0
  30. package/src/agentmail/handlers.ts +262 -0
  31. package/src/agentmail/index.ts +9 -0
  32. package/src/agentmail/templates.ts +111 -0
  33. package/src/agentmail/types.ts +51 -0
  34. package/src/artifact-sdk/browser-sdk.ts +30 -0
  35. package/src/artifact-sdk/index.ts +2 -0
  36. package/src/artifact-sdk/localtunnel.d.ts +20 -0
  37. package/src/artifact-sdk/port.ts +12 -0
  38. package/src/artifact-sdk/server.ts +156 -0
  39. package/src/artifact-sdk/tunnel.ts +19 -0
  40. package/src/be/chunking.ts +193 -0
  41. package/src/be/db-queries/oauth.ts +90 -0
  42. package/src/be/db-queries/tracker.ts +182 -0
  43. package/src/be/db.ts +3327 -784
  44. package/src/be/embedding.ts +80 -0
  45. package/src/be/migrations/001_initial.sql +409 -0
  46. package/src/be/migrations/002_one_time_schedules.sql +59 -0
  47. package/src/be/migrations/003_workflows.sql +51 -0
  48. package/src/be/migrations/004_workflow_source.sql +81 -0
  49. package/src/be/migrations/005_epic_next_steps.sql +2 -0
  50. package/src/be/migrations/006_vcs_provider.sql +94 -0
  51. package/src/be/migrations/007_task_dir.sql +2 -0
  52. package/src/be/migrations/008_workflow_redesign.sql +85 -0
  53. package/src/be/migrations/009_tracker_integration.sql +144 -0
  54. package/src/be/migrations/010_step_diagnostics.sql +1 -0
  55. package/src/be/migrations/011_step_next_port.sql +1 -0
  56. package/src/be/migrations/012_trigger_schema.sql +1 -0
  57. package/src/be/migrations/013_task_output_schema.sql +2 -0
  58. package/src/be/migrations/014_prompt_templates.sql +33 -0
  59. package/src/be/migrations/015_workflow_workspace.sql +3 -0
  60. package/src/be/migrations/016_active_session_runner_session.sql +4 -0
  61. package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
  62. package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
  63. package/src/be/migrations/runner.ts +188 -0
  64. package/src/be/seed.ts +62 -0
  65. package/src/cli.tsx +231 -299
  66. package/src/commands/artifact.ts +241 -0
  67. package/src/commands/onboard/compose-generator.ts +169 -0
  68. package/src/commands/onboard/env-generator.ts +79 -0
  69. package/src/commands/onboard/manifest.ts +37 -0
  70. package/src/commands/onboard/presets.ts +85 -0
  71. package/src/commands/onboard/service-names.ts +47 -0
  72. package/src/commands/onboard/steps/core-credentials.tsx +111 -0
  73. package/src/commands/onboard/steps/custom-templates.tsx +168 -0
  74. package/src/commands/onboard/steps/generate.tsx +154 -0
  75. package/src/commands/onboard/steps/harness-credentials.tsx +195 -0
  76. package/src/commands/onboard/steps/harness.tsx +21 -0
  77. package/src/commands/onboard/steps/health-check.tsx +171 -0
  78. package/src/commands/onboard/steps/integration-github.tsx +105 -0
  79. package/src/commands/onboard/steps/integration-gitlab.tsx +79 -0
  80. package/src/commands/onboard/steps/integration-menu.tsx +58 -0
  81. package/src/commands/onboard/steps/integration-sentry.tsx +79 -0
  82. package/src/commands/onboard/steps/integration-slack.tsx +165 -0
  83. package/src/commands/onboard/steps/post-connect.tsx +145 -0
  84. package/src/commands/onboard/steps/post-dashboard.tsx +34 -0
  85. package/src/commands/onboard/steps/post-task.tsx +103 -0
  86. package/src/commands/onboard/steps/prereq-check.tsx +178 -0
  87. package/src/commands/onboard/steps/review.tsx +82 -0
  88. package/src/commands/onboard/steps/start.tsx +97 -0
  89. package/src/commands/onboard/templates.ts +34 -0
  90. package/src/commands/onboard/types.ts +259 -0
  91. package/src/commands/onboard.tsx +425 -0
  92. package/src/commands/runner.ts +1540 -630
  93. package/src/commands/setup.tsx +23 -38
  94. package/src/commands/shared/client-config.ts +41 -0
  95. package/src/commands/templates.ts +172 -0
  96. package/src/github/app.ts +8 -0
  97. package/src/github/handlers.ts +384 -151
  98. package/src/github/index.ts +1 -0
  99. package/src/github/mentions-aliases.test.ts +73 -0
  100. package/src/github/mentions.test.ts +3 -3
  101. package/src/github/mentions.ts +32 -6
  102. package/src/github/templates.ts +398 -0
  103. package/src/github/types.ts +1 -0
  104. package/src/gitlab/auth.ts +63 -0
  105. package/src/gitlab/handlers.ts +368 -0
  106. package/src/gitlab/index.ts +19 -0
  107. package/src/gitlab/reactions.ts +104 -0
  108. package/src/gitlab/templates.ts +140 -0
  109. package/src/gitlab/types.ts +130 -0
  110. package/src/heartbeat/heartbeat.ts +434 -0
  111. package/src/heartbeat/index.ts +1 -0
  112. package/src/heartbeat/templates.ts +30 -0
  113. package/src/hooks/hook.ts +555 -4
  114. package/src/hooks/tool-loop-detection.test.ts +158 -0
  115. package/src/hooks/tool-loop-detection.ts +167 -0
  116. package/src/http/active-sessions.ts +199 -0
  117. package/src/http/agents.ts +328 -0
  118. package/src/http/config.ts +191 -0
  119. package/src/http/core.ts +309 -0
  120. package/src/http/db-query.ts +91 -0
  121. package/src/http/ecosystem.ts +63 -0
  122. package/src/http/epics.ts +460 -0
  123. package/src/http/index.ts +216 -0
  124. package/src/http/mcp.ts +77 -0
  125. package/src/http/memory.ts +168 -0
  126. package/src/http/openapi.ts +109 -0
  127. package/src/http/poll.ts +299 -0
  128. package/src/http/prompt-templates.ts +412 -0
  129. package/src/http/repos.ts +195 -0
  130. package/src/http/route-def.ts +123 -0
  131. package/src/http/schedules.ts +426 -0
  132. package/src/http/session-data.ts +241 -0
  133. package/src/http/stats.ts +174 -0
  134. package/src/http/tasks.ts +468 -0
  135. package/src/http/trackers/index.ts +10 -0
  136. package/src/http/trackers/linear.ts +187 -0
  137. package/src/http/types.ts +12 -0
  138. package/src/http/utils.ts +87 -0
  139. package/src/http/webhooks.ts +432 -0
  140. package/src/http/workflows.ts +530 -0
  141. package/src/http.ts +1 -1890
  142. package/src/linear/README.md +65 -0
  143. package/src/linear/app.ts +48 -0
  144. package/src/linear/client.ts +18 -0
  145. package/src/linear/index.ts +1 -0
  146. package/src/linear/oauth.ts +35 -0
  147. package/src/linear/outbound.ts +212 -0
  148. package/src/linear/sync.ts +567 -0
  149. package/src/linear/templates.ts +47 -0
  150. package/src/linear/types.ts +7 -0
  151. package/src/linear/webhook.ts +104 -0
  152. package/src/oauth/README.md +66 -0
  153. package/src/oauth/index.ts +6 -0
  154. package/src/oauth/wrapper.ts +204 -0
  155. package/src/prompts/base-prompt.ts +150 -265
  156. package/src/prompts/defaults.ts +196 -0
  157. package/src/prompts/registry.ts +57 -0
  158. package/src/prompts/resolver.ts +296 -0
  159. package/src/prompts/session-templates.ts +604 -0
  160. package/src/providers/claude-adapter.ts +442 -0
  161. package/src/providers/index.ts +24 -0
  162. package/src/providers/pi-mono-adapter.ts +442 -0
  163. package/src/providers/pi-mono-extension.ts +624 -0
  164. package/src/providers/pi-mono-mcp-client.ts +124 -0
  165. package/src/providers/types.ts +75 -0
  166. package/src/scheduler/scheduler.test.ts +2 -0
  167. package/src/scheduler/scheduler.ts +231 -40
  168. package/src/server.ts +97 -6
  169. package/src/slack/HEURISTICS.md +105 -0
  170. package/src/slack/actions.ts +133 -0
  171. package/src/slack/app.ts +7 -0
  172. package/src/slack/assistant.ts +118 -0
  173. package/src/slack/blocks.ts +233 -0
  174. package/src/slack/channel-activity.ts +177 -0
  175. package/src/slack/commands.ts +31 -17
  176. package/src/slack/files.ts +1 -1
  177. package/src/slack/handlers.test.ts +114 -1
  178. package/src/slack/handlers.ts +230 -55
  179. package/src/slack/responses.ts +120 -67
  180. package/src/slack/router.ts +17 -99
  181. package/src/slack/templates.ts +55 -0
  182. package/src/slack/thread-buffer.ts +213 -0
  183. package/src/slack/watcher.ts +119 -4
  184. package/src/tests/agent-activity.test.ts +247 -0
  185. package/src/tests/agentmail-filters.test.ts +97 -0
  186. package/src/tests/artifact-sdk.test.ts +800 -0
  187. package/src/tests/base-prompt.test.ts +264 -0
  188. package/src/tests/build-pi-skills.test.ts +127 -0
  189. package/src/tests/channel-activity.test.ts +363 -0
  190. package/src/tests/claude-adapter.test.ts +126 -0
  191. package/src/tests/context-versioning.test.ts +425 -0
  192. package/src/tests/db-queries-oauth.test.ts +197 -0
  193. package/src/tests/db-queries-tracker.test.ts +230 -0
  194. package/src/tests/epics.test.ts +3 -3
  195. package/src/tests/error-tracker.test.ts +368 -0
  196. package/src/tests/fetch-resolved-env.test.ts +167 -0
  197. package/src/tests/generate-default-claude-md.test.ts +9 -1
  198. package/src/tests/generate-identity-templates.test.ts +124 -0
  199. package/src/tests/gitlab-auth.test.ts +109 -0
  200. package/src/tests/gitlab-handlers.test.ts +691 -0
  201. package/src/tests/gitlab-vcs-db.test.ts +177 -0
  202. package/src/tests/heartbeat.test.ts +364 -0
  203. package/src/tests/http-api-integration.test.ts +1698 -0
  204. package/src/tests/linear-outbound-sync.test.ts +200 -0
  205. package/src/tests/linear-webhook.test.ts +406 -0
  206. package/src/tests/match-route.test.ts +187 -0
  207. package/src/tests/memory.test.ts +737 -0
  208. package/src/tests/migration-runner-regressions.test.ts +86 -0
  209. package/src/tests/model-control.test.ts +338 -0
  210. package/src/tests/oauth-wrapper.test.ts +147 -0
  211. package/src/tests/onboard-compose.test.ts +138 -0
  212. package/src/tests/onboard-env.test.ts +174 -0
  213. package/src/tests/onboard-manifest.test.ts +137 -0
  214. package/src/tests/pi-mono-adapter.test.ts +234 -0
  215. package/src/tests/pool-session-logs.test.ts +199 -0
  216. package/src/tests/progress-dedup.test.ts +98 -0
  217. package/src/tests/prompt-template-github.test.ts +682 -0
  218. package/src/tests/prompt-template-remaining.test.ts +504 -0
  219. package/src/tests/prompt-template-resolver.test.ts +621 -0
  220. package/src/tests/prompt-template-session.test.ts +363 -0
  221. package/src/tests/prompt-templates-db.test.ts +616 -0
  222. package/src/tests/provider-adapter.test.ts +122 -0
  223. package/src/tests/provider-command-format.test.ts +98 -0
  224. package/src/tests/reload-config.test.ts +170 -0
  225. package/src/tests/runner-polling-api.test.ts +25 -20
  226. package/src/tests/scheduled-tasks.test.ts +104 -0
  227. package/src/tests/scheduler-backoff.test.ts +166 -0
  228. package/src/tests/self-improvement.test.ts +541 -0
  229. package/src/tests/session-attach.test.ts +536 -0
  230. package/src/tests/session-costs.test.ts +267 -1
  231. package/src/tests/slack-actions.test.ts +133 -0
  232. package/src/tests/slack-assistant.test.ts +136 -0
  233. package/src/tests/slack-blocks.test.ts +246 -0
  234. package/src/tests/slack-metadata-inheritance.test.ts +243 -0
  235. package/src/tests/slack-queue-offline.test.ts +174 -0
  236. package/src/tests/slack-router.test.ts +181 -0
  237. package/src/tests/slack-thread-buffer.test.ts +305 -0
  238. package/src/tests/slack-thread-followups.test.ts +298 -0
  239. package/src/tests/slack-watcher.test.ts +101 -0
  240. package/src/tests/structured-output.test.ts +307 -0
  241. package/src/tests/swarm-repos.test.ts +198 -0
  242. package/src/tests/task-cancellation.test.ts +6 -4
  243. package/src/tests/task-working-dir.test.ts +176 -0
  244. package/src/tests/template-fetch.test.ts +490 -0
  245. package/src/tests/tool-annotations.test.ts +371 -0
  246. package/src/tests/tracker-tools.test.ts +184 -0
  247. package/src/tests/update-profile-agentid.test.ts +248 -0
  248. package/src/tests/update-profile-api.test.ts +143 -3
  249. package/src/tests/update-profile-auth.test.ts +195 -0
  250. package/src/tests/validation-adapters.test.ts +86 -0
  251. package/src/tests/vcs-provider.test.ts +27 -0
  252. package/src/tests/workflow-agent-task.test.ts +196 -0
  253. package/src/tests/workflow-async-v2.test.ts +508 -0
  254. package/src/tests/workflow-convergence.test.ts +541 -0
  255. package/src/tests/workflow-definition-validation.test.ts +366 -0
  256. package/src/tests/workflow-engine-v2.test.ts +691 -0
  257. package/src/tests/workflow-executors.test.ts +736 -0
  258. package/src/tests/workflow-http-v2.test.ts +599 -0
  259. package/src/tests/workflow-integration-io.test.ts +902 -0
  260. package/src/tests/workflow-io-schemas.test.ts +624 -0
  261. package/src/tests/workflow-registry.test.ts +592 -0
  262. package/src/tests/workflow-retry-v2.test.ts +401 -0
  263. package/src/tests/workflow-retry-validation.test.ts +282 -0
  264. package/src/tests/workflow-schedule-trigger.test.ts +104 -0
  265. package/src/tests/workflow-template.test.ts +288 -0
  266. package/src/tests/workflow-trigger-schema.test.ts +359 -0
  267. package/src/tests/workflow-triggers-v2.test.ts +264 -0
  268. package/src/tests/workflow-versions.test.ts +208 -0
  269. package/src/tests/workflow-workspace.test.ts +272 -0
  270. package/src/tests/x402-client.test.ts +117 -0
  271. package/src/tests/x402-config.test.ts +182 -0
  272. package/src/tests/x402-spending-tracker.test.ts +185 -0
  273. package/src/tools/cancel-task.ts +2 -0
  274. package/src/tools/context-diff.ts +171 -0
  275. package/src/tools/context-history.ts +138 -0
  276. package/src/tools/create-channel.ts +1 -0
  277. package/src/tools/db-query.ts +78 -0
  278. package/src/tools/delete-channel.ts +132 -0
  279. package/src/tools/epics/assign-task-to-epic.ts +1 -0
  280. package/src/tools/epics/create-epic.ts +3 -2
  281. package/src/tools/epics/delete-epic.ts +2 -0
  282. package/src/tools/epics/get-epic-details.ts +2 -0
  283. package/src/tools/epics/list-epics.ts +2 -0
  284. package/src/tools/epics/unassign-task-from-epic.ts +1 -0
  285. package/src/tools/epics/update-epic.ts +7 -4
  286. package/src/tools/get-swarm.ts +2 -0
  287. package/src/tools/get-task-details.ts +2 -0
  288. package/src/tools/get-tasks.ts +27 -1
  289. package/src/tools/inject-learning.ts +106 -0
  290. package/src/tools/join-swarm.ts +17 -7
  291. package/src/tools/list-channels.ts +2 -0
  292. package/src/tools/list-services.ts +2 -0
  293. package/src/tools/memory-get.ts +56 -0
  294. package/src/tools/memory-search.ts +131 -0
  295. package/src/tools/my-agent-info.ts +2 -0
  296. package/src/tools/poll-task.ts +2 -20
  297. package/src/tools/post-message.ts +1 -0
  298. package/src/tools/prompt-templates/delete.ts +86 -0
  299. package/src/tools/prompt-templates/get.ts +89 -0
  300. package/src/tools/prompt-templates/index.ts +5 -0
  301. package/src/tools/prompt-templates/list.ts +95 -0
  302. package/src/tools/prompt-templates/preview.ts +84 -0
  303. package/src/tools/prompt-templates/set.ts +117 -0
  304. package/src/tools/read-messages.ts +2 -0
  305. package/src/tools/register-agentmail-inbox.ts +166 -0
  306. package/src/tools/register-service.ts +2 -0
  307. package/src/tools/schedules/create-schedule.ts +134 -24
  308. package/src/tools/schedules/delete-schedule.ts +2 -0
  309. package/src/tools/schedules/list-schedules.ts +20 -4
  310. package/src/tools/schedules/run-schedule-now.ts +1 -0
  311. package/src/tools/schedules/update-schedule.ts +49 -17
  312. package/src/tools/send-task.ts +132 -10
  313. package/src/tools/slack-download-file.ts +4 -2
  314. package/src/tools/slack-list-channels.ts +2 -0
  315. package/src/tools/slack-post.ts +2 -0
  316. package/src/tools/slack-read.ts +2 -0
  317. package/src/tools/slack-reply.ts +2 -0
  318. package/src/tools/slack-upload-file.ts +2 -0
  319. package/src/tools/store-progress.ts +205 -4
  320. package/src/tools/swarm-config/delete-config.ts +87 -0
  321. package/src/tools/swarm-config/get-config.ts +108 -0
  322. package/src/tools/swarm-config/index.ts +4 -0
  323. package/src/tools/swarm-config/list-config.ts +99 -0
  324. package/src/tools/swarm-config/set-config.ts +118 -0
  325. package/src/tools/task-action.ts +50 -5
  326. package/src/tools/task-dedup.ts +97 -0
  327. package/src/tools/templates.ts +53 -0
  328. package/src/tools/tool-config.ts +124 -0
  329. package/src/tools/tracker/index.ts +6 -0
  330. package/src/tools/tracker/tracker-link-epic.ts +64 -0
  331. package/src/tools/tracker/tracker-link-task.ts +64 -0
  332. package/src/tools/tracker/tracker-map-agent.ts +57 -0
  333. package/src/tools/tracker/tracker-status.ts +56 -0
  334. package/src/tools/tracker/tracker-sync-status.ts +42 -0
  335. package/src/tools/tracker/tracker-unlink.ts +41 -0
  336. package/src/tools/unregister-service.ts +2 -0
  337. package/src/tools/update-profile.ts +172 -17
  338. package/src/tools/update-service-status.ts +2 -0
  339. package/src/tools/utils.ts +10 -1
  340. package/src/tools/workflows/create-workflow.ts +129 -0
  341. package/src/tools/workflows/delete-workflow.ts +42 -0
  342. package/src/tools/workflows/get-workflow-run.ts +59 -0
  343. package/src/tools/workflows/get-workflow.ts +53 -0
  344. package/src/tools/workflows/index.ts +9 -0
  345. package/src/tools/workflows/list-workflow-runs.ts +48 -0
  346. package/src/tools/workflows/list-workflows.ts +42 -0
  347. package/src/tools/workflows/retry-workflow-run.ts +40 -0
  348. package/src/tools/workflows/trigger-workflow.ts +96 -0
  349. package/src/tools/workflows/update-workflow.ts +133 -0
  350. package/src/tracker/types.ts +51 -0
  351. package/src/types.ts +530 -14
  352. package/src/utils/credentials.test.ts +156 -0
  353. package/src/utils/credentials.ts +50 -0
  354. package/src/utils/error-tracker.ts +190 -0
  355. package/src/vcs/index.ts +15 -0
  356. package/src/vcs/types.ts +5 -0
  357. package/src/workflows/checkpoint.ts +121 -0
  358. package/src/workflows/cooldown.ts +28 -0
  359. package/src/workflows/definition.ts +235 -0
  360. package/src/workflows/engine.ts +580 -0
  361. package/src/workflows/event-bus.ts +29 -0
  362. package/src/workflows/executors/agent-task.ts +103 -0
  363. package/src/workflows/executors/base.ts +86 -0
  364. package/src/workflows/executors/code-match.ts +88 -0
  365. package/src/workflows/executors/index.ts +16 -0
  366. package/src/workflows/executors/notify.ts +93 -0
  367. package/src/workflows/executors/property-match.ts +104 -0
  368. package/src/workflows/executors/raw-llm.ts +83 -0
  369. package/src/workflows/executors/registry.ts +76 -0
  370. package/src/workflows/executors/script.ts +103 -0
  371. package/src/workflows/executors/validate.ts +215 -0
  372. package/src/workflows/executors/vcs.ts +58 -0
  373. package/src/workflows/index.ts +61 -0
  374. package/src/workflows/input.ts +46 -0
  375. package/src/workflows/json-schema-validator.ts +118 -0
  376. package/src/workflows/recovery.ts +139 -0
  377. package/src/workflows/resume.ts +229 -0
  378. package/src/workflows/retry-poller.ts +216 -0
  379. package/src/workflows/template.ts +74 -0
  380. package/src/workflows/templates.ts +86 -0
  381. package/src/workflows/triggers.ts +124 -0
  382. package/src/workflows/validation.ts +104 -0
  383. package/src/workflows/version.ts +44 -0
  384. package/src/x402/cli.ts +140 -0
  385. package/src/x402/client.ts +192 -0
  386. package/src/x402/config.ts +131 -0
  387. package/src/x402/index.ts +37 -0
  388. package/src/x402/openfort-signer.ts +83 -0
  389. package/src/x402/spending-tracker.ts +109 -0
  390. package/templates/official/coder/CLAUDE.md +49 -0
  391. package/templates/official/coder/IDENTITY.md +28 -0
  392. package/templates/official/coder/SOUL.md +43 -0
  393. package/templates/official/coder/TOOLS.md +40 -0
  394. package/templates/official/coder/config.json +23 -0
  395. package/templates/official/coder/start-up.sh +23 -0
  396. package/templates/official/content-reviewer/CLAUDE.md +68 -0
  397. package/templates/official/content-reviewer/IDENTITY.md +28 -0
  398. package/templates/official/content-reviewer/SOUL.md +44 -0
  399. package/templates/official/content-reviewer/TOOLS.md +37 -0
  400. package/templates/official/content-reviewer/config.json +23 -0
  401. package/templates/official/content-reviewer/start-up.sh +23 -0
  402. package/templates/official/content-strategist/CLAUDE.md +63 -0
  403. package/templates/official/content-strategist/IDENTITY.md +33 -0
  404. package/templates/official/content-strategist/SOUL.md +48 -0
  405. package/templates/official/content-strategist/TOOLS.md +47 -0
  406. package/templates/official/content-strategist/config.json +23 -0
  407. package/templates/official/content-strategist/start-up.sh +23 -0
  408. package/templates/official/content-writer/CLAUDE.md +72 -0
  409. package/templates/official/content-writer/IDENTITY.md +30 -0
  410. package/templates/official/content-writer/SOUL.md +46 -0
  411. package/templates/official/content-writer/TOOLS.md +44 -0
  412. package/templates/official/content-writer/config.json +23 -0
  413. package/templates/official/content-writer/start-up.sh +23 -0
  414. package/templates/official/forward-deployed-engineer/CLAUDE.md +54 -0
  415. package/templates/official/forward-deployed-engineer/IDENTITY.md +37 -0
  416. package/templates/official/forward-deployed-engineer/SOUL.md +55 -0
  417. package/templates/official/forward-deployed-engineer/config.json +21 -0
  418. package/templates/official/lead/CLAUDE.md +33 -0
  419. package/templates/official/lead/IDENTITY.md +36 -0
  420. package/templates/official/lead/SOUL.md +51 -0
  421. package/templates/official/lead/config.json +22 -0
  422. package/templates/official/researcher/CLAUDE.md +46 -0
  423. package/templates/official/researcher/IDENTITY.md +28 -0
  424. package/templates/official/researcher/SOUL.md +43 -0
  425. package/templates/official/researcher/config.json +21 -0
  426. package/templates/official/reviewer/CLAUDE.md +63 -0
  427. package/templates/official/reviewer/IDENTITY.md +28 -0
  428. package/templates/official/reviewer/SOUL.md +45 -0
  429. package/templates/official/reviewer/config.json +21 -0
  430. package/templates/official/tester/CLAUDE.md +53 -0
  431. package/templates/official/tester/IDENTITY.md +28 -0
  432. package/templates/official/tester/SOUL.md +55 -0
  433. package/templates/official/tester/config.json +21 -0
  434. package/templates/schema.ts +35 -0
  435. package/.claude/settings.local.json +0 -115
  436. package/.dockerignore +0 -61
  437. package/.editorconfig +0 -15
  438. package/.env.docker.example +0 -39
  439. package/.env.example +0 -40
  440. package/.github/workflows/ci.yml +0 -76
  441. package/.github/workflows/docker-and-deploy.yml +0 -117
  442. package/.wts-config.json +0 -4
  443. package/.wts-setup.ts +0 -102
  444. package/CLAUDE.md +0 -104
  445. package/CONTRIBUTING.md +0 -270
  446. package/DEPLOYMENT.md +0 -605
  447. package/Dockerfile +0 -57
  448. package/Dockerfile.worker +0 -157
  449. package/FAQ.md +0 -19
  450. package/MCP.md +0 -406
  451. package/UI.md +0 -40
  452. package/assets/agent-swarm-logo-orange.png +0 -0
  453. package/assets/agent-swarm-logo.png +0 -0
  454. package/assets/agent-swarm.mp4 +0 -0
  455. package/assets/agent-swarm.png +0 -0
  456. package/biome.json +0 -39
  457. package/deploy/DEPLOY.md +0 -60
  458. package/deploy/agent-swarm.service +0 -17
  459. package/deploy/docker-push.ts +0 -30
  460. package/deploy/install.ts +0 -85
  461. package/deploy/prod-db.ts +0 -42
  462. package/deploy/uninstall.ts +0 -12
  463. package/deploy/update.ts +0 -21
  464. package/docker-compose.example.yml +0 -159
  465. package/docker-entrypoint.sh +0 -352
  466. package/ecosystem.config.cjs +0 -66
  467. package/plugin/README.md +0 -1
  468. package/plugin/hooks/hooks.json +0 -71
  469. package/pyproject.toml +0 -9
  470. package/scripts/generate-mcp-docs.ts +0 -415
  471. package/slack-manifest.json +0 -71
  472. package/src/tests/get-inbox-message.test.ts +0 -145
  473. package/src/tools/get-inbox-message.ts +0 -89
  474. package/src/tools/inbox-delegate.ts +0 -113
  475. package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
  476. package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
  477. package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
  478. package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
  479. package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
  480. package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
  481. package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
  482. package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
  483. package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
  484. package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
  485. package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
  486. package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
  487. package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
  488. package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
  489. package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
  490. package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
  491. package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
  492. package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
  493. package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
  494. package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
  495. package/thoughts/shared/research/.gitkeep +0 -0
  496. package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
  497. package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
  498. package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
  499. package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
  500. package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
  501. package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
  502. package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
  503. package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
  504. package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
  505. package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
  506. package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
  507. package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
  508. package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
  509. package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
  510. package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
  511. package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
  512. package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
  513. package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
  514. package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
  515. package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
  516. package/tsconfig.json +0 -37
  517. package/ui/CLAUDE.md +0 -49
  518. package/ui/bun.lock +0 -771
  519. package/ui/index.html +0 -22
  520. package/ui/package-lock.json +0 -5290
  521. package/ui/package.json +0 -33
  522. package/ui/pnpm-lock.yaml +0 -3341
  523. package/ui/postcss.config.js +0 -6
  524. package/ui/public/logo.png +0 -0
  525. package/ui/src/App.tsx +0 -63
  526. package/ui/src/components/ActivityFeed.tsx +0 -440
  527. package/ui/src/components/AgentDetailPanel.tsx +0 -733
  528. package/ui/src/components/AgentsPanel.tsx +0 -815
  529. package/ui/src/components/ChatPanel.tsx +0 -1920
  530. package/ui/src/components/ConfigModal.tsx +0 -253
  531. package/ui/src/components/Dashboard.tsx +0 -832
  532. package/ui/src/components/EditAgentProfileModal.tsx +0 -433
  533. package/ui/src/components/EpicDetailPage.tsx +0 -741
  534. package/ui/src/components/EpicsPanel.tsx +0 -566
  535. package/ui/src/components/Header.tsx +0 -160
  536. package/ui/src/components/JsonViewer.tsx +0 -171
  537. package/ui/src/components/ScheduledTaskDetailPanel.tsx +0 -517
  538. package/ui/src/components/ScheduledTasksPanel.tsx +0 -639
  539. package/ui/src/components/ServicesPanel.tsx +0 -622
  540. package/ui/src/components/SessionLogPanel.tsx +0 -1219
  541. package/ui/src/components/StatsBar.tsx +0 -321
  542. package/ui/src/components/StatusBadge.tsx +0 -168
  543. package/ui/src/components/TaskDetailPanel.tsx +0 -903
  544. package/ui/src/components/TasksPanel.tsx +0 -614
  545. package/ui/src/components/UsageCharts.tsx +0 -216
  546. package/ui/src/components/UsageTab.tsx +0 -394
  547. package/ui/src/hooks/queries.ts +0 -353
  548. package/ui/src/hooks/useAutoScroll.ts +0 -83
  549. package/ui/src/index.css +0 -257
  550. package/ui/src/lib/api.ts +0 -268
  551. package/ui/src/lib/config.ts +0 -35
  552. package/ui/src/lib/contentPreview.ts +0 -208
  553. package/ui/src/lib/theme.ts +0 -214
  554. package/ui/src/lib/utils.ts +0 -88
  555. package/ui/src/main.tsx +0 -28
  556. package/ui/src/types/api.ts +0 -323
  557. package/ui/src/vite-env.d.ts +0 -1
  558. package/ui/tailwind.config.js +0 -37
  559. package/ui/tsconfig.json +0 -31
  560. package/ui/vite.config.ts +0 -35
  561. /package/{thoughts/shared/plans → templates/community}/.gitkeep +0 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Minimal MCP client for Streamable HTTP transport.
3
+ *
4
+ * Connects to the swarm's HTTP MCP endpoint, performs the handshake,
5
+ * discovers tools, and forwards tool calls. This avoids depending on
6
+ * a separate MCP client library for pi-mono.
7
+ */
8
+
9
+ interface McpTool {
10
+ name: string;
11
+ description?: string;
12
+ inputSchema: Record<string, unknown>;
13
+ }
14
+
15
+ interface McpToolCallResult {
16
+ content: Array<{ type: string; text?: string }>;
17
+ isError?: boolean;
18
+ }
19
+
20
+ export class McpHttpClient {
21
+ private sessionId: string | null = null;
22
+ private nextId = 1;
23
+
24
+ constructor(
25
+ private baseUrl: string,
26
+ private apiKey: string,
27
+ private agentId: string,
28
+ private taskId?: string,
29
+ ) {}
30
+
31
+ private async send(body: unknown): Promise<{ data: unknown; headers: Headers }> {
32
+ const headers: Record<string, string> = {
33
+ "Content-Type": "application/json",
34
+ Accept: "application/json, text/event-stream",
35
+ Authorization: `Bearer ${this.apiKey}`,
36
+ "X-Agent-ID": this.agentId,
37
+ };
38
+ if (this.taskId) {
39
+ headers["X-Source-Task-Id"] = this.taskId;
40
+ }
41
+ if (this.sessionId) {
42
+ headers["mcp-session-id"] = this.sessionId;
43
+ }
44
+
45
+ const res = await fetch(`${this.baseUrl}/mcp`, {
46
+ method: "POST",
47
+ headers,
48
+ body: JSON.stringify(body),
49
+ });
50
+
51
+ if (!res.ok) {
52
+ throw new Error(`MCP request failed: ${res.status} ${res.statusText}`);
53
+ }
54
+
55
+ // Capture session ID from response
56
+ const sid = res.headers.get("mcp-session-id");
57
+ if (sid) this.sessionId = sid;
58
+
59
+ // Handle SSE responses (extract JSON from event stream)
60
+ const contentType = res.headers.get("content-type") || "";
61
+ if (contentType.includes("text/event-stream")) {
62
+ const text = await res.text();
63
+ const dataLines = text
64
+ .split("\n")
65
+ .filter((l) => l.startsWith("data: "))
66
+ .map((l) => l.slice(6));
67
+ const lastData = dataLines[dataLines.length - 1];
68
+ return { data: lastData ? JSON.parse(lastData) : null, headers: res.headers };
69
+ }
70
+
71
+ const data = await res.json();
72
+ return { data, headers: res.headers };
73
+ }
74
+
75
+ /** Perform MCP initialize + initialized handshake */
76
+ async initialize(): Promise<void> {
77
+ const { data } = await this.send({
78
+ jsonrpc: "2.0",
79
+ id: this.nextId++,
80
+ method: "initialize",
81
+ params: {
82
+ protocolVersion: "2025-03-26",
83
+ capabilities: {},
84
+ clientInfo: { name: "agent-swarm-pi-mono", version: "1.0.0" },
85
+ },
86
+ });
87
+
88
+ if (!data || typeof data !== "object" || !("result" in (data as Record<string, unknown>))) {
89
+ throw new Error(`MCP initialize failed: ${JSON.stringify(data)}`);
90
+ }
91
+
92
+ // Send initialized notification (no response expected for notifications)
93
+ await this.send({
94
+ jsonrpc: "2.0",
95
+ method: "notifications/initialized",
96
+ });
97
+ }
98
+
99
+ /** Discover all available MCP tools */
100
+ async listTools(): Promise<McpTool[]> {
101
+ const { data } = await this.send({
102
+ jsonrpc: "2.0",
103
+ id: this.nextId++,
104
+ method: "tools/list",
105
+ params: {},
106
+ });
107
+
108
+ const result = data as { result?: { tools?: McpTool[] } };
109
+ return result?.result?.tools ?? [];
110
+ }
111
+
112
+ /** Call an MCP tool */
113
+ async callTool(name: string, args: Record<string, unknown>): Promise<McpToolCallResult> {
114
+ const { data } = await this.send({
115
+ jsonrpc: "2.0",
116
+ id: this.nextId++,
117
+ method: "tools/call",
118
+ params: { name, arguments: args },
119
+ });
120
+
121
+ const result = data as { result?: McpToolCallResult };
122
+ return result?.result ?? { content: [{ type: "text", text: "No result" }] };
123
+ }
124
+ }
@@ -0,0 +1,75 @@
1
+ /** Data for session cost tracking. Shared across all provider adapters. */
2
+ export interface CostData {
3
+ sessionId: string;
4
+ taskId?: string;
5
+ agentId: string;
6
+ totalCostUsd: number;
7
+ inputTokens?: number;
8
+ outputTokens?: number;
9
+ cacheReadTokens?: number;
10
+ cacheWriteTokens?: number;
11
+ durationMs: number;
12
+ numTurns: number;
13
+ model: string;
14
+ isError: boolean;
15
+ }
16
+
17
+ /** Normalized event emitted by any provider adapter. */
18
+ export type ProviderEvent =
19
+ | { type: "session_init"; sessionId: string }
20
+ | { type: "message"; role: "assistant" | "user"; content: string }
21
+ | { type: "tool_start"; toolCallId: string; toolName: string; args: unknown }
22
+ | { type: "tool_end"; toolCallId: string; toolName: string; result: unknown }
23
+ | { type: "result"; cost: CostData; output?: string; isError: boolean; errorCategory?: string }
24
+ | { type: "error"; message: string; category?: string }
25
+ | { type: "raw_log"; content: string }
26
+ | { type: "raw_stderr"; content: string }
27
+ | { type: "custom"; name: string; data: unknown };
28
+
29
+ /** Configuration passed to a provider adapter to create a session. */
30
+ export interface ProviderSessionConfig {
31
+ prompt: string;
32
+ systemPrompt: string;
33
+ model: string;
34
+ role: string;
35
+ agentId: string;
36
+ taskId: string;
37
+ apiUrl: string;
38
+ apiKey: string;
39
+ cwd: string;
40
+ resumeSessionId?: string;
41
+ iteration?: number;
42
+ logFile: string;
43
+ /** Extra CLI args — used by Claude adapter, ignored by others. */
44
+ additionalArgs?: string[];
45
+ /** Resolved environment variables to pass to the spawned process. */
46
+ env?: Record<string, string>;
47
+ }
48
+
49
+ /** A running provider session. */
50
+ export interface ProviderSession {
51
+ readonly sessionId: string | undefined;
52
+ onEvent(listener: (event: ProviderEvent) => void): void;
53
+ waitForCompletion(): Promise<ProviderResult>;
54
+ abort(): Promise<void>;
55
+ }
56
+
57
+ /** Result returned when a provider session completes. */
58
+ export interface ProviderResult {
59
+ exitCode: number;
60
+ sessionId?: string;
61
+ cost?: CostData;
62
+ output?: string;
63
+ isError: boolean;
64
+ errorCategory?: string;
65
+ /** Human-readable failure reason built from error tracking. */
66
+ failureReason?: string;
67
+ }
68
+
69
+ /** Main contract for a harness provider adapter. */
70
+ export interface ProviderAdapter {
71
+ readonly name: string;
72
+ createSession(config: ProviderSessionConfig): Promise<ProviderSession>;
73
+ canResume(sessionId: string): Promise<boolean>;
74
+ formatCommand(commandName: string): string;
75
+ }
@@ -107,6 +107,8 @@ describe("calculateNextRun", () => {
107
107
  priority: 50,
108
108
  enabled: true,
109
109
  timezone: "UTC",
110
+ consecutiveErrors: 0,
111
+ scheduleType: "recurring" as const,
110
112
  createdAt: new Date().toISOString(),
111
113
  lastUpdatedAt: new Date().toISOString(),
112
114
  } as Parameters<typeof calculateNextRun>[0];
@@ -7,9 +7,86 @@ import {
7
7
  updateScheduledTask,
8
8
  } from "@/be/db";
9
9
  import type { ScheduledTask } from "@/types";
10
+ import type { ExecutorRegistry } from "@/workflows/executors/registry";
11
+ import { handleScheduleTrigger } from "@/workflows/triggers";
10
12
 
11
13
  let schedulerInterval: ReturnType<typeof setInterval> | null = null;
12
14
  let isProcessing = false;
15
+ let executorRegistry: ExecutorRegistry | null = null;
16
+
17
+ /**
18
+ * Recover missed scheduled task runs from downtime.
19
+ * Fires ONE catch-up run per schedule (not N missed runs).
20
+ * Tags the task with "recovered" so it's distinguishable.
21
+ */
22
+ async function recoverMissedSchedules(): Promise<void> {
23
+ const now = new Date();
24
+ const dueSchedules = getDueScheduledTasks();
25
+
26
+ for (const schedule of dueSchedules) {
27
+ if (!schedule.nextRunAt) continue;
28
+ const missedBy = now.getTime() - new Date(schedule.nextRunAt).getTime();
29
+ if (missedBy < 15000) continue; // Less than 15s — normal timing jitter
30
+
31
+ console.log(
32
+ `[Scheduler] Recovering missed schedule "${schedule.name}" ` +
33
+ `(was due ${Math.round(missedBy / 1000)}s ago)`,
34
+ );
35
+
36
+ try {
37
+ // Check if any workflows are linked to this schedule
38
+ let triggeredWorkflows = false;
39
+ if (executorRegistry) {
40
+ const runIds = await handleScheduleTrigger(schedule.id, schedule, executorRegistry);
41
+ if (runIds.length > 0) {
42
+ triggeredWorkflows = true;
43
+ console.log(
44
+ `[Scheduler] Recovered schedule "${schedule.name}" → triggered ${runIds.length} workflow(s)`,
45
+ );
46
+ }
47
+ }
48
+
49
+ if (!triggeredWorkflows) {
50
+ const tx = getDb().transaction(() => {
51
+ createTaskExtended(schedule.taskTemplate, {
52
+ creatorAgentId: schedule.createdByAgentId,
53
+ taskType: schedule.taskType,
54
+ tags: [...schedule.tags, "scheduled", `schedule:${schedule.name}`, "recovered"],
55
+ priority: schedule.priority,
56
+ agentId: schedule.targetAgentId,
57
+ model: schedule.model,
58
+ scheduleId: schedule.id,
59
+ source: "schedule",
60
+ });
61
+ });
62
+ tx();
63
+ }
64
+
65
+ // Update schedule state regardless of workflow/task path
66
+ if (schedule.scheduleType === "one_time") {
67
+ updateScheduledTask(schedule.id, {
68
+ lastRunAt: now.toISOString(),
69
+ nextRunAt: null,
70
+ enabled: false,
71
+ lastUpdatedAt: now.toISOString(),
72
+ });
73
+ } else {
74
+ const nextRun = calculateNextRun(schedule, now);
75
+ updateScheduledTask(schedule.id, {
76
+ lastRunAt: now.toISOString(),
77
+ nextRunAt: nextRun,
78
+ lastUpdatedAt: now.toISOString(),
79
+ });
80
+ }
81
+
82
+ if (schedule.scheduleType === "one_time") {
83
+ console.log(`[Scheduler] One-time schedule "${schedule.name}" recovered and auto-disabled`);
84
+ }
85
+ } catch (err) {
86
+ console.error(`[Scheduler] Error recovering "${schedule.name}":`, err);
87
+ }
88
+ }
89
+ }
13
90
 
14
91
  /**
15
92
  * Calculate next run time based on cron expression or interval.
@@ -38,52 +115,141 @@ export function calculateNextRun(schedule: ScheduledTask, fromTime: Date = new D
38
115
  throw new Error("Schedule must have cronExpression or intervalMs");
39
116
  }
40
117
 
118
+ // Exponential backoff schedule for consecutive errors (in ms)
119
+ const ERROR_BACKOFF_MS = [
120
+ 60_000, // 1 minute
121
+ 300_000, // 5 minutes
122
+ 900_000, // 15 minutes
123
+ 1_800_000, // 30 minutes
124
+ 3_600_000, // 1 hour (cap)
125
+ ];
126
+
127
+ const MAX_CONSECUTIVE_ERRORS = 5;
128
+
129
+ function getBackoffMs(consecutiveErrors: number): number {
130
+ const idx = Math.min(consecutiveErrors - 1, ERROR_BACKOFF_MS.length - 1);
131
+ return ERROR_BACKOFF_MS[Math.max(0, idx)] ?? ERROR_BACKOFF_MS[0]!;
132
+ }
133
+
41
134
  /**
42
135
  * Execute a single scheduled task by creating an agent task.
136
+ * Tracks consecutive errors and applies exponential backoff on failure.
43
137
  */
44
138
  async function executeSchedule(schedule: ScheduledTask): Promise<void> {
45
- // Wrap in transaction to ensure atomicity of task creation and schedule update
46
- const tx = getDb().transaction(() => {
139
+ try {
140
+ // Check if any workflows are linked to this schedule
141
+ let triggeredWorkflows = false;
142
+ if (executorRegistry) {
143
+ const runIds = await handleScheduleTrigger(schedule.id, schedule, executorRegistry);
144
+ if (runIds.length > 0) {
145
+ triggeredWorkflows = true;
146
+ console.log(
147
+ `[Scheduler] Schedule "${schedule.name}" → triggered ${runIds.length} workflow(s)`,
148
+ );
149
+ }
150
+ }
151
+
152
+ if (!triggeredWorkflows) {
153
+ // No workflows linked — create standalone task (existing behavior)
154
+ getDb().transaction(() => {
155
+ createTaskExtended(schedule.taskTemplate, {
156
+ creatorAgentId: schedule.createdByAgentId,
157
+ taskType: schedule.taskType,
158
+ tags: [...schedule.tags, "scheduled", `schedule:${schedule.name}`],
159
+ priority: schedule.priority,
160
+ agentId: schedule.targetAgentId,
161
+ model: schedule.model,
162
+ scheduleId: schedule.id,
163
+ source: "schedule",
164
+ });
165
+ })();
166
+ }
167
+
168
+ // Update schedule state regardless of workflow/task path
47
169
  const now = new Date().toISOString();
170
+ if (schedule.scheduleType === "one_time") {
171
+ updateScheduledTask(schedule.id, {
172
+ lastRunAt: now,
173
+ nextRunAt: null,
174
+ enabled: false,
175
+ lastUpdatedAt: now,
176
+ consecutiveErrors: 0,
177
+ lastErrorAt: null,
178
+ lastErrorMessage: null,
179
+ });
180
+ console.log(`[Scheduler] Executed one-time schedule "${schedule.name}", auto-disabled`);
181
+ } else {
182
+ const nextRun = calculateNextRun(schedule, new Date());
183
+ updateScheduledTask(schedule.id, {
184
+ lastRunAt: now,
185
+ nextRunAt: nextRun,
186
+ lastUpdatedAt: now,
187
+ consecutiveErrors: 0,
188
+ lastErrorAt: null,
189
+ lastErrorMessage: null,
190
+ });
191
+ console.log(`[Scheduler] Executed schedule "${schedule.name}", next run: ${nextRun}`);
192
+ }
193
+ } catch (err) {
194
+ const errorCount = (schedule.consecutiveErrors ?? 0) + 1;
195
+ const now = new Date();
196
+ const errorMsg = err instanceof Error ? err.message : String(err);
48
197
 
49
- // Create the actual task
50
- createTaskExtended(schedule.taskTemplate, {
51
- creatorAgentId: schedule.createdByAgentId,
52
- taskType: schedule.taskType,
53
- tags: [...schedule.tags, "scheduled", `schedule:${schedule.name}`],
54
- priority: schedule.priority,
55
- agentId: schedule.targetAgentId, // null goes to pool
56
- });
198
+ console.error(
199
+ `[Scheduler] Error executing "${schedule.name}" (${errorCount} consecutive):`,
200
+ errorMsg,
201
+ );
57
202
 
58
- // Update lastRunAt and nextRunAt
59
- const nextRun = calculateNextRun(schedule, new Date());
60
- updateScheduledTask(schedule.id, {
61
- lastRunAt: now,
62
- nextRunAt: nextRun,
63
- lastUpdatedAt: now,
64
- });
203
+ const updates: {
204
+ consecutiveErrors: number;
205
+ lastErrorAt: string;
206
+ lastErrorMessage: string;
207
+ lastUpdatedAt: string;
208
+ enabled?: boolean;
209
+ nextRunAt?: string;
210
+ } = {
211
+ consecutiveErrors: errorCount,
212
+ lastErrorAt: now.toISOString(),
213
+ lastErrorMessage: errorMsg.slice(0, 500),
214
+ lastUpdatedAt: now.toISOString(),
215
+ };
65
216
 
66
- return nextRun;
67
- });
217
+ if (schedule.scheduleType === "one_time") {
218
+ updates.enabled = false;
219
+ console.warn(
220
+ `[Scheduler] One-time schedule "${schedule.name}" failed, auto-disabled: ${errorMsg}`,
221
+ );
222
+ } else if (errorCount >= MAX_CONSECUTIVE_ERRORS) {
223
+ updates.enabled = false;
224
+ console.warn(
225
+ `[Scheduler] Auto-disabled "${schedule.name}" after ${errorCount} consecutive errors`,
226
+ );
227
+ } else {
228
+ const backoff = getBackoffMs(errorCount);
229
+ updates.nextRunAt = new Date(now.getTime() + backoff).toISOString();
230
+ console.log(`[Scheduler] Backing off "${schedule.name}" for ${backoff / 1000}s`);
231
+ }
68
232
 
69
- const nextRun = tx();
70
- console.log(`[Scheduler] Executed schedule "${schedule.name}", next run: ${nextRun}`);
233
+ updateScheduledTask(schedule.id, updates);
234
+ }
71
235
  }
72
236
 
73
237
  /**
74
238
  * Start the scheduler polling loop.
239
+ * @param registry ExecutorRegistry for triggering workflows linked to schedules
75
240
  * @param intervalMs Polling interval in milliseconds (default: 10000)
76
241
  */
77
- export function startScheduler(intervalMs = 10000): void {
242
+ export function startScheduler(registry: ExecutorRegistry, intervalMs = 10000): void {
78
243
  if (schedulerInterval) {
79
244
  console.log("[Scheduler] Already running");
80
245
  return;
81
246
  }
82
247
 
248
+ executorRegistry = registry;
83
249
  console.log(`[Scheduler] Starting with ${intervalMs}ms polling interval`);
84
250
 
85
- // Run immediately once, then start interval
86
- void processSchedules();
251
+ // Recover missed schedules from downtime, then run normal processing
252
+ void recoverMissedSchedules().then(() => processSchedules());
87
253
 
88
254
  schedulerInterval = setInterval(async () => {
89
255
  await processSchedules();
@@ -138,27 +304,52 @@ export async function runScheduleNow(scheduleId: string): Promise<void> {
138
304
  throw new Error(`Schedule is disabled: ${schedule.name}`);
139
305
  }
140
306
 
141
- // Wrap in transaction to ensure atomicity of task creation and schedule update
142
- const tx = getDb().transaction(() => {
143
- const now = new Date().toISOString();
307
+ // Check if any workflows are linked to this schedule
308
+ let triggeredWorkflows = false;
309
+ if (executorRegistry) {
310
+ const runIds = await handleScheduleTrigger(scheduleId, schedule, executorRegistry);
311
+ if (runIds.length > 0) {
312
+ triggeredWorkflows = true;
313
+ console.log(
314
+ `[Scheduler] Manual run of "${schedule.name}" → triggered ${runIds.length} workflow(s)`,
315
+ );
316
+ }
317
+ }
144
318
 
145
- // Create the actual task
146
- createTaskExtended(schedule.taskTemplate, {
147
- creatorAgentId: schedule.createdByAgentId,
148
- taskType: schedule.taskType,
149
- tags: [...schedule.tags, "scheduled", `schedule:${schedule.name}`, "manual-run"],
150
- priority: schedule.priority,
151
- agentId: schedule.targetAgentId,
152
- });
319
+ if (!triggeredWorkflows) {
320
+ // No workflows linked — create standalone task (existing behavior)
321
+ getDb().transaction(() => {
322
+ createTaskExtended(schedule.taskTemplate, {
323
+ creatorAgentId: schedule.createdByAgentId,
324
+ taskType: schedule.taskType,
325
+ tags: [...schedule.tags, "scheduled", `schedule:${schedule.name}`, "manual-run"],
326
+ priority: schedule.priority,
327
+ agentId: schedule.targetAgentId,
328
+ model: schedule.model,
329
+ scheduleId: schedule.id,
330
+ source: "schedule",
331
+ });
332
+ })();
333
+ }
153
334
 
335
+ // Update schedule state
336
+ const now = new Date().toISOString();
337
+ if (schedule.scheduleType === "one_time") {
338
+ updateScheduledTask(schedule.id, {
339
+ lastRunAt: now,
340
+ nextRunAt: null,
341
+ enabled: false,
342
+ lastUpdatedAt: now,
343
+ });
344
+ console.log(
345
+ `[Scheduler] Manually executed one-time schedule "${schedule.name}", auto-disabled`,
346
+ );
347
+ } else {
154
348
  // Only update lastRunAt, not nextRunAt (to not affect regular schedule)
155
349
  updateScheduledTask(schedule.id, {
156
350
  lastRunAt: now,
157
351
  lastUpdatedAt: now,
158
352
  });
159
- });
160
-
161
- tx();
162
-
163
- console.log(`[Scheduler] Manually executed schedule "${schedule.name}"`);
353
+ console.log(`[Scheduler] Manually executed schedule "${schedule.name}"`);
354
+ }
164
355
  }