@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,567 @@
1
+ import { cancelTask, createTaskExtended, getAllAgents, getTaskById } from "../be/db";
2
+ import { getOAuthTokens } from "../be/db-queries/oauth";
3
+ import {
4
+ createTrackerSync,
5
+ deleteTrackerSync,
6
+ getTrackerSyncByExternalId,
7
+ updateTrackerSync,
8
+ } from "../be/db-queries/tracker";
9
+ import { resolveTemplate } from "../prompts/resolver";
10
+ // Side-effect import: registers all Linear event templates in the in-memory registry
11
+ import "./templates";
12
+
13
+ /**
14
+ * In-memory map: swarmTaskId → Linear agentSessionId.
15
+ * Used by outbound sync to post activities back to the AgentSession.
16
+ * Not persisted — sessions are ephemeral and tied to the process lifetime.
17
+ */
18
+ export const taskSessionMap = new Map<string, string>();
19
+
20
+ const AGENT_ACTIVITY_MUTATION = `
21
+ mutation AgentActivityCreate($input: AgentActivityCreateInput!) {
22
+ agentActivityCreate(input: $input) { success }
23
+ }
24
+ `;
25
+
26
+ const AGENT_SESSION_UPDATE_MUTATION = `
27
+ mutation AgentSessionUpdate($id: String!, $input: AgentSessionUpdateInput!) {
28
+ agentSessionUpdate(id: $id, input: $input) { success }
29
+ }
30
+ `;
31
+
32
+ /**
33
+ * Low-level helper to post an activity to a Linear AgentSession via GraphQL.
34
+ *
35
+ * Activity types and their effect on session state:
36
+ * - `thought` — internal note (dimmed), session becomes active
37
+ * - `action` — tool invocation, session becomes active
38
+ * - `response` — final result, session auto-completes
39
+ * - `error` — error message, session transitions to error state
40
+ *
41
+ * No `signal` parameter is needed — Linear derives session state from the activity type.
42
+ */
43
+ async function postAgentActivity(
44
+ sessionId: string,
45
+ content:
46
+ | { type: "thought" | "response" | "error"; body: string }
47
+ | { type: "action"; action: string; parameter?: string; result?: string },
48
+ ): Promise<boolean> {
49
+ const tokens = getOAuthTokens("linear");
50
+ if (!tokens) {
51
+ console.log("[Linear Sync] No OAuth tokens, cannot post AgentSession activity");
52
+ return false;
53
+ }
54
+
55
+ const input = {
56
+ agentSessionId: sessionId,
57
+ content,
58
+ };
59
+
60
+ const res = await fetch("https://api.linear.app/graphql", {
61
+ method: "POST",
62
+ headers: {
63
+ "Content-Type": "application/json",
64
+ Authorization: `Bearer ${tokens.accessToken}`,
65
+ },
66
+ body: JSON.stringify({
67
+ query: AGENT_ACTIVITY_MUTATION,
68
+ variables: { input },
69
+ }),
70
+ });
71
+
72
+ if (!res.ok) {
73
+ console.error(
74
+ `[Linear Sync] Failed to post activity to AgentSession ${sessionId}: ${res.status} ${res.statusText}`,
75
+ );
76
+ return false;
77
+ }
78
+
79
+ const result = (await res.json()) as {
80
+ data?: { agentActivityCreate?: { success: boolean } };
81
+ errors?: unknown[];
82
+ };
83
+ if (result.errors) {
84
+ console.error("[Linear Sync] GraphQL errors posting AgentSession activity:", result.errors);
85
+ return false;
86
+ }
87
+
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * Update an AgentSession via the agentSessionUpdate mutation.
93
+ * Used to set externalUrls, plan, etc.
94
+ */
95
+ async function updateAgentSession(
96
+ sessionId: string,
97
+ input: Record<string, unknown>,
98
+ ): Promise<boolean> {
99
+ const tokens = getOAuthTokens("linear");
100
+ if (!tokens) {
101
+ console.log("[Linear Sync] No OAuth tokens, cannot update AgentSession");
102
+ return false;
103
+ }
104
+
105
+ const res = await fetch("https://api.linear.app/graphql", {
106
+ method: "POST",
107
+ headers: {
108
+ "Content-Type": "application/json",
109
+ Authorization: `Bearer ${tokens.accessToken}`,
110
+ },
111
+ body: JSON.stringify({
112
+ query: AGENT_SESSION_UPDATE_MUTATION,
113
+ variables: { id: sessionId, input },
114
+ }),
115
+ });
116
+
117
+ if (!res.ok) {
118
+ console.error(
119
+ `[Linear Sync] Failed to update AgentSession ${sessionId}: ${res.status} ${res.statusText}`,
120
+ );
121
+ return false;
122
+ }
123
+
124
+ const result = (await res.json()) as {
125
+ data?: { agentSessionUpdate?: { success: boolean } };
126
+ errors?: unknown[];
127
+ };
128
+ if (result.errors) {
129
+ console.error("[Linear Sync] GraphQL errors updating AgentSession:", result.errors);
130
+ return false;
131
+ }
132
+
133
+ return true;
134
+ }
135
+
136
+ /**
137
+ * Acknowledge a Linear AgentSession by posting a thought activity.
138
+ * Creating an activity transitions the session from "pending" to "active".
139
+ */
140
+ async function acknowledgeAgentSession(sessionId: string, message: string): Promise<void> {
141
+ const ok = await postAgentActivity(sessionId, { type: "thought", body: message });
142
+ if (ok) {
143
+ console.log(`[Linear Sync] AgentSession ${sessionId} acknowledged`);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Post a response activity to a Linear AgentSession (visible as a comment).
149
+ */
150
+ export async function postAgentSessionResponse(sessionId: string, body: string): Promise<void> {
151
+ await postAgentActivity(sessionId, { type: "response", body });
152
+ }
153
+
154
+ /**
155
+ * Post a thought activity to a Linear AgentSession (dimmed internal thinking).
156
+ */
157
+ export async function postAgentSessionThought(sessionId: string, body: string): Promise<void> {
158
+ await postAgentActivity(sessionId, { type: "thought", body });
159
+ }
160
+
161
+ /**
162
+ * Post an error activity to a Linear AgentSession.
163
+ */
164
+ export async function postAgentSessionError(sessionId: string, body: string): Promise<void> {
165
+ await postAgentActivity(sessionId, { type: "error", body });
166
+ }
167
+
168
+ /**
169
+ * End a Linear AgentSession by posting a response or error activity.
170
+ * A `response` activity auto-completes the session; an `error` activity marks it as errored.
171
+ * No explicit signal is needed — Linear derives state from the activity type.
172
+ */
173
+ export async function endAgentSession(
174
+ sessionId: string,
175
+ body: string,
176
+ type: "response" | "error" = "response",
177
+ ): Promise<void> {
178
+ await postAgentActivity(sessionId, { type, body });
179
+ }
180
+
181
+ /**
182
+ * Post an action activity to a Linear AgentSession (tool invocation).
183
+ */
184
+ export async function postAgentSessionAction(
185
+ sessionId: string,
186
+ action: string,
187
+ parameter?: string,
188
+ result?: string,
189
+ ): Promise<void> {
190
+ const content: { type: "action"; action: string; parameter?: string; result?: string } = {
191
+ type: "action",
192
+ action,
193
+ };
194
+ if (parameter) content.parameter = parameter;
195
+ if (result) content.result = result;
196
+ await postAgentActivity(sessionId, content);
197
+ }
198
+
199
+ /**
200
+ * Set externalUrls on an AgentSession so users can click through to the swarm dashboard.
201
+ */
202
+ export async function updateAgentSessionExternalUrls(
203
+ sessionId: string,
204
+ urls: { label: string; url: string }[],
205
+ ): Promise<void> {
206
+ const ok = await updateAgentSession(sessionId, { externalUrls: urls });
207
+ if (ok) {
208
+ console.log(`[Linear Sync] Set externalUrls on AgentSession ${sessionId}`);
209
+ }
210
+ }
211
+
212
+ // Status mapping: Linear state names → swarm task statuses
213
+ const LINEAR_STATUS_MAP: Record<string, string> = {
214
+ Backlog: "skip",
215
+ Todo: "unassigned",
216
+ "In Progress": "in_progress",
217
+ Done: "completed",
218
+ Canceled: "cancelled",
219
+ Cancelled: "cancelled",
220
+ };
221
+
222
+ export function mapLinearStatusToSwarm(linearStateName: string): string | null {
223
+ return LINEAR_STATUS_MAP[linearStateName] ?? null;
224
+ }
225
+
226
+ /**
227
+ * Find the lead agent to receive Linear tasks.
228
+ * Returns null if no lead is available (task will go to pool).
229
+ */
230
+ function findLeadAgent() {
231
+ const agents = getAllAgents();
232
+ const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
233
+ if (onlineLead) return onlineLead;
234
+ return agents.find((a) => a.isLead) ?? null;
235
+ }
236
+
237
+ /**
238
+ * Handle AgentSession events from Linear.
239
+ * These are fired when an issue is assigned to the Linear agent integration,
240
+ * triggering a new swarm task.
241
+ */
242
+ export async function handleAgentSessionEvent(event: Record<string, unknown>): Promise<void> {
243
+ // Linear sends AgentSessionEvent with agentSession.issue (not data.issue)
244
+ const agentSession = event.agentSession as Record<string, unknown> | undefined;
245
+ const data = agentSession ?? (event.data as Record<string, unknown> | undefined);
246
+ if (!data) {
247
+ console.log("[Linear Sync] AgentSession event has no agentSession/data, skipping");
248
+ return;
249
+ }
250
+
251
+ const issue = data.issue as Record<string, unknown> | undefined;
252
+ if (!issue) {
253
+ console.log("[Linear Sync] AgentSession event has no issue data, skipping");
254
+ return;
255
+ }
256
+
257
+ const issueId = String(issue.id ?? "");
258
+ const issueIdentifier = String(issue.identifier ?? "");
259
+ const issueTitle = String(issue.title ?? "");
260
+ const issueUrl = String(issue.url ?? "");
261
+ const issueDescription = issue.description ? String(issue.description) : "";
262
+ const sessionUrl = agentSession ? String(agentSession.url ?? "") : "";
263
+
264
+ if (!issueId) {
265
+ console.log("[Linear Sync] AgentSession event has no issue ID, skipping");
266
+ return;
267
+ }
268
+
269
+ // Check if we already track this issue
270
+ const existing = getTrackerSyncByExternalId("linear", "task", issueId);
271
+ if (existing) {
272
+ console.log(
273
+ `[Linear Sync] Issue ${issueIdentifier} already tracked as task ${existing.swarmId}, skipping`,
274
+ );
275
+ return;
276
+ }
277
+
278
+ const lead = findLeadAgent();
279
+
280
+ const sessionSection = sessionUrl ? `\nSession: ${sessionUrl}` : "";
281
+ const descriptionSection = issueDescription ? `\nDescription:\n${issueDescription}\n` : "";
282
+ const assignedResult = resolveTemplate("linear.issue.assigned", {
283
+ issue_identifier: issueIdentifier,
284
+ issue_title: issueTitle,
285
+ issue_url: issueUrl,
286
+ session_section: sessionSection,
287
+ description_section: descriptionSection,
288
+ });
289
+
290
+ if (assignedResult.skipped) {
291
+ return;
292
+ }
293
+
294
+ const task = createTaskExtended(assignedResult.text, {
295
+ agentId: lead?.id ?? "",
296
+ source: "linear",
297
+ taskType: "linear-issue",
298
+ });
299
+
300
+ createTrackerSync({
301
+ provider: "linear",
302
+ entityType: "task",
303
+ providerEntityType: "Issue",
304
+ swarmId: task.id,
305
+ externalId: issueId,
306
+ externalIdentifier: issueIdentifier,
307
+ externalUrl: issueUrl,
308
+ lastSyncOrigin: "external",
309
+ syncDirection: "inbound",
310
+ });
311
+
312
+ // Track the AgentSession so outbound sync can post activities to it
313
+ const sessionId = agentSession ? String(agentSession.id ?? "") : "";
314
+ if (sessionId) {
315
+ taskSessionMap.set(task.id, sessionId);
316
+
317
+ // Acknowledge the AgentSession (pending → active)
318
+ acknowledgeAgentSession(
319
+ sessionId,
320
+ `Task received by Agent Swarm (${task.id}). Processing...`,
321
+ ).catch((err) => {
322
+ console.error("[Linear Sync] Failed to acknowledge AgentSession:", err);
323
+ });
324
+
325
+ // Set externalUrls so users can click through to the swarm dashboard
326
+ const dashboardUrl = process.env.SWARM_DASHBOARD_URL || process.env.APP_URL;
327
+ if (dashboardUrl) {
328
+ updateAgentSessionExternalUrls(sessionId, [
329
+ { label: "View in Agent Swarm", url: `${dashboardUrl}/tasks/${task.id}` },
330
+ ]).catch((err) => {
331
+ console.error("[Linear Sync] Failed to set externalUrls on AgentSession:", err);
332
+ });
333
+ }
334
+ }
335
+
336
+ console.log(
337
+ `[Linear Sync] Created task ${task.id} for ${issueIdentifier} -> ${lead?.name ?? "unassigned"}`,
338
+ );
339
+ }
340
+
341
+ /**
342
+ * Handle Issue update events from Linear webhooks.
343
+ * Updates swarm task status when a tracked Linear issue changes state.
344
+ */
345
+ export async function handleIssueUpdate(
346
+ event: Record<string, unknown>,
347
+ deliveryId?: string,
348
+ ): Promise<void> {
349
+ const data = event.data as Record<string, unknown> | undefined;
350
+ if (!data) return;
351
+
352
+ const issueId = String(data.id ?? "");
353
+ if (!issueId) return;
354
+
355
+ const sync = getTrackerSyncByExternalId("linear", "task", issueId);
356
+ if (!sync) {
357
+ // We don't track this issue — ignore
358
+ return;
359
+ }
360
+
361
+ // Check if the status (state) changed
362
+ const updatedFrom = event.updatedFrom as Record<string, unknown> | undefined;
363
+ if (!updatedFrom) return;
364
+
365
+ const state = data.state as Record<string, unknown> | undefined;
366
+ if (!state) return;
367
+
368
+ const stateName = String(state.name ?? "");
369
+ const swarmStatus = mapLinearStatusToSwarm(stateName);
370
+
371
+ if (!swarmStatus) {
372
+ console.log(
373
+ `[Linear Sync] Unknown Linear status "${stateName}" for issue ${issueId}, skipping`,
374
+ );
375
+ return;
376
+ }
377
+
378
+ // Update tracker_sync metadata
379
+ updateTrackerSync(sync.id, {
380
+ lastSyncOrigin: "external",
381
+ lastSyncedAt: new Date().toISOString(),
382
+ lastDeliveryId: deliveryId ?? null,
383
+ });
384
+
385
+ // Map status to swarm actions
386
+ if (swarmStatus === "cancelled") {
387
+ const task = getTaskById(sync.swarmId);
388
+ if (task && !["completed", "failed", "cancelled"].includes(task.status)) {
389
+ cancelTask(sync.swarmId, `Linear issue cancelled`);
390
+ console.log(
391
+ `[Linear Sync] Cancelled task ${sync.swarmId} (Linear issue ${data.identifier ?? issueId} cancelled)`,
392
+ );
393
+ }
394
+ return;
395
+ }
396
+
397
+ if (swarmStatus === "completed") {
398
+ // We don't auto-complete tasks from Linear — the agent decides when work is done
399
+ console.log(
400
+ `[Linear Sync] Linear issue ${data.identifier ?? issueId} marked Done — not auto-completing task ${sync.swarmId}`,
401
+ );
402
+ return;
403
+ }
404
+
405
+ // For skip / unassigned / in_progress — log but don't force status changes
406
+ console.log(
407
+ `[Linear Sync] Issue ${data.identifier ?? issueId} status → ${stateName} (mapped: ${swarmStatus})`,
408
+ );
409
+ }
410
+
411
+ /**
412
+ * Handle Issue delete events from Linear webhooks.
413
+ * Cancels the swarm task if the tracked Linear issue is removed.
414
+ */
415
+ export async function handleIssueDelete(event: Record<string, unknown>): Promise<void> {
416
+ const data = event.data as Record<string, unknown> | undefined;
417
+ if (!data) return;
418
+
419
+ const issueId = String(data.id ?? "");
420
+ if (!issueId) return;
421
+
422
+ const sync = getTrackerSyncByExternalId("linear", "task", issueId);
423
+ if (!sync) return;
424
+
425
+ const task = getTaskById(sync.swarmId);
426
+ if (task && !["completed", "failed", "cancelled"].includes(task.status)) {
427
+ cancelTask(sync.swarmId, "Linear issue deleted");
428
+ console.log(`[Linear Sync] Cancelled task ${sync.swarmId} (Linear issue ${issueId} deleted)`);
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Handle "prompted" AgentSession events — user sent a follow-up message
434
+ * in the Linear agent chat UI.
435
+ */
436
+ export async function handleAgentSessionPrompted(event: Record<string, unknown>): Promise<void> {
437
+ const agentSession = event.agentSession as Record<string, unknown> | undefined;
438
+ if (!agentSession) {
439
+ console.log("[Linear Sync] Prompted event has no agentSession, skipping");
440
+ return;
441
+ }
442
+
443
+ const sessionId = String(agentSession.id ?? "");
444
+ const issue = agentSession.issue as Record<string, unknown> | undefined;
445
+
446
+ // User message is in event.agentActivity.content.body (not agentSession.comment.body)
447
+ const agentActivity = event.agentActivity as Record<string, unknown> | undefined;
448
+ const activityContent = agentActivity?.content as Record<string, unknown> | undefined;
449
+ const userMessage = activityContent ? String(activityContent.body ?? "") : "";
450
+ const activitySignal = agentActivity ? String(agentActivity.signal ?? "") : "";
451
+
452
+ if (!issue) {
453
+ console.log("[Linear Sync] Prompted event has no issue data, skipping");
454
+ return;
455
+ }
456
+
457
+ const issueId = String(issue.id ?? "");
458
+ const issueIdentifier = String(issue.identifier ?? "");
459
+ const issueTitle = String(issue.title ?? "");
460
+ const issueUrl = String(issue.url ?? "");
461
+
462
+ // Handle stop signal — cancel the active task
463
+ if (activitySignal === "stop") {
464
+ const existing = getTrackerSyncByExternalId("linear", "task", issueId);
465
+ if (existing) {
466
+ const existingTask = getTaskById(existing.swarmId);
467
+ if (existingTask && !["completed", "failed", "cancelled"].includes(existingTask.status)) {
468
+ cancelTask(existing.swarmId, "Stopped by user from Linear");
469
+ console.log(`[Linear Sync] Cancelled task ${existing.swarmId} (stop signal from Linear)`);
470
+ }
471
+ }
472
+ if (sessionId) {
473
+ endAgentSession(sessionId, "Task cancelled by user.", "response").catch((err) => {
474
+ console.error("[Linear Sync] Failed to end session on stop:", err);
475
+ });
476
+ }
477
+ return;
478
+ }
479
+
480
+ if (!issueId || !userMessage) {
481
+ console.log("[Linear Sync] Prompted event missing issue ID or message, skipping");
482
+ return;
483
+ }
484
+
485
+ // Look up existing tracker_sync for this issue
486
+ const existing = getTrackerSyncByExternalId("linear", "task", issueId);
487
+
488
+ if (existing) {
489
+ const existingTask = getTaskById(existing.swarmId);
490
+
491
+ // If the task is still in progress, acknowledge but don't create a new one
492
+ if (existingTask && !["completed", "failed", "cancelled"].includes(existingTask.status)) {
493
+ console.log(`[Linear Sync] Prompted on in-progress task ${existing.swarmId}, acknowledging`);
494
+ if (sessionId) {
495
+ postAgentSessionThought(
496
+ sessionId,
497
+ "Message received, but the agent is currently working on this task. Your message will be considered when possible.",
498
+ ).catch((err) => {
499
+ console.error("[Linear Sync] Failed to post thought for prompted event:", err);
500
+ });
501
+ }
502
+ return;
503
+ }
504
+ }
505
+
506
+ // Task is completed/failed/cancelled or doesn't exist — create a new follow-up task
507
+ const lead = findLeadAgent();
508
+
509
+ const followupResult = resolveTemplate("linear.issue.followup", {
510
+ issue_identifier: issueIdentifier,
511
+ issue_title: issueTitle,
512
+ issue_url: issueUrl,
513
+ user_message: userMessage,
514
+ });
515
+
516
+ if (followupResult.skipped) {
517
+ return;
518
+ }
519
+
520
+ const task = createTaskExtended(followupResult.text, {
521
+ agentId: lead?.id ?? "",
522
+ source: "linear",
523
+ taskType: "linear-issue",
524
+ });
525
+
526
+ // Repoint the existing tracker_sync to the new follow-up task (can't create a
527
+ // duplicate due to UNIQUE(provider, entityType, externalId) constraint)
528
+ if (existing) {
529
+ deleteTrackerSync(existing.id);
530
+ }
531
+ createTrackerSync({
532
+ provider: "linear",
533
+ entityType: "task",
534
+ providerEntityType: "Issue",
535
+ swarmId: task.id,
536
+ externalId: issueId,
537
+ externalIdentifier: issueIdentifier,
538
+ externalUrl: issueUrl,
539
+ lastSyncOrigin: "external",
540
+ syncDirection: "inbound",
541
+ });
542
+
543
+ // Track session and acknowledge
544
+ if (sessionId) {
545
+ taskSessionMap.set(task.id, sessionId);
546
+ acknowledgeAgentSession(
547
+ sessionId,
548
+ `Follow-up task created (${task.id}). Processing your message...`,
549
+ ).catch((err) => {
550
+ console.error("[Linear Sync] Failed to acknowledge prompted AgentSession:", err);
551
+ });
552
+
553
+ // Set externalUrls for the follow-up task
554
+ const dashboardUrl = process.env.SWARM_DASHBOARD_URL || process.env.APP_URL;
555
+ if (dashboardUrl) {
556
+ updateAgentSessionExternalUrls(sessionId, [
557
+ { label: "View in Agent Swarm", url: `${dashboardUrl}/tasks/${task.id}` },
558
+ ]).catch((err) => {
559
+ console.error("[Linear Sync] Failed to set externalUrls on prompted AgentSession:", err);
560
+ });
561
+ }
562
+ }
563
+
564
+ console.log(
565
+ `[Linear Sync] Created follow-up task ${task.id} for ${issueIdentifier} (prompted) -> ${lead?.name ?? "unassigned"}`,
566
+ );
567
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Linear event prompt template definitions.
3
+ *
4
+ * Each template is registered at module load time via registerTemplate().
5
+ * Handlers import this module for the side-effect of registration.
6
+ */
7
+
8
+ import { registerTemplate } from "../prompts/registry";
9
+
10
+ // ============================================================================
11
+ // Issue events
12
+ // ============================================================================
13
+
14
+ registerTemplate({
15
+ eventType: "linear.issue.assigned",
16
+ header: "[Linear {{issue_identifier}}] {{issue_title}}",
17
+ defaultBody: `Source: Linear (Agent Session)
18
+ URL: {{issue_url}}{{session_section}}
19
+ {{description_section}}`,
20
+ variables: [
21
+ { name: "issue_identifier", description: "Linear issue identifier (e.g. ENG-123)" },
22
+ { name: "issue_title", description: "Issue title" },
23
+ { name: "issue_url", description: "Issue URL on Linear" },
24
+ { name: "session_section", description: "Session URL line or empty string" },
25
+ { name: "description_section", description: "Description section or empty string" },
26
+ ],
27
+ category: "event",
28
+ });
29
+
30
+ registerTemplate({
31
+ eventType: "linear.issue.followup",
32
+ header: "[Linear {{issue_identifier}}] Follow-up: {{issue_title}}",
33
+ defaultBody: `Source: Linear (Agent Session follow-up)
34
+ URL: {{issue_url}}
35
+
36
+ User message:
37
+ {{user_message}}
38
+
39
+ Original issue: {{issue_identifier}} \u2014 {{issue_title}}`,
40
+ variables: [
41
+ { name: "issue_identifier", description: "Linear issue identifier (e.g. ENG-123)" },
42
+ { name: "issue_title", description: "Issue title" },
43
+ { name: "issue_url", description: "Issue URL on Linear" },
44
+ { name: "user_message", description: "Follow-up message from user" },
45
+ ],
46
+ category: "event",
47
+ });
@@ -0,0 +1,7 @@
1
+ export interface LinearTokenResponse {
2
+ access_token: string;
3
+ token_type: string;
4
+ expires_in: number;
5
+ scope: string;
6
+ refresh_token?: string;
7
+ }