@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,230 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { closeDb, initDb } from "../be/db";
4
+ import {
5
+ createTrackerAgentMapping,
6
+ createTrackerSync,
7
+ deleteTrackerAgentMapping,
8
+ deleteTrackerSync,
9
+ getAllTrackerAgentMappings,
10
+ getAllTrackerSyncs,
11
+ getTrackerAgentMapping,
12
+ getTrackerAgentMappingByExternalUser,
13
+ getTrackerSync,
14
+ getTrackerSyncByExternalId,
15
+ updateTrackerSync,
16
+ } from "../be/db-queries/tracker";
17
+
18
+ const TEST_DB_PATH = "./test-db-queries-tracker.sqlite";
19
+
20
+ beforeAll(() => {
21
+ initDb(TEST_DB_PATH);
22
+ });
23
+
24
+ afterAll(async () => {
25
+ closeDb();
26
+ await unlink(TEST_DB_PATH).catch(() => {});
27
+ await unlink(`${TEST_DB_PATH}-wal`).catch(() => {});
28
+ await unlink(`${TEST_DB_PATH}-shm`).catch(() => {});
29
+ });
30
+
31
+ describe("Tracker Sync CRUD", () => {
32
+ test("getTrackerSync returns null for unknown mapping", () => {
33
+ expect(getTrackerSync("linear", "task", "nonexistent")).toBeNull();
34
+ });
35
+
36
+ test("createTrackerSync creates a mapping", () => {
37
+ const sync = createTrackerSync({
38
+ provider: "linear",
39
+ entityType: "task",
40
+ swarmId: "task-001",
41
+ externalId: "LIN-123",
42
+ externalIdentifier: "ENG-42",
43
+ externalUrl: "https://linear.app/team/ENG-42",
44
+ syncDirection: "inbound",
45
+ });
46
+
47
+ expect(sync.id).toBeDefined();
48
+ expect(sync.provider).toBe("linear");
49
+ expect(sync.entityType).toBe("task");
50
+ expect(sync.swarmId).toBe("task-001");
51
+ expect(sync.externalId).toBe("LIN-123");
52
+ expect(sync.externalIdentifier).toBe("ENG-42");
53
+ expect(sync.externalUrl).toBe("https://linear.app/team/ENG-42");
54
+ expect(sync.syncDirection).toBe("inbound");
55
+ expect(sync.lastSyncOrigin).toBeNull();
56
+ });
57
+
58
+ test("getTrackerSync retrieves by swarmId", () => {
59
+ const sync = getTrackerSync("linear", "task", "task-001");
60
+ expect(sync).not.toBeNull();
61
+ expect(sync!.externalId).toBe("LIN-123");
62
+ });
63
+
64
+ test("getTrackerSyncByExternalId retrieves by externalId", () => {
65
+ const sync = getTrackerSyncByExternalId("linear", "task", "LIN-123");
66
+ expect(sync).not.toBeNull();
67
+ expect(sync!.swarmId).toBe("task-001");
68
+ });
69
+
70
+ test("updateTrackerSync updates fields", () => {
71
+ const sync = getTrackerSync("linear", "task", "task-001")!;
72
+ updateTrackerSync(sync.id, {
73
+ lastSyncOrigin: "external",
74
+ lastDeliveryId: "delivery-abc",
75
+ syncDirection: "bidirectional",
76
+ });
77
+
78
+ const updated = getTrackerSync("linear", "task", "task-001")!;
79
+ expect(updated.lastSyncOrigin).toBe("external");
80
+ expect(updated.lastDeliveryId).toBe("delivery-abc");
81
+ expect(updated.syncDirection).toBe("bidirectional");
82
+ });
83
+
84
+ test("createTrackerSync enforces unique(provider, entityType, swarmId)", () => {
85
+ expect(() =>
86
+ createTrackerSync({
87
+ provider: "linear",
88
+ entityType: "task",
89
+ swarmId: "task-001",
90
+ externalId: "LIN-999",
91
+ }),
92
+ ).toThrow();
93
+ });
94
+
95
+ test("createTrackerSync enforces unique(provider, entityType, externalId)", () => {
96
+ expect(() =>
97
+ createTrackerSync({
98
+ provider: "linear",
99
+ entityType: "task",
100
+ swarmId: "task-999",
101
+ externalId: "LIN-123",
102
+ }),
103
+ ).toThrow();
104
+ });
105
+
106
+ test("same externalId allowed for different entityTypes", () => {
107
+ const epic = createTrackerSync({
108
+ provider: "linear",
109
+ entityType: "epic",
110
+ swarmId: "epic-001",
111
+ externalId: "LIN-123",
112
+ });
113
+ expect(epic.entityType).toBe("epic");
114
+ });
115
+
116
+ test("same swarmId allowed for different providers", () => {
117
+ const jiraSync = createTrackerSync({
118
+ provider: "jira" as "linear", // cast for test — DB doesn't constrain provider values
119
+ entityType: "task",
120
+ swarmId: "task-001",
121
+ externalId: "JIRA-456",
122
+ });
123
+ expect(jiraSync.provider).toBe("jira");
124
+ });
125
+
126
+ test("getAllTrackerSyncs returns all", () => {
127
+ const all = getAllTrackerSyncs();
128
+ expect(all.length).toBeGreaterThanOrEqual(3);
129
+ });
130
+
131
+ test("getAllTrackerSyncs filters by provider", () => {
132
+ const linear = getAllTrackerSyncs("linear");
133
+ const jira = getAllTrackerSyncs("jira");
134
+ expect(linear.length).toBeGreaterThanOrEqual(2);
135
+ expect(jira.length).toBe(1);
136
+ });
137
+
138
+ test("getAllTrackerSyncs filters by entityType", () => {
139
+ const tasks = getAllTrackerSyncs(undefined, "task");
140
+ const epics = getAllTrackerSyncs(undefined, "epic");
141
+ expect(tasks.length).toBeGreaterThanOrEqual(2);
142
+ expect(epics.length).toBeGreaterThanOrEqual(1);
143
+ });
144
+
145
+ test("deleteTrackerSync removes the mapping", () => {
146
+ const sync = getTrackerSyncByExternalId("jira", "task", "JIRA-456")!;
147
+ deleteTrackerSync(sync.id);
148
+ expect(getTrackerSyncByExternalId("jira", "task", "JIRA-456")).toBeNull();
149
+ });
150
+ });
151
+
152
+ describe("Tracker Agent Mapping CRUD", () => {
153
+ test("getTrackerAgentMapping returns null for unknown", () => {
154
+ expect(getTrackerAgentMapping("linear", "nonexistent")).toBeNull();
155
+ });
156
+
157
+ test("createTrackerAgentMapping creates a mapping", () => {
158
+ const mapping = createTrackerAgentMapping({
159
+ provider: "linear",
160
+ agentId: "agent-001",
161
+ externalUserId: "lin-user-abc",
162
+ agentName: "Coder Agent",
163
+ });
164
+
165
+ expect(mapping.id).toBeDefined();
166
+ expect(mapping.provider).toBe("linear");
167
+ expect(mapping.agentId).toBe("agent-001");
168
+ expect(mapping.externalUserId).toBe("lin-user-abc");
169
+ expect(mapping.agentName).toBe("Coder Agent");
170
+ });
171
+
172
+ test("getTrackerAgentMapping retrieves by agentId", () => {
173
+ const mapping = getTrackerAgentMapping("linear", "agent-001");
174
+ expect(mapping).not.toBeNull();
175
+ expect(mapping!.externalUserId).toBe("lin-user-abc");
176
+ });
177
+
178
+ test("getTrackerAgentMappingByExternalUser retrieves by externalUserId", () => {
179
+ const mapping = getTrackerAgentMappingByExternalUser("linear", "lin-user-abc");
180
+ expect(mapping).not.toBeNull();
181
+ expect(mapping!.agentId).toBe("agent-001");
182
+ });
183
+
184
+ test("enforces unique(provider, agentId)", () => {
185
+ expect(() =>
186
+ createTrackerAgentMapping({
187
+ provider: "linear",
188
+ agentId: "agent-001",
189
+ externalUserId: "lin-user-xyz",
190
+ agentName: "Duplicate",
191
+ }),
192
+ ).toThrow();
193
+ });
194
+
195
+ test("enforces unique(provider, externalUserId)", () => {
196
+ expect(() =>
197
+ createTrackerAgentMapping({
198
+ provider: "linear",
199
+ agentId: "agent-002",
200
+ externalUserId: "lin-user-abc",
201
+ agentName: "Duplicate",
202
+ }),
203
+ ).toThrow();
204
+ });
205
+
206
+ test("same agentId allowed for different providers", () => {
207
+ const jiraMapping = createTrackerAgentMapping({
208
+ provider: "jira" as "linear",
209
+ agentId: "agent-001",
210
+ externalUserId: "jira-user-abc",
211
+ agentName: "Coder Agent",
212
+ });
213
+ expect(jiraMapping.provider).toBe("jira");
214
+ });
215
+
216
+ test("getAllTrackerAgentMappings returns all", () => {
217
+ const all = getAllTrackerAgentMappings();
218
+ expect(all.length).toBeGreaterThanOrEqual(2);
219
+ });
220
+
221
+ test("getAllTrackerAgentMappings filters by provider", () => {
222
+ const linear = getAllTrackerAgentMappings("linear");
223
+ expect(linear.length).toBe(1);
224
+ });
225
+
226
+ test("deleteTrackerAgentMapping removes the mapping", () => {
227
+ deleteTrackerAgentMapping("jira", "agent-001");
228
+ expect(getTrackerAgentMapping("jira", "agent-001")).toBeNull();
229
+ });
230
+ });
@@ -92,8 +92,8 @@ describe("Epics Integration", () => {
92
92
  leadAgentId: leadAgent.id,
93
93
  researchDocPath: "/thoughts/research/test.md",
94
94
  planDocPath: "/thoughts/plans/test.md",
95
- githubRepo: "desplega-ai/agent-swarm",
96
- githubMilestone: "v1.0",
95
+ vcsRepo: "desplega-ai/agent-swarm",
96
+ vcsMilestone: "v1.0",
97
97
  });
98
98
 
99
99
  expect(epic.id).toBeDefined();
@@ -107,7 +107,7 @@ describe("Epics Integration", () => {
107
107
  expect(epic.createdByAgentId).toBe(testAgent.id);
108
108
  expect(epic.leadAgentId).toBe(leadAgent.id);
109
109
  expect(epic.researchDocPath).toBe("/thoughts/research/test.md");
110
- expect(epic.githubRepo).toBe("desplega-ai/agent-swarm");
110
+ expect(epic.vcsRepo).toBe("desplega-ai/agent-swarm");
111
111
  });
112
112
 
113
113
  test("should auto-create a channel when creating an epic", () => {
@@ -0,0 +1,368 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ parseStderrForErrors,
4
+ SessionErrorTracker,
5
+ trackErrorFromJson,
6
+ } from "../utils/error-tracker";
7
+
8
+ describe("SessionErrorTracker", () => {
9
+ test("hasErrors returns false when no errors tracked", () => {
10
+ const tracker = new SessionErrorTracker();
11
+ expect(tracker.hasErrors()).toBe(false);
12
+ expect(tracker.getErrors()).toHaveLength(0);
13
+ });
14
+
15
+ test("addApiError tracks an API error", () => {
16
+ const tracker = new SessionErrorTracker();
17
+ tracker.addApiError("rate_limit", "Rate limit exceeded");
18
+
19
+ expect(tracker.hasErrors()).toBe(true);
20
+ const errors = tracker.getErrors();
21
+ expect(errors).toHaveLength(1);
22
+ expect(errors[0]!.type).toBe("api_error");
23
+ expect(errors[0]!.errorCategory).toBe("rate_limit");
24
+ expect(errors[0]!.message).toBe("Rate limit exceeded");
25
+ expect(errors[0]!.timestamp).toBeTruthy();
26
+ });
27
+
28
+ test("addResultError tracks multiple error messages", () => {
29
+ const tracker = new SessionErrorTracker();
30
+ tracker.addResultError("error_max_turns", ["Turn limit reached", "Session ended"]);
31
+
32
+ expect(tracker.getErrors()).toHaveLength(2);
33
+ expect(tracker.getErrors()[0]!.type).toBe("result_error");
34
+ expect(tracker.getErrors()[0]!.errorCategory).toBe("error_max_turns");
35
+ expect(tracker.getErrors()[0]!.message).toBe("Turn limit reached");
36
+ expect(tracker.getErrors()[1]!.message).toBe("Session ended");
37
+ });
38
+
39
+ test("addErrorEvent tracks an error event", () => {
40
+ const tracker = new SessionErrorTracker();
41
+ tracker.addErrorEvent("Something went wrong");
42
+
43
+ const errors = tracker.getErrors();
44
+ expect(errors).toHaveLength(1);
45
+ expect(errors[0]!.type).toBe("api_error");
46
+ expect(errors[0]!.message).toBe("Something went wrong");
47
+ expect(errors[0]!.errorCategory).toBeUndefined();
48
+ });
49
+
50
+ test("addStderrError tracks a stderr error", () => {
51
+ const tracker = new SessionErrorTracker();
52
+ tracker.addStderrError("fatal: connection refused");
53
+
54
+ const errors = tracker.getErrors();
55
+ expect(errors).toHaveLength(1);
56
+ expect(errors[0]!.type).toBe("stderr_error");
57
+ expect(errors[0]!.message).toBe("fatal: connection refused");
58
+ });
59
+ });
60
+
61
+ describe("buildFailureReason", () => {
62
+ test("returns generic message when no errors", () => {
63
+ const tracker = new SessionErrorTracker();
64
+ expect(tracker.buildFailureReason(1)).toBe("Claude process exited with code 1");
65
+ });
66
+
67
+ test("returns rate limit message", () => {
68
+ const tracker = new SessionErrorTracker();
69
+ tracker.addApiError("rate_limit", "Too many requests");
70
+ expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Too many requests");
71
+ });
72
+
73
+ test("returns authentication failed message", () => {
74
+ const tracker = new SessionErrorTracker();
75
+ tracker.addApiError("authentication_failed", "Invalid API key");
76
+ expect(tracker.buildFailureReason(1)).toBe("Authentication failed: Invalid API key");
77
+ });
78
+
79
+ test("returns billing error message", () => {
80
+ const tracker = new SessionErrorTracker();
81
+ tracker.addApiError("billing_error", "Insufficient funds");
82
+ expect(tracker.buildFailureReason(1)).toBe("Billing error: Insufficient funds");
83
+ });
84
+
85
+ test("returns server error message", () => {
86
+ const tracker = new SessionErrorTracker();
87
+ tracker.addApiError("server_error", "Service unavailable");
88
+ expect(tracker.buildFailureReason(1)).toBe(
89
+ "Server error (API overloaded): Service unavailable",
90
+ );
91
+ });
92
+
93
+ test("returns max turns exceeded for result errors", () => {
94
+ const tracker = new SessionErrorTracker();
95
+ tracker.addResultError("error_max_turns", ["Reached 50 turns"]);
96
+ expect(tracker.buildFailureReason(1)).toBe("Max turns exceeded: Reached 50 turns");
97
+ });
98
+
99
+ test("returns budget limit exceeded for result errors", () => {
100
+ const tracker = new SessionErrorTracker();
101
+ tracker.addResultError("error_max_budget_usd", ["$5.00 limit reached"]);
102
+ expect(tracker.buildFailureReason(1)).toBe("Budget limit exceeded: $5.00 limit reached");
103
+ });
104
+
105
+ test("returns error during execution for result errors", () => {
106
+ const tracker = new SessionErrorTracker();
107
+ tracker.addResultError("error_during_execution", ["Process crashed"]);
108
+ expect(tracker.buildFailureReason(1)).toBe("Error during execution: Process crashed");
109
+ });
110
+
111
+ test("returns generic session error for unknown result subtype", () => {
112
+ const tracker = new SessionErrorTracker();
113
+ tracker.addResultError("unknown_subtype", ["Something odd"]);
114
+ expect(tracker.buildFailureReason(2)).toBe("Session error (exit code 2): Something odd");
115
+ });
116
+
117
+ test("falls back to session error when only stderr errors present", () => {
118
+ const tracker = new SessionErrorTracker();
119
+ tracker.addStderrError("segfault");
120
+ expect(tracker.buildFailureReason(139)).toBe("Session error (exit code 139): segfault");
121
+ });
122
+
123
+ test("falls back to session error for error events without category", () => {
124
+ const tracker = new SessionErrorTracker();
125
+ tracker.addErrorEvent("connection timeout");
126
+ expect(tracker.buildFailureReason(1)).toBe("Session error (exit code 1): connection timeout");
127
+ });
128
+
129
+ test("shows count of additional errors when multiple unique messages", () => {
130
+ const tracker = new SessionErrorTracker();
131
+ tracker.addApiError("rate_limit", "Error one");
132
+ tracker.addApiError("rate_limit", "Error two");
133
+ tracker.addApiError("rate_limit", "Error three");
134
+ expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Error one (+2 more error(s))");
135
+ });
136
+
137
+ test("deduplicates identical error messages in count", () => {
138
+ const tracker = new SessionErrorTracker();
139
+ tracker.addApiError("rate_limit", "Same error");
140
+ tracker.addApiError("rate_limit", "Same error");
141
+ tracker.addApiError("rate_limit", "Different error");
142
+ expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Same error (+1 more error(s))");
143
+ });
144
+
145
+ test("uses first api error category as primary", () => {
146
+ const tracker = new SessionErrorTracker();
147
+ tracker.addApiError("rate_limit", "Rate limited");
148
+ tracker.addApiError("server_error", "Server down");
149
+ // First category (rate_limit) wins
150
+ expect(tracker.buildFailureReason(1)).toBe("Rate limit hit: Rate limited (+1 more error(s))");
151
+ });
152
+ });
153
+
154
+ describe("trackErrorFromJson", () => {
155
+ test("tracks assistant message with API error", () => {
156
+ const tracker = new SessionErrorTracker();
157
+ trackErrorFromJson(
158
+ {
159
+ type: "assistant",
160
+ message: {
161
+ error: "rate_limit",
162
+ content: [{ text: "Rate limit exceeded, please retry" }],
163
+ },
164
+ },
165
+ tracker,
166
+ );
167
+
168
+ const errors = tracker.getErrors();
169
+ expect(errors).toHaveLength(1);
170
+ expect(errors[0]!.type).toBe("api_error");
171
+ expect(errors[0]!.errorCategory).toBe("rate_limit");
172
+ expect(errors[0]!.message).toBe("Rate limit exceeded, please retry");
173
+ });
174
+
175
+ test("tracks assistant message error with no content, falls back to error string", () => {
176
+ const tracker = new SessionErrorTracker();
177
+ trackErrorFromJson(
178
+ {
179
+ type: "assistant",
180
+ message: { error: "server_error" },
181
+ },
182
+ tracker,
183
+ );
184
+
185
+ const errors = tracker.getErrors();
186
+ expect(errors).toHaveLength(1);
187
+ expect(errors[0]!.message).toBe("server_error");
188
+ });
189
+
190
+ test("ignores assistant messages without error", () => {
191
+ const tracker = new SessionErrorTracker();
192
+ trackErrorFromJson({ type: "assistant", message: { content: [{ text: "Hello" }] } }, tracker);
193
+ expect(tracker.hasErrors()).toBe(false);
194
+ });
195
+
196
+ test("tracks explicit error events", () => {
197
+ const tracker = new SessionErrorTracker();
198
+ trackErrorFromJson({ type: "error", error: "Connection lost" }, tracker);
199
+
200
+ const errors = tracker.getErrors();
201
+ expect(errors).toHaveLength(1);
202
+ expect(errors[0]!.type).toBe("api_error");
203
+ expect(errors[0]!.message).toBe("Connection lost");
204
+ });
205
+
206
+ test("tracks error event with message field fallback", () => {
207
+ const tracker = new SessionErrorTracker();
208
+ trackErrorFromJson({ type: "error", message: "Timeout reached" }, tracker);
209
+
210
+ expect(tracker.getErrors()[0]!.message).toBe("Timeout reached");
211
+ });
212
+
213
+ test("tracks error event with JSON fallback when no error or message", () => {
214
+ const tracker = new SessionErrorTracker();
215
+ trackErrorFromJson({ type: "error" }, tracker);
216
+
217
+ expect(tracker.getErrors()[0]!.message).toBe('{"type":"error"}');
218
+ });
219
+
220
+ test("tracks result events with is_error true", () => {
221
+ const tracker = new SessionErrorTracker();
222
+ trackErrorFromJson(
223
+ {
224
+ type: "result",
225
+ is_error: true,
226
+ subtype: "error_max_turns",
227
+ errors: ["Max turns reached"],
228
+ },
229
+ tracker,
230
+ );
231
+
232
+ const errors = tracker.getErrors();
233
+ expect(errors).toHaveLength(1);
234
+ expect(errors[0]!.type).toBe("result_error");
235
+ expect(errors[0]!.errorCategory).toBe("error_max_turns");
236
+ expect(errors[0]!.message).toBe("Max turns reached");
237
+ });
238
+
239
+ test("tracks result event falling back to result field when no errors array", () => {
240
+ const tracker = new SessionErrorTracker();
241
+ trackErrorFromJson({ type: "result", is_error: true, result: "Something failed" }, tracker);
242
+
243
+ expect(tracker.getErrors()[0]!.message).toBe("Something failed");
244
+ expect(tracker.getErrors()[0]!.errorCategory).toBe("error_during_execution");
245
+ });
246
+
247
+ test("tracks result event with unknown error when no errors or result", () => {
248
+ const tracker = new SessionErrorTracker();
249
+ trackErrorFromJson({ type: "result", is_error: true }, tracker);
250
+
251
+ expect(tracker.getErrors()[0]!.message).toBe("Unknown error");
252
+ });
253
+
254
+ test("ignores result events without is_error", () => {
255
+ const tracker = new SessionErrorTracker();
256
+ trackErrorFromJson({ type: "result", result: "All good" }, tracker);
257
+ expect(tracker.hasErrors()).toBe(false);
258
+ });
259
+
260
+ test("ignores unrelated event types", () => {
261
+ const tracker = new SessionErrorTracker();
262
+ trackErrorFromJson({ type: "content_block_delta", delta: {} }, tracker);
263
+ expect(tracker.hasErrors()).toBe(false);
264
+ });
265
+ });
266
+
267
+ describe("parseStderrForErrors", () => {
268
+ test("ignores empty or whitespace-only stderr", () => {
269
+ const tracker = new SessionErrorTracker();
270
+ parseStderrForErrors("", tracker);
271
+ parseStderrForErrors(" ", tracker);
272
+ expect(tracker.hasErrors()).toBe(false);
273
+ });
274
+
275
+ test("detects rate limit errors", () => {
276
+ const tracker = new SessionErrorTracker();
277
+ parseStderrForErrors("Rate limit exceeded for model", tracker);
278
+
279
+ expect(tracker.getErrors()).toHaveLength(1);
280
+ expect(tracker.getErrors()[0]!.message).toBe("Rate limit exceeded for model");
281
+ });
282
+
283
+ test("detects rate_limit with underscore", () => {
284
+ const tracker = new SessionErrorTracker();
285
+ parseStderrForErrors("rate_limit: too many requests", tracker);
286
+
287
+ expect(tracker.hasErrors()).toBe(true);
288
+ });
289
+
290
+ test("detects 429 status code", () => {
291
+ const tracker = new SessionErrorTracker();
292
+ parseStderrForErrors("HTTP 429 Too Many Requests", tracker);
293
+
294
+ expect(tracker.hasErrors()).toBe(true);
295
+ });
296
+
297
+ test("detects authentication errors", () => {
298
+ const tracker = new SessionErrorTracker();
299
+ parseStderrForErrors("Authentication failed: invalid key", tracker);
300
+
301
+ expect(tracker.getErrors()[0]!.message).toBe(
302
+ "Authentication error: Authentication failed: invalid key",
303
+ );
304
+ });
305
+
306
+ test("detects unauthorized errors", () => {
307
+ const tracker = new SessionErrorTracker();
308
+ parseStderrForErrors("Unauthorized access attempt", tracker);
309
+
310
+ expect(tracker.getErrors()[0]!.message).toContain("Authentication error:");
311
+ });
312
+
313
+ test("detects 401 status code", () => {
314
+ const tracker = new SessionErrorTracker();
315
+ parseStderrForErrors("HTTP 401 Unauthorized", tracker);
316
+
317
+ expect(tracker.getErrors()[0]!.message).toContain("Authentication error:");
318
+ });
319
+
320
+ test("detects billing errors", () => {
321
+ const tracker = new SessionErrorTracker();
322
+ parseStderrForErrors("Billing account suspended", tracker);
323
+
324
+ expect(tracker.getErrors()[0]!.message).toContain("Billing error:");
325
+ });
326
+
327
+ test("detects payment errors", () => {
328
+ const tracker = new SessionErrorTracker();
329
+ parseStderrForErrors("Payment method declined", tracker);
330
+
331
+ expect(tracker.getErrors()[0]!.message).toContain("Billing error:");
332
+ });
333
+
334
+ test("detects generic error keyword", () => {
335
+ const tracker = new SessionErrorTracker();
336
+ parseStderrForErrors("Error: ECONNREFUSED", tracker);
337
+
338
+ expect(tracker.getErrors()[0]!.message).toBe("Error: ECONNREFUSED");
339
+ });
340
+
341
+ test("detects fatal keyword", () => {
342
+ const tracker = new SessionErrorTracker();
343
+ parseStderrForErrors("fatal: unable to access remote", tracker);
344
+
345
+ expect(tracker.getErrors()[0]!.message).toBe("fatal: unable to access remote");
346
+ });
347
+
348
+ test("detects panic keyword", () => {
349
+ const tracker = new SessionErrorTracker();
350
+ parseStderrForErrors("panic: runtime error: index out of range", tracker);
351
+
352
+ expect(tracker.getErrors()[0]!.message).toBe("panic: runtime error: index out of range");
353
+ });
354
+
355
+ test("uses only first line of multiline stderr", () => {
356
+ const tracker = new SessionErrorTracker();
357
+ parseStderrForErrors("Error: something broke\n at function.js:10\n at main.js:5", tracker);
358
+
359
+ expect(tracker.getErrors()[0]!.message).toBe("Error: something broke");
360
+ });
361
+
362
+ test("ignores stderr without recognized error patterns", () => {
363
+ const tracker = new SessionErrorTracker();
364
+ parseStderrForErrors("Debugger attached.\nWaiting for connections...", tracker);
365
+
366
+ expect(tracker.hasErrors()).toBe(false);
367
+ });
368
+ });