@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,737 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { chunkContent } from "../be/chunking";
4
+ import {
5
+ closeDb,
6
+ createAgent,
7
+ createMemory,
8
+ deleteMemoriesBySourcePath,
9
+ deleteMemory,
10
+ getDb,
11
+ getMemoryById,
12
+ getMemoryStats,
13
+ initDb,
14
+ listMemoriesByAgent,
15
+ searchMemoriesByVector,
16
+ updateMemoryEmbedding,
17
+ } from "../be/db";
18
+ import { cosineSimilarity, deserializeEmbedding, serializeEmbedding } from "../be/embedding";
19
+
20
+ const TEST_DB_PATH = "./test-memory.sqlite";
21
+
22
+ describe("Memory System", () => {
23
+ const agentA = "aaaa0000-0000-4000-8000-000000000001";
24
+ const agentB = "bbbb0000-0000-4000-8000-000000000002";
25
+
26
+ beforeAll(async () => {
27
+ for (const suffix of ["", "-wal", "-shm"]) {
28
+ try {
29
+ await unlink(TEST_DB_PATH + suffix);
30
+ } catch {
31
+ // File doesn't exist
32
+ }
33
+ }
34
+
35
+ initDb(TEST_DB_PATH);
36
+
37
+ createAgent({ id: agentA, name: "Agent A", isLead: false, status: "idle" });
38
+ createAgent({ id: agentB, name: "Agent B", isLead: true, status: "idle" });
39
+ });
40
+
41
+ afterAll(async () => {
42
+ closeDb();
43
+ for (const suffix of ["", "-wal", "-shm"]) {
44
+ try {
45
+ await unlink(TEST_DB_PATH + suffix);
46
+ } catch {
47
+ // File doesn't exist
48
+ }
49
+ }
50
+ });
51
+
52
+ // ==========================================================================
53
+ // Embedding utility tests
54
+ // ==========================================================================
55
+
56
+ describe("cosineSimilarity", () => {
57
+ test("identical vectors return 1", () => {
58
+ const a = new Float32Array([1, 2, 3]);
59
+ const b = new Float32Array([1, 2, 3]);
60
+ expect(cosineSimilarity(a, b)).toBeCloseTo(1.0, 5);
61
+ });
62
+
63
+ test("opposite vectors return -1", () => {
64
+ const a = new Float32Array([1, 0, 0]);
65
+ const b = new Float32Array([-1, 0, 0]);
66
+ expect(cosineSimilarity(a, b)).toBeCloseTo(-1.0, 5);
67
+ });
68
+
69
+ test("orthogonal vectors return 0", () => {
70
+ const a = new Float32Array([1, 0, 0]);
71
+ const b = new Float32Array([0, 1, 0]);
72
+ expect(cosineSimilarity(a, b)).toBeCloseTo(0.0, 5);
73
+ });
74
+
75
+ test("throws on different lengths", () => {
76
+ const a = new Float32Array([1, 2]);
77
+ const b = new Float32Array([1, 2, 3]);
78
+ expect(() => cosineSimilarity(a, b)).toThrow("same length");
79
+ });
80
+
81
+ test("zero vectors return 0", () => {
82
+ const a = new Float32Array([0, 0, 0]);
83
+ const b = new Float32Array([1, 2, 3]);
84
+ expect(cosineSimilarity(a, b)).toBe(0);
85
+ });
86
+
87
+ test("empty vectors return 0", () => {
88
+ const a = new Float32Array([]);
89
+ const b = new Float32Array([]);
90
+ expect(cosineSimilarity(a, b)).toBe(0);
91
+ });
92
+ });
93
+
94
+ describe("serializeEmbedding / deserializeEmbedding", () => {
95
+ test("roundtrip preserves values", () => {
96
+ const original = new Float32Array([0.1, -0.5, 3.14, 0, -1.0]);
97
+ const buffer = serializeEmbedding(original);
98
+ const restored = deserializeEmbedding(buffer);
99
+ expect(restored.length).toBe(original.length);
100
+ for (let i = 0; i < original.length; i++) {
101
+ expect(restored[i]).toBeCloseTo(original[i], 5);
102
+ }
103
+ });
104
+
105
+ test("roundtrip with 512-dim vector", () => {
106
+ const original = new Float32Array(512);
107
+ for (let i = 0; i < 512; i++) {
108
+ original[i] = Math.random() * 2 - 1;
109
+ }
110
+ const buffer = serializeEmbedding(original);
111
+ expect(buffer.length).toBe(512 * 4); // 4 bytes per float32
112
+ const restored = deserializeEmbedding(buffer);
113
+ expect(restored.length).toBe(512);
114
+ for (let i = 0; i < 512; i++) {
115
+ expect(restored[i]).toBeCloseTo(original[i], 5);
116
+ }
117
+ });
118
+ });
119
+
120
+ // ==========================================================================
121
+ // Chunking tests
122
+ // ==========================================================================
123
+
124
+ describe("chunkContent", () => {
125
+ test("small text returns single chunk", () => {
126
+ const text =
127
+ "Hello, this is a short text that is long enough to pass the minimum chunk size threshold for testing.";
128
+ const chunks = chunkContent(text);
129
+ expect(chunks.length).toBe(1);
130
+ expect(chunks[0]!.chunkIndex).toBe(0);
131
+ expect(chunks[0]!.totalChunks).toBe(1);
132
+ expect(chunks[0]!.content).toBe(text);
133
+ });
134
+
135
+ test("empty text returns empty array", () => {
136
+ expect(chunkContent("")).toEqual([]);
137
+ expect(chunkContent(" ")).toEqual([]);
138
+ });
139
+
140
+ test("text under MIN_CHUNK_SIZE returns empty array", () => {
141
+ expect(chunkContent("Hi")).toEqual([]);
142
+ });
143
+
144
+ test("splits on markdown headers", () => {
145
+ // Each section needs enough content to pass MIN_CHUNK_SIZE, and total must exceed MAX_CHUNK_SIZE (2000)
146
+ const sectionContent =
147
+ "This is a detailed paragraph with important technical content. ".repeat(20);
148
+ const content = [
149
+ "# Title",
150
+ "",
151
+ sectionContent,
152
+ "",
153
+ "## Section One",
154
+ "",
155
+ `Content of section one: ${sectionContent}`,
156
+ "",
157
+ "## Section Two",
158
+ "",
159
+ `Content of section two: ${sectionContent}`,
160
+ ].join("\n");
161
+
162
+ expect(content.length).toBeGreaterThan(2000);
163
+ const chunks = chunkContent(content);
164
+ expect(chunks.length).toBeGreaterThanOrEqual(2);
165
+
166
+ // Check that headings are preserved as prefixes
167
+ const sectionOneChunk = chunks.find((c) => c.content.includes("section one"));
168
+ expect(sectionOneChunk).toBeDefined();
169
+ });
170
+
171
+ test("splits oversized sections recursively", () => {
172
+ // Create a section longer than MAX_CHUNK_SIZE (2000 chars)
173
+ const longParagraph = "This is a sentence that contributes to a very long paragraph. ".repeat(
174
+ 50,
175
+ );
176
+ const chunks = chunkContent(longParagraph);
177
+ expect(chunks.length).toBeGreaterThan(1);
178
+
179
+ // All chunks should be reasonably sized
180
+ for (const chunk of chunks) {
181
+ // Allow some slack for overlap
182
+ expect(chunk.content.length).toBeLessThanOrEqual(2200);
183
+ }
184
+ });
185
+
186
+ test("includes heading hierarchy as prefix", () => {
187
+ const content = [
188
+ "# Main Title",
189
+ "",
190
+ "## Sub Section",
191
+ "",
192
+ "Content under sub section that needs to be long enough to pass the minimum chunk size filter for proper testing.",
193
+ ].join("\n");
194
+
195
+ const chunks = chunkContent(content);
196
+ const subSectionChunk = chunks.find((c) => c.content.includes("Content under sub section"));
197
+ expect(subSectionChunk).toBeDefined();
198
+ if (subSectionChunk) {
199
+ expect(subSectionChunk.content).toContain("# Main Title");
200
+ expect(subSectionChunk.content).toContain("## Sub Section");
201
+ }
202
+ });
203
+
204
+ test("chunk indices are sequential", () => {
205
+ const longText = "A ".repeat(3000);
206
+ const chunks = chunkContent(longText);
207
+ for (let i = 0; i < chunks.length; i++) {
208
+ expect(chunks[i].chunkIndex).toBe(i);
209
+ expect(chunks[i].totalChunks).toBe(chunks.length);
210
+ }
211
+ });
212
+ });
213
+
214
+ // ==========================================================================
215
+ // DB CRUD tests
216
+ // ==========================================================================
217
+
218
+ describe("createMemory", () => {
219
+ test("creates a memory with all fields", () => {
220
+ const memory = createMemory({
221
+ agentId: agentA,
222
+ scope: "agent",
223
+ name: "Test Memory",
224
+ content: "Some important information",
225
+ summary: "A summary",
226
+ source: "manual",
227
+ sourceTaskId: null,
228
+ sourcePath: "/workspace/personal/memory/test.md",
229
+ chunkIndex: 0,
230
+ totalChunks: 1,
231
+ tags: ["test", "important"],
232
+ });
233
+
234
+ expect(memory.id).toBeDefined();
235
+ expect(memory.agentId).toBe(agentA);
236
+ expect(memory.scope).toBe("agent");
237
+ expect(memory.name).toBe("Test Memory");
238
+ expect(memory.content).toBe("Some important information");
239
+ expect(memory.summary).toBe("A summary");
240
+ expect(memory.source).toBe("manual");
241
+ expect(memory.chunkIndex).toBe(0);
242
+ expect(memory.totalChunks).toBe(1);
243
+ expect(memory.tags).toEqual(["test", "important"]);
244
+ expect(memory.createdAt).toBeDefined();
245
+ expect(memory.accessedAt).toBeDefined();
246
+ });
247
+
248
+ test("creates with minimal fields", () => {
249
+ const memory = createMemory({
250
+ scope: "swarm",
251
+ name: "Minimal",
252
+ content: "Just content",
253
+ source: "file_index",
254
+ });
255
+
256
+ expect(memory.agentId).toBeNull();
257
+ expect(memory.summary).toBeNull();
258
+ expect(memory.sourceTaskId).toBeNull();
259
+ expect(memory.sourcePath).toBeNull();
260
+ expect(memory.chunkIndex).toBe(0);
261
+ expect(memory.totalChunks).toBe(1);
262
+ expect(memory.tags).toEqual([]);
263
+ });
264
+ });
265
+
266
+ describe("getMemoryById", () => {
267
+ test("returns existing memory", () => {
268
+ const created = createMemory({
269
+ agentId: agentA,
270
+ scope: "agent",
271
+ name: "Findable",
272
+ content: "Find me",
273
+ source: "manual",
274
+ });
275
+
276
+ const found = getMemoryById(created.id);
277
+ expect(found).not.toBeNull();
278
+ expect(found!.id).toBe(created.id);
279
+ expect(found!.name).toBe("Findable");
280
+ });
281
+
282
+ test("returns null for non-existent ID", () => {
283
+ const found = getMemoryById("00000000-0000-0000-0000-000000000000");
284
+ expect(found).toBeNull();
285
+ });
286
+
287
+ test("updates accessedAt on retrieval", () => {
288
+ const created = createMemory({
289
+ agentId: agentA,
290
+ scope: "agent",
291
+ name: "Access Test",
292
+ content: "Check access time",
293
+ source: "manual",
294
+ });
295
+
296
+ // Force a tiny delay so timestamps differ
297
+ const start = performance.now();
298
+ while (performance.now() - start < 5) {
299
+ /* spin */
300
+ }
301
+
302
+ const found = getMemoryById(created.id);
303
+ expect(found).not.toBeNull();
304
+ // accessedAt should be updated (may or may not differ depending on timing)
305
+ expect(found!.accessedAt).toBeDefined();
306
+ });
307
+ });
308
+
309
+ describe("updateMemoryEmbedding", () => {
310
+ test("stores and retrieves embedding BLOB", () => {
311
+ const memory = createMemory({
312
+ agentId: agentA,
313
+ scope: "agent",
314
+ name: "Embedding Test",
315
+ content: "Vector storage test",
316
+ source: "manual",
317
+ });
318
+
319
+ const embedding = new Float32Array([0.1, 0.2, 0.3, -0.5]);
320
+ updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
321
+
322
+ // Read back the raw row to check embedding
323
+ const { getDb } = require("../be/db");
324
+ const row = getDb()
325
+ .prepare("SELECT embedding FROM agent_memory WHERE id = ?")
326
+ .get(memory.id) as { embedding: Buffer | null };
327
+ expect(row.embedding).not.toBeNull();
328
+
329
+ const restored = deserializeEmbedding(row.embedding!);
330
+ expect(restored.length).toBe(4);
331
+ expect(restored[0]).toBeCloseTo(0.1, 5);
332
+ expect(restored[3]).toBeCloseTo(-0.5, 5);
333
+ });
334
+ });
335
+
336
+ describe("searchMemoriesByVector", () => {
337
+ const searchAgentId = "cccc0000-0000-4000-8000-000000000003";
338
+ const searchAgentId2 = "dddd0000-0000-4000-8000-000000000004";
339
+
340
+ beforeAll(() => {
341
+ createAgent({
342
+ id: searchAgentId,
343
+ name: "Search Agent",
344
+ isLead: false,
345
+ status: "idle",
346
+ });
347
+ createAgent({
348
+ id: searchAgentId2,
349
+ name: "Search Agent 2",
350
+ isLead: false,
351
+ status: "idle",
352
+ });
353
+
354
+ // Create memories with known embeddings
355
+ // Memory 1: agent scope for searchAgentId, embedding [1,0,0]
356
+ const m1 = createMemory({
357
+ agentId: searchAgentId,
358
+ scope: "agent",
359
+ name: "Agent Memory 1",
360
+ content: "Agent-scoped content",
361
+ source: "manual",
362
+ });
363
+ updateMemoryEmbedding(m1.id, serializeEmbedding(new Float32Array([1, 0, 0])));
364
+
365
+ // Memory 2: swarm scope, embedding [0,1,0]
366
+ const m2 = createMemory({
367
+ agentId: searchAgentId,
368
+ scope: "swarm",
369
+ name: "Swarm Memory 1",
370
+ content: "Swarm-scoped content",
371
+ source: "file_index",
372
+ });
373
+ updateMemoryEmbedding(m2.id, serializeEmbedding(new Float32Array([0, 1, 0])));
374
+
375
+ // Memory 3: agent scope for OTHER agent, embedding [0,0,1]
376
+ const m3 = createMemory({
377
+ agentId: searchAgentId2,
378
+ scope: "agent",
379
+ name: "Other Agent Memory",
380
+ content: "Other agent's private memory",
381
+ source: "manual",
382
+ });
383
+ updateMemoryEmbedding(m3.id, serializeEmbedding(new Float32Array([0, 0, 1])));
384
+ });
385
+
386
+ test("worker sees own agent-scoped + swarm memories", () => {
387
+ const query = new Float32Array([1, 0, 0]); // closest to Memory 1
388
+ const results = searchMemoriesByVector(query, searchAgentId, { isLead: false });
389
+ const names = results.map((r) => r.name);
390
+
391
+ expect(names).toContain("Agent Memory 1");
392
+ expect(names).toContain("Swarm Memory 1");
393
+ expect(names).not.toContain("Other Agent Memory");
394
+ });
395
+
396
+ test("worker does not see other agent's agent-scoped memories", () => {
397
+ const query = new Float32Array([0, 0, 1]); // closest to Memory 3
398
+ const results = searchMemoriesByVector(query, searchAgentId, { isLead: false });
399
+ const names = results.map((r) => r.name);
400
+
401
+ expect(names).not.toContain("Other Agent Memory");
402
+ });
403
+
404
+ test("lead sees ALL memories across agents", () => {
405
+ const query = new Float32Array([0, 0, 1]); // closest to Memory 3
406
+ const results = searchMemoriesByVector(query, searchAgentId, { isLead: true });
407
+ const names = results.map((r) => r.name);
408
+
409
+ expect(names).toContain("Other Agent Memory");
410
+ expect(names).toContain("Agent Memory 1");
411
+ expect(names).toContain("Swarm Memory 1");
412
+ });
413
+
414
+ test("results sorted by similarity (highest first)", () => {
415
+ const query = new Float32Array([1, 0, 0]); // identical to Memory 1's embedding
416
+ const results = searchMemoriesByVector(query, searchAgentId, { isLead: true });
417
+
418
+ expect(results.length).toBeGreaterThan(0);
419
+ expect(results[0].name).toBe("Agent Memory 1");
420
+ expect(results[0].similarity).toBeCloseTo(1.0, 3);
421
+
422
+ // Each subsequent result should have lower or equal similarity
423
+ for (let i = 1; i < results.length; i++) {
424
+ expect(results[i].similarity).toBeLessThanOrEqual(results[i - 1].similarity);
425
+ }
426
+ });
427
+
428
+ test("scope filter works", () => {
429
+ const query = new Float32Array([1, 1, 1]);
430
+ const agentOnly = searchMemoriesByVector(query, searchAgentId, {
431
+ scope: "agent",
432
+ isLead: false,
433
+ });
434
+ const swarmOnly = searchMemoriesByVector(query, searchAgentId, {
435
+ scope: "swarm",
436
+ isLead: false,
437
+ });
438
+
439
+ for (const r of agentOnly) {
440
+ expect(r.scope).toBe("agent");
441
+ }
442
+ for (const r of swarmOnly) {
443
+ expect(r.scope).toBe("swarm");
444
+ }
445
+ });
446
+
447
+ test("source filter works", () => {
448
+ const query = new Float32Array([1, 1, 1]);
449
+ const results = searchMemoriesByVector(query, searchAgentId, {
450
+ source: "file_index",
451
+ isLead: true,
452
+ });
453
+
454
+ for (const r of results) {
455
+ expect(r.source).toBe("file_index");
456
+ }
457
+ });
458
+
459
+ test("limit works", () => {
460
+ const query = new Float32Array([1, 1, 1]);
461
+ const results = searchMemoriesByVector(query, searchAgentId, {
462
+ limit: 1,
463
+ isLead: true,
464
+ });
465
+ expect(results.length).toBe(1);
466
+ });
467
+ });
468
+
469
+ describe("listMemoriesByAgent", () => {
470
+ test("lists agent memories with pagination", () => {
471
+ const listAgent = "eeee0000-0000-4000-8000-000000000005";
472
+ createAgent({ id: listAgent, name: "List Agent", isLead: false, status: "idle" });
473
+
474
+ for (let i = 0; i < 5; i++) {
475
+ createMemory({
476
+ agentId: listAgent,
477
+ scope: "agent",
478
+ name: `List Memory ${i}`,
479
+ content: `Content ${i}`,
480
+ source: "manual",
481
+ });
482
+ }
483
+
484
+ const page1 = listMemoriesByAgent(listAgent, { scope: "agent", limit: 3, offset: 0 });
485
+ expect(page1.length).toBe(3);
486
+
487
+ const page2 = listMemoriesByAgent(listAgent, { scope: "agent", limit: 3, offset: 3 });
488
+ expect(page2.length).toBe(2);
489
+ });
490
+ });
491
+
492
+ describe("deleteMemory", () => {
493
+ test("deletes existing memory", () => {
494
+ const memory = createMemory({
495
+ agentId: agentA,
496
+ scope: "agent",
497
+ name: "To Delete",
498
+ content: "Delete me",
499
+ source: "manual",
500
+ });
501
+
502
+ const deleted = deleteMemory(memory.id);
503
+ expect(deleted).toBe(true);
504
+
505
+ const found = getMemoryById(memory.id);
506
+ expect(found).toBeNull();
507
+ });
508
+
509
+ test("returns false for non-existent memory", () => {
510
+ const deleted = deleteMemory("00000000-0000-0000-0000-000000000000");
511
+ expect(deleted).toBe(false);
512
+ });
513
+ });
514
+
515
+ describe("deleteMemoriesBySourcePath", () => {
516
+ test("deletes all chunks for a source path", () => {
517
+ const path = "/workspace/personal/memory/to-reindex.md";
518
+
519
+ // Create multiple chunks
520
+ for (let i = 0; i < 3; i++) {
521
+ createMemory({
522
+ agentId: agentA,
523
+ scope: "agent",
524
+ name: "Reindex Test",
525
+ content: `Chunk ${i}`,
526
+ source: "file_index",
527
+ sourcePath: path,
528
+ chunkIndex: i,
529
+ totalChunks: 3,
530
+ });
531
+ }
532
+
533
+ const deleted = deleteMemoriesBySourcePath(path, agentA);
534
+ expect(deleted).toBe(3);
535
+
536
+ // Verify they're gone
537
+ const remaining = listMemoriesByAgent(agentA).filter((m) => m.sourcePath === path);
538
+ expect(remaining.length).toBe(0);
539
+ });
540
+ });
541
+
542
+ describe("getMemoryStats", () => {
543
+ test("returns correct stats", () => {
544
+ const statsAgent = "ffff0000-0000-4000-8000-000000000006";
545
+ createAgent({ id: statsAgent, name: "Stats Agent", isLead: false, status: "idle" });
546
+
547
+ createMemory({
548
+ agentId: statsAgent,
549
+ scope: "agent",
550
+ name: "Stat 1",
551
+ content: "Content",
552
+ source: "manual",
553
+ });
554
+ createMemory({
555
+ agentId: statsAgent,
556
+ scope: "swarm",
557
+ name: "Stat 2",
558
+ content: "Content",
559
+ source: "file_index",
560
+ });
561
+ createMemory({
562
+ agentId: statsAgent,
563
+ scope: "agent",
564
+ name: "Stat 3",
565
+ content: "Content",
566
+ source: "manual",
567
+ });
568
+
569
+ const stats = getMemoryStats(statsAgent);
570
+ expect(stats.total).toBe(3);
571
+ expect(stats.bySource.manual).toBe(2);
572
+ expect(stats.bySource.file_index).toBe(1);
573
+ expect(stats.byScope.agent).toBe(2);
574
+ expect(stats.byScope.swarm).toBe(1);
575
+ });
576
+ });
577
+
578
+ // ==========================================================================
579
+ // Memory Ingestion API tests (POST /api/memory/index simulation)
580
+ // ==========================================================================
581
+
582
+ describe("memory ingestion (API logic)", () => {
583
+ const ingestAgent = "1111aaaa-0000-4000-8000-000000000007";
584
+
585
+ beforeAll(() => {
586
+ createAgent({ id: ingestAgent, name: "Ingest Agent", isLead: false, status: "idle" });
587
+ });
588
+
589
+ test("creates memory records from content", () => {
590
+ const chunks = chunkContent("Short but sufficient content for a single chunk test memory.");
591
+ // Simulate API: if chunks are empty, create a single memory
592
+ const finalChunks =
593
+ chunks.length > 0
594
+ ? chunks
595
+ : [
596
+ {
597
+ content: "Short but sufficient content for a single chunk test memory.",
598
+ chunkIndex: 0,
599
+ totalChunks: 1,
600
+ headings: [] as string[],
601
+ },
602
+ ];
603
+
604
+ const memoryIds = getDb().transaction(() => {
605
+ const ids: string[] = [];
606
+ for (const chunk of finalChunks) {
607
+ const memory = createMemory({
608
+ agentId: ingestAgent,
609
+ content: chunk.content,
610
+ name: "ingest-test",
611
+ scope: "agent",
612
+ source: "file_index",
613
+ sourcePath: "/workspace/personal/memory/ingest-test.md",
614
+ chunkIndex: chunk.chunkIndex,
615
+ totalChunks: chunk.totalChunks,
616
+ });
617
+ ids.push(memory.id);
618
+ }
619
+ return ids;
620
+ })();
621
+
622
+ expect(memoryIds.length).toBe(1);
623
+ const memory = getMemoryById(memoryIds[0]!);
624
+ expect(memory).not.toBeNull();
625
+ expect(memory!.source).toBe("file_index");
626
+ expect(memory!.sourcePath).toBe("/workspace/personal/memory/ingest-test.md");
627
+ });
628
+
629
+ test("dedup: re-indexing same sourcePath replaces old chunks", () => {
630
+ const path = "/workspace/personal/memory/dedup-test.md";
631
+
632
+ // First indexing
633
+ const m1 = createMemory({
634
+ agentId: ingestAgent,
635
+ content: "Original content",
636
+ name: "dedup-test",
637
+ scope: "agent",
638
+ source: "file_index",
639
+ sourcePath: path,
640
+ });
641
+
642
+ // Re-index: delete old + create new in transaction
643
+ getDb().transaction(() => {
644
+ deleteMemoriesBySourcePath(path, ingestAgent);
645
+ createMemory({
646
+ agentId: ingestAgent,
647
+ content: "Updated content",
648
+ name: "dedup-test",
649
+ scope: "agent",
650
+ source: "file_index",
651
+ sourcePath: path,
652
+ });
653
+ })();
654
+
655
+ // Old memory should be gone
656
+ expect(getMemoryById(m1.id)).toBeNull();
657
+
658
+ // New memory should exist
659
+ const memories = listMemoriesByAgent(ingestAgent, { scope: "agent" }).filter(
660
+ (m) => m.sourcePath === path,
661
+ );
662
+ expect(memories.length).toBe(1);
663
+ expect(memories[0]!.content).toBe("Updated content");
664
+ });
665
+
666
+ test("large content creates multiple chunk records", () => {
667
+ const path = "/workspace/personal/memory/chunked-test.md";
668
+ const longContent = "A ".repeat(3000); // ~6000 chars, well over MAX_CHUNK_SIZE
669
+
670
+ const chunks = chunkContent(longContent);
671
+ expect(chunks.length).toBeGreaterThan(1);
672
+
673
+ getDb().transaction(() => {
674
+ deleteMemoriesBySourcePath(path, ingestAgent);
675
+ for (const chunk of chunks) {
676
+ createMemory({
677
+ agentId: ingestAgent,
678
+ content: chunk.content,
679
+ name: "chunked-test",
680
+ scope: "agent",
681
+ source: "file_index",
682
+ sourcePath: path,
683
+ chunkIndex: chunk.chunkIndex,
684
+ totalChunks: chunk.totalChunks,
685
+ });
686
+ }
687
+ })();
688
+
689
+ const memories = listMemoriesByAgent(ingestAgent, { scope: "agent" }).filter(
690
+ (m) => m.sourcePath === path,
691
+ );
692
+ expect(memories.length).toBe(chunks.length);
693
+ // Verify chunk metadata
694
+ for (const m of memories) {
695
+ expect(m.totalChunks).toBe(chunks.length);
696
+ }
697
+ });
698
+
699
+ test("memory created without OPENAI_API_KEY has null embedding", () => {
700
+ const memory = createMemory({
701
+ agentId: ingestAgent,
702
+ content: "No embedding needed",
703
+ name: "no-embed",
704
+ scope: "agent",
705
+ source: "manual",
706
+ });
707
+
708
+ const row = getDb()
709
+ .prepare("SELECT embedding FROM agent_memory WHERE id = ?")
710
+ .get(memory.id) as { embedding: Buffer | null };
711
+ expect(row.embedding).toBeNull();
712
+ });
713
+
714
+ test("updateMemoryEmbedding stores and retrieves correctly", () => {
715
+ const memory = createMemory({
716
+ agentId: ingestAgent,
717
+ content: "Embed me",
718
+ name: "embed-update",
719
+ scope: "agent",
720
+ source: "manual",
721
+ });
722
+
723
+ const embedding = new Float32Array([0.5, -0.3, 0.8]);
724
+ updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
725
+
726
+ const row = getDb()
727
+ .prepare("SELECT embedding FROM agent_memory WHERE id = ?")
728
+ .get(memory.id) as { embedding: Buffer | null };
729
+ expect(row.embedding).not.toBeNull();
730
+
731
+ const restored = deserializeEmbedding(row.embedding!);
732
+ expect(restored[0]).toBeCloseTo(0.5, 5);
733
+ expect(restored[1]).toBeCloseTo(-0.3, 5);
734
+ expect(restored[2]).toBeCloseTo(0.8, 5);
735
+ });
736
+ });
737
+ });