macro-agent 0.1.0 → 0.1.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 (660) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/issues.jsonl +28 -0
  3. package/.sudocode/specs.jsonl +8 -0
  4. package/CLAUDE.md +25 -17
  5. package/README.md +11 -29
  6. package/dist/acp/macro-agent.d.ts +15 -0
  7. package/dist/acp/macro-agent.d.ts.map +1 -1
  8. package/dist/acp/macro-agent.js +131 -35
  9. package/dist/acp/macro-agent.js.map +1 -1
  10. package/dist/acp/types.d.ts +32 -1
  11. package/dist/acp/types.d.ts.map +1 -1
  12. package/dist/acp/types.js.map +1 -1
  13. package/dist/agent/agent-manager.d.ts +65 -1
  14. package/dist/agent/agent-manager.d.ts.map +1 -1
  15. package/dist/agent/agent-manager.js +544 -200
  16. package/dist/agent/agent-manager.js.map +1 -1
  17. package/dist/agent/types.d.ts +8 -1
  18. package/dist/agent/types.d.ts.map +1 -1
  19. package/dist/agent/types.js.map +1 -1
  20. package/dist/api/server.d.ts +8 -1
  21. package/dist/api/server.d.ts.map +1 -1
  22. package/dist/api/server.js +136 -8
  23. package/dist/api/server.js.map +1 -1
  24. package/dist/api/types.d.ts +1 -1
  25. package/dist/api/types.d.ts.map +1 -1
  26. package/dist/auth/index.d.ts +2 -0
  27. package/dist/auth/index.d.ts.map +1 -0
  28. package/dist/auth/index.js +2 -0
  29. package/dist/auth/index.js.map +1 -0
  30. package/dist/auth/token.d.ts +41 -0
  31. package/dist/auth/token.d.ts.map +1 -0
  32. package/dist/auth/token.js +73 -0
  33. package/dist/auth/token.js.map +1 -0
  34. package/dist/cli/acp.d.ts +2 -23
  35. package/dist/cli/acp.d.ts.map +1 -1
  36. package/dist/cli/acp.js +197 -61
  37. package/dist/cli/acp.js.map +1 -1
  38. package/dist/cli/index.js +152 -16
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/mcp.d.ts +6 -0
  41. package/dist/cli/mcp.d.ts.map +1 -1
  42. package/dist/cli/mcp.js +279 -173
  43. package/dist/cli/mcp.js.map +1 -1
  44. package/dist/cli/parse-args.d.ts +20 -0
  45. package/dist/cli/parse-args.d.ts.map +1 -0
  46. package/dist/cli/parse-args.js +43 -0
  47. package/dist/cli/parse-args.js.map +1 -0
  48. package/dist/cli/stable-instance-id.d.ts +8 -0
  49. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  50. package/dist/cli/stable-instance-id.js +14 -0
  51. package/dist/cli/stable-instance-id.js.map +1 -0
  52. package/dist/config/project-config.d.ts +85 -7
  53. package/dist/config/project-config.d.ts.map +1 -1
  54. package/dist/config/project-config.js +133 -20
  55. package/dist/config/project-config.js.map +1 -1
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +2 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/lifecycle/handlers/index.d.ts +7 -3
  61. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  62. package/dist/lifecycle/handlers/index.js +25 -8
  63. package/dist/lifecycle/handlers/index.js.map +1 -1
  64. package/dist/lifecycle/types.d.ts +2 -0
  65. package/dist/lifecycle/types.d.ts.map +1 -1
  66. package/dist/lifecycle/types.js.map +1 -1
  67. package/dist/map/adapter/acp-over-map.d.ts +17 -0
  68. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  69. package/dist/map/adapter/acp-over-map.js +384 -23
  70. package/dist/map/adapter/acp-over-map.js.map +1 -1
  71. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  72. package/dist/map/adapter/connection-manager.js +3 -0
  73. package/dist/map/adapter/connection-manager.js.map +1 -1
  74. package/dist/map/adapter/event-log.d.ts +87 -0
  75. package/dist/map/adapter/event-log.d.ts.map +1 -0
  76. package/dist/map/adapter/event-log.js +122 -0
  77. package/dist/map/adapter/event-log.js.map +1 -0
  78. package/dist/map/adapter/event-translator.js +6 -6
  79. package/dist/map/adapter/event-translator.js.map +1 -1
  80. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  81. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  82. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  83. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  84. package/dist/map/adapter/extensions/index.d.ts +13 -1
  85. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  86. package/dist/map/adapter/extensions/index.js +61 -0
  87. package/dist/map/adapter/extensions/index.js.map +1 -1
  88. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  89. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  90. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  91. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  92. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  93. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  94. package/dist/map/adapter/extensions/rename.js +49 -0
  95. package/dist/map/adapter/extensions/rename.js.map +1 -0
  96. package/dist/map/adapter/extensions/streams.d.ts +95 -0
  97. package/dist/map/adapter/extensions/streams.d.ts.map +1 -0
  98. package/dist/map/adapter/extensions/streams.js +515 -0
  99. package/dist/map/adapter/extensions/streams.js.map +1 -0
  100. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  101. package/dist/map/adapter/extensions/task.js +10 -0
  102. package/dist/map/adapter/extensions/task.js.map +1 -1
  103. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  104. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  105. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  106. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  107. package/dist/map/adapter/index.d.ts +2 -1
  108. package/dist/map/adapter/index.d.ts.map +1 -1
  109. package/dist/map/adapter/index.js +10 -2
  110. package/dist/map/adapter/index.js.map +1 -1
  111. package/dist/map/adapter/interface.d.ts +2 -0
  112. package/dist/map/adapter/interface.d.ts.map +1 -1
  113. package/dist/map/adapter/map-adapter.d.ts +3 -0
  114. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  115. package/dist/map/adapter/map-adapter.js +258 -35
  116. package/dist/map/adapter/map-adapter.js.map +1 -1
  117. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  118. package/dist/map/adapter/subscription-manager.js +5 -1
  119. package/dist/map/adapter/subscription-manager.js.map +1 -1
  120. package/dist/map/adapter/types.d.ts +3 -1
  121. package/dist/map/adapter/types.d.ts.map +1 -1
  122. package/dist/mcp/map-client.d.ts +39 -0
  123. package/dist/mcp/map-client.d.ts.map +1 -0
  124. package/dist/mcp/map-client.js +129 -0
  125. package/dist/mcp/map-client.js.map +1 -0
  126. package/dist/mcp/mcp-server.d.ts +16 -0
  127. package/dist/mcp/mcp-server.d.ts.map +1 -1
  128. package/dist/mcp/mcp-server.js +125 -88
  129. package/dist/mcp/mcp-server.js.map +1 -1
  130. package/dist/mcp/tools/done.d.ts.map +1 -1
  131. package/dist/mcp/tools/done.js +18 -0
  132. package/dist/mcp/tools/done.js.map +1 -1
  133. package/dist/mcp/types.d.ts +9 -1
  134. package/dist/mcp/types.d.ts.map +1 -1
  135. package/dist/mcp/types.js.map +1 -1
  136. package/dist/metrics/metrics.js +1 -1
  137. package/dist/metrics/metrics.js.map +1 -1
  138. package/dist/roles/builtin/coordinator.d.ts.map +1 -1
  139. package/dist/roles/builtin/coordinator.js +2 -1
  140. package/dist/roles/builtin/coordinator.js.map +1 -1
  141. package/dist/roles/builtin/integrator.d.ts.map +1 -1
  142. package/dist/roles/builtin/integrator.js +2 -1
  143. package/dist/roles/builtin/integrator.js.map +1 -1
  144. package/dist/roles/builtin/worker.d.ts.map +1 -1
  145. package/dist/roles/builtin/worker.js +3 -1
  146. package/dist/roles/builtin/worker.js.map +1 -1
  147. package/dist/roles/capabilities.d.ts +9 -1
  148. package/dist/roles/capabilities.d.ts.map +1 -1
  149. package/dist/roles/capabilities.js +27 -7
  150. package/dist/roles/capabilities.js.map +1 -1
  151. package/dist/roles/config-loader.d.ts +6 -6
  152. package/dist/roles/config-loader.d.ts.map +1 -1
  153. package/dist/roles/config-loader.js +8 -7
  154. package/dist/roles/config-loader.js.map +1 -1
  155. package/dist/roles/registry.d.ts +2 -2
  156. package/dist/roles/registry.js +2 -2
  157. package/dist/roles/types.d.ts +3 -1
  158. package/dist/roles/types.d.ts.map +1 -1
  159. package/dist/server/combined-server.d.ts +28 -1
  160. package/dist/server/combined-server.d.ts.map +1 -1
  161. package/dist/server/combined-server.js +111 -8
  162. package/dist/server/combined-server.js.map +1 -1
  163. package/dist/store/event-store.d.ts +2 -1
  164. package/dist/store/event-store.d.ts.map +1 -1
  165. package/dist/store/event-store.js +80 -24
  166. package/dist/store/event-store.js.map +1 -1
  167. package/dist/store/instance.d.ts +1 -1
  168. package/dist/store/instance.d.ts.map +1 -1
  169. package/dist/store/instance.js +2 -2
  170. package/dist/store/instance.js.map +1 -1
  171. package/dist/store/types/agents.d.ts +23 -0
  172. package/dist/store/types/agents.d.ts.map +1 -1
  173. package/dist/store/types/events.d.ts +1 -1
  174. package/dist/store/types/events.d.ts.map +1 -1
  175. package/dist/task/backend/index.d.ts +47 -29
  176. package/dist/task/backend/index.d.ts.map +1 -1
  177. package/dist/task/backend/index.js +109 -71
  178. package/dist/task/backend/index.js.map +1 -1
  179. package/dist/task/backend/memory.d.ts +1 -0
  180. package/dist/task/backend/memory.d.ts.map +1 -1
  181. package/dist/task/backend/memory.js +3 -0
  182. package/dist/task/backend/memory.js.map +1 -1
  183. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  184. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  185. package/dist/task/backend/opentasks/backend.js +1023 -0
  186. package/dist/task/backend/opentasks/backend.js.map +1 -0
  187. package/dist/task/backend/opentasks/client.d.ts +337 -0
  188. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  189. package/dist/task/backend/opentasks/client.js +225 -0
  190. package/dist/task/backend/opentasks/client.js.map +1 -0
  191. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  192. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  193. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  194. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  195. package/dist/task/backend/opentasks/index.d.ts +21 -0
  196. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  197. package/dist/task/backend/opentasks/index.js +21 -0
  198. package/dist/task/backend/opentasks/index.js.map +1 -0
  199. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  200. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  201. package/dist/task/backend/opentasks/mapping.js +77 -0
  202. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  203. package/dist/task/backend/types.d.ts +33 -53
  204. package/dist/task/backend/types.d.ts.map +1 -1
  205. package/dist/task/backend/types.js +7 -11
  206. package/dist/task/backend/types.js.map +1 -1
  207. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  208. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  209. package/dist/task/backend/unified-tool-provider.js +623 -0
  210. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  211. package/dist/teams/index.d.ts +3 -1
  212. package/dist/teams/index.d.ts.map +1 -1
  213. package/dist/teams/index.js +2 -0
  214. package/dist/teams/index.js.map +1 -1
  215. package/dist/teams/seed-defaults.d.ts +20 -0
  216. package/dist/teams/seed-defaults.d.ts.map +1 -0
  217. package/dist/teams/seed-defaults.js +71 -0
  218. package/dist/teams/seed-defaults.js.map +1 -0
  219. package/dist/teams/team-loader.d.ts +7 -3
  220. package/dist/teams/team-loader.d.ts.map +1 -1
  221. package/dist/teams/team-loader.js +156 -164
  222. package/dist/teams/team-loader.js.map +1 -1
  223. package/dist/teams/team-manager.d.ts +112 -0
  224. package/dist/teams/team-manager.d.ts.map +1 -0
  225. package/dist/teams/team-manager.js +305 -0
  226. package/dist/teams/team-manager.js.map +1 -0
  227. package/dist/teams/team-runtime.d.ts +125 -19
  228. package/dist/teams/team-runtime.d.ts.map +1 -1
  229. package/dist/teams/team-runtime.js +529 -119
  230. package/dist/teams/team-runtime.js.map +1 -1
  231. package/dist/teams/types.d.ts +41 -151
  232. package/dist/teams/types.d.ts.map +1 -1
  233. package/dist/teams/types.js +2 -3
  234. package/dist/teams/types.js.map +1 -1
  235. package/docs/architecture.md +7 -6
  236. package/docs/configuration.md +26 -62
  237. package/docs/implementation-details.md +5 -5
  238. package/docs/implementation-summary.md +17 -17
  239. package/docs/plan-self-driving-support.md +4 -4
  240. package/docs/spec-self-driving-support.md +10 -10
  241. package/docs/team-templates.md +2 -2
  242. package/docs/teams.md +76 -3
  243. package/docs/troubleshooting.md +10 -11
  244. package/package.json +7 -4
  245. package/references/minimem/.claude/settings.json +7 -0
  246. package/references/minimem/.sudocode/issues.jsonl +18 -0
  247. package/references/minimem/.sudocode/specs.jsonl +1 -0
  248. package/references/minimem/CLAUDE.md +310 -0
  249. package/references/minimem/README.md +562 -0
  250. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
  251. package/references/minimem/claude-plugin/.mcp.json +7 -0
  252. package/references/minimem/claude-plugin/README.md +158 -0
  253. package/references/minimem/claude-plugin/commands/recall.md +47 -0
  254. package/references/minimem/claude-plugin/commands/remember.md +41 -0
  255. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
  256. package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
  257. package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
  258. package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
  259. package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
  260. package/references/minimem/media/banner.png +0 -0
  261. package/references/minimem/package-lock.json +5373 -0
  262. package/references/minimem/package.json +72 -0
  263. package/references/minimem/scripts/postbuild.js +35 -0
  264. package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
  265. package/references/minimem/src/__tests__/errors.test.ts +265 -0
  266. package/references/minimem/src/__tests__/helpers.ts +199 -0
  267. package/references/minimem/src/__tests__/internal.test.ts +407 -0
  268. package/references/minimem/src/__tests__/knowledge.test.ts +287 -0
  269. package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
  270. package/references/minimem/src/__tests__/session.test.ts +190 -0
  271. package/references/minimem/src/cli/__tests__/commands.test.ts +759 -0
  272. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
  273. package/references/minimem/src/cli/commands/append.ts +76 -0
  274. package/references/minimem/src/cli/commands/config.ts +262 -0
  275. package/references/minimem/src/cli/commands/conflicts.ts +413 -0
  276. package/references/minimem/src/cli/commands/daemon.ts +169 -0
  277. package/references/minimem/src/cli/commands/index.ts +12 -0
  278. package/references/minimem/src/cli/commands/init.ts +88 -0
  279. package/references/minimem/src/cli/commands/mcp.ts +177 -0
  280. package/references/minimem/src/cli/commands/push-pull.ts +213 -0
  281. package/references/minimem/src/cli/commands/search.ts +158 -0
  282. package/references/minimem/src/cli/commands/status.ts +84 -0
  283. package/references/minimem/src/cli/commands/sync-init.ts +290 -0
  284. package/references/minimem/src/cli/commands/sync.ts +70 -0
  285. package/references/minimem/src/cli/commands/upsert.ts +197 -0
  286. package/references/minimem/src/cli/config.ts +584 -0
  287. package/references/minimem/src/cli/index.ts +264 -0
  288. package/references/minimem/src/cli/shared.ts +161 -0
  289. package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
  290. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
  291. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
  292. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
  293. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
  294. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
  295. package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
  296. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
  297. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
  298. package/references/minimem/src/cli/sync/central.ts +292 -0
  299. package/references/minimem/src/cli/sync/conflicts.ts +204 -0
  300. package/references/minimem/src/cli/sync/daemon.ts +407 -0
  301. package/references/minimem/src/cli/sync/detection.ts +138 -0
  302. package/references/minimem/src/cli/sync/index.ts +107 -0
  303. package/references/minimem/src/cli/sync/operations.ts +373 -0
  304. package/references/minimem/src/cli/sync/registry.ts +279 -0
  305. package/references/minimem/src/cli/sync/state.ts +355 -0
  306. package/references/minimem/src/cli/sync/validation.ts +206 -0
  307. package/references/minimem/src/cli/sync/watcher.ts +234 -0
  308. package/references/minimem/src/cli/version.ts +34 -0
  309. package/references/minimem/src/core/index.ts +9 -0
  310. package/references/minimem/src/core/indexer.ts +628 -0
  311. package/references/minimem/src/core/searcher.ts +221 -0
  312. package/references/minimem/src/db/schema.ts +183 -0
  313. package/references/minimem/src/db/sqlite-vec.ts +24 -0
  314. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
  315. package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
  316. package/references/minimem/src/embeddings/batch-openai.ts +409 -0
  317. package/references/minimem/src/embeddings/embeddings.ts +434 -0
  318. package/references/minimem/src/index.ts +109 -0
  319. package/references/minimem/src/internal.ts +299 -0
  320. package/references/minimem/src/minimem.ts +1276 -0
  321. package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
  322. package/references/minimem/src/search/graph.ts +234 -0
  323. package/references/minimem/src/search/hybrid.ts +151 -0
  324. package/references/minimem/src/search/search.ts +256 -0
  325. package/references/minimem/src/server/__tests__/mcp.test.ts +341 -0
  326. package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
  327. package/references/minimem/src/server/mcp.ts +326 -0
  328. package/references/minimem/src/server/tools.ts +720 -0
  329. package/references/minimem/src/session.ts +460 -0
  330. package/references/minimem/tsconfig.json +19 -0
  331. package/references/minimem/tsup.config.ts +26 -0
  332. package/references/minimem/vitest.config.ts +24 -0
  333. package/references/openteams/.claude/settings.json +6 -0
  334. package/references/openteams/README.md +1 -0
  335. package/references/openteams/SKILL.md +341 -0
  336. package/references/openteams/design.md +411 -0
  337. package/references/openteams/examples/bmad-method/prompts/analyst/ROLE.md +16 -0
  338. package/references/openteams/examples/bmad-method/prompts/analyst/SOUL.md +5 -0
  339. package/references/openteams/examples/bmad-method/prompts/architect/ROLE.md +24 -0
  340. package/references/openteams/examples/bmad-method/prompts/architect/SOUL.md +5 -0
  341. package/references/openteams/examples/bmad-method/prompts/developer/ROLE.md +25 -0
  342. package/references/openteams/examples/bmad-method/prompts/developer/SOUL.md +5 -0
  343. package/references/openteams/examples/bmad-method/prompts/master/ROLE.md +21 -0
  344. package/references/openteams/examples/bmad-method/prompts/master/SOUL.md +5 -0
  345. package/references/openteams/examples/bmad-method/prompts/pm/ROLE.md +20 -0
  346. package/references/openteams/examples/bmad-method/prompts/pm/SOUL.md +5 -0
  347. package/references/openteams/examples/bmad-method/prompts/qa/ROLE.md +17 -0
  348. package/references/openteams/examples/bmad-method/prompts/qa/SOUL.md +5 -0
  349. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/ROLE.md +23 -0
  350. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/SOUL.md +5 -0
  351. package/references/openteams/examples/bmad-method/prompts/scrum-master/ROLE.md +27 -0
  352. package/references/openteams/examples/bmad-method/prompts/scrum-master/SOUL.md +5 -0
  353. package/references/openteams/examples/bmad-method/prompts/tech-writer/ROLE.md +21 -0
  354. package/references/openteams/examples/bmad-method/prompts/tech-writer/SOUL.md +5 -0
  355. package/references/openteams/examples/bmad-method/prompts/ux-designer/ROLE.md +16 -0
  356. package/references/openteams/examples/bmad-method/prompts/ux-designer/SOUL.md +5 -0
  357. package/references/openteams/examples/bmad-method/roles/analyst.yaml +9 -0
  358. package/references/openteams/examples/bmad-method/roles/architect.yaml +9 -0
  359. package/references/openteams/examples/bmad-method/roles/developer.yaml +8 -0
  360. package/references/openteams/examples/bmad-method/roles/master.yaml +8 -0
  361. package/references/openteams/examples/bmad-method/roles/pm.yaml +9 -0
  362. package/references/openteams/examples/bmad-method/roles/qa.yaml +8 -0
  363. package/references/openteams/examples/bmad-method/roles/quick-flow-dev.yaml +8 -0
  364. package/references/openteams/examples/bmad-method/roles/scrum-master.yaml +9 -0
  365. package/references/openteams/examples/bmad-method/roles/tech-writer.yaml +8 -0
  366. package/references/openteams/examples/bmad-method/roles/ux-designer.yaml +8 -0
  367. package/references/openteams/examples/bmad-method/team.yaml +161 -0
  368. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/ROLE.md +17 -0
  369. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/SOUL.md +5 -0
  370. package/references/openteams/examples/get-shit-done/prompts/debugger/ROLE.md +25 -0
  371. package/references/openteams/examples/get-shit-done/prompts/debugger/SOUL.md +5 -0
  372. package/references/openteams/examples/get-shit-done/prompts/executor/ROLE.md +34 -0
  373. package/references/openteams/examples/get-shit-done/prompts/executor/SOUL.md +5 -0
  374. package/references/openteams/examples/get-shit-done/prompts/integration-checker/ROLE.md +18 -0
  375. package/references/openteams/examples/get-shit-done/prompts/integration-checker/SOUL.md +3 -0
  376. package/references/openteams/examples/get-shit-done/prompts/orchestrator/ROLE.md +42 -0
  377. package/references/openteams/examples/get-shit-done/prompts/orchestrator/SOUL.md +5 -0
  378. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/ROLE.md +15 -0
  379. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/SOUL.md +3 -0
  380. package/references/openteams/examples/get-shit-done/prompts/plan-checker/ROLE.md +17 -0
  381. package/references/openteams/examples/get-shit-done/prompts/plan-checker/SOUL.md +3 -0
  382. package/references/openteams/examples/get-shit-done/prompts/planner/ROLE.md +28 -0
  383. package/references/openteams/examples/get-shit-done/prompts/planner/SOUL.md +5 -0
  384. package/references/openteams/examples/get-shit-done/prompts/project-researcher/ROLE.md +16 -0
  385. package/references/openteams/examples/get-shit-done/prompts/project-researcher/SOUL.md +3 -0
  386. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/ROLE.md +13 -0
  387. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/SOUL.md +3 -0
  388. package/references/openteams/examples/get-shit-done/prompts/roadmapper/ROLE.md +14 -0
  389. package/references/openteams/examples/get-shit-done/prompts/roadmapper/SOUL.md +3 -0
  390. package/references/openteams/examples/get-shit-done/prompts/verifier/ROLE.md +19 -0
  391. package/references/openteams/examples/get-shit-done/prompts/verifier/SOUL.md +5 -0
  392. package/references/openteams/examples/get-shit-done/roles/codebase-mapper.yaml +8 -0
  393. package/references/openteams/examples/get-shit-done/roles/debugger.yaml +8 -0
  394. package/references/openteams/examples/get-shit-done/roles/executor.yaml +8 -0
  395. package/references/openteams/examples/get-shit-done/roles/integration-checker.yaml +8 -0
  396. package/references/openteams/examples/get-shit-done/roles/orchestrator.yaml +9 -0
  397. package/references/openteams/examples/get-shit-done/roles/phase-researcher.yaml +7 -0
  398. package/references/openteams/examples/get-shit-done/roles/plan-checker.yaml +8 -0
  399. package/references/openteams/examples/get-shit-done/roles/planner.yaml +8 -0
  400. package/references/openteams/examples/get-shit-done/roles/project-researcher.yaml +8 -0
  401. package/references/openteams/examples/get-shit-done/roles/research-synthesizer.yaml +7 -0
  402. package/references/openteams/examples/get-shit-done/roles/roadmapper.yaml +7 -0
  403. package/references/openteams/examples/get-shit-done/roles/verifier.yaml +8 -0
  404. package/references/openteams/examples/get-shit-done/team.yaml +154 -0
  405. package/references/openteams/package-lock.json +2181 -0
  406. package/references/openteams/package.json +48 -0
  407. package/references/openteams/schema/role.schema.json +125 -0
  408. package/references/openteams/schema/team.schema.json +284 -0
  409. package/references/openteams/src/cli/agent.ts +104 -0
  410. package/references/openteams/src/cli/cli.test.ts +381 -0
  411. package/references/openteams/src/cli/generate.ts +220 -0
  412. package/references/openteams/src/cli/message.ts +241 -0
  413. package/references/openteams/src/cli/task.ts +154 -0
  414. package/references/openteams/src/cli/team.ts +104 -0
  415. package/references/openteams/src/cli/template.ts +207 -0
  416. package/references/openteams/src/cli.ts +45 -0
  417. package/references/openteams/src/db/database.test.ts +185 -0
  418. package/references/openteams/src/db/database.ts +240 -0
  419. package/references/openteams/src/generators/agent-prompt-generator.test.ts +332 -0
  420. package/references/openteams/src/generators/agent-prompt-generator.ts +521 -0
  421. package/references/openteams/src/generators/package-generator.test.ts +129 -0
  422. package/references/openteams/src/generators/package-generator.ts +102 -0
  423. package/references/openteams/src/generators/skill-generator.test.ts +246 -0
  424. package/references/openteams/src/generators/skill-generator.ts +374 -0
  425. package/references/openteams/src/index.ts +104 -0
  426. package/references/openteams/src/services/agent-service.test.ts +158 -0
  427. package/references/openteams/src/services/agent-service.ts +84 -0
  428. package/references/openteams/src/services/communication-service.test.ts +455 -0
  429. package/references/openteams/src/services/communication-service.ts +371 -0
  430. package/references/openteams/src/services/message-service.test.ts +342 -0
  431. package/references/openteams/src/services/message-service.ts +203 -0
  432. package/references/openteams/src/services/task-service.test.ts +434 -0
  433. package/references/openteams/src/services/task-service.ts +239 -0
  434. package/references/openteams/src/services/team-service.test.ts +181 -0
  435. package/references/openteams/src/services/team-service.ts +139 -0
  436. package/references/openteams/src/services/template-service.test.ts +306 -0
  437. package/references/openteams/src/services/template-service.ts +182 -0
  438. package/references/openteams/src/spawner/acp-factory.ts +96 -0
  439. package/references/openteams/src/spawner/interface.ts +31 -0
  440. package/references/openteams/src/spawner/mock.test.ts +93 -0
  441. package/references/openteams/src/spawner/mock.ts +59 -0
  442. package/references/openteams/src/template/loader.test.ts +1319 -0
  443. package/references/openteams/src/template/loader.ts +698 -0
  444. package/references/openteams/src/template/types.ts +200 -0
  445. package/references/openteams/src/types.ts +205 -0
  446. package/references/openteams/tsconfig.json +18 -0
  447. package/references/openteams/vitest.config.ts +9 -0
  448. package/references/skill-tree/.claude/settings.json +6 -0
  449. package/references/skill-tree/.sudocode/issues.jsonl +11 -0
  450. package/references/skill-tree/.sudocode/specs.jsonl +1 -0
  451. package/references/skill-tree/CLAUDE.md +150 -0
  452. package/references/skill-tree/README.md +324 -0
  453. package/references/skill-tree/docs/GAPS_v1.md +221 -0
  454. package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
  455. package/references/skill-tree/docs/TODOS.md +91 -0
  456. package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
  457. package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
  458. package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
  459. package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
  460. package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
  461. package/references/skill-tree/docs/scraper/README.md +170 -0
  462. package/references/skill-tree/examples/basic-usage.ts +190 -0
  463. package/references/skill-tree/package-lock.json +1509 -0
  464. package/references/skill-tree/package.json +66 -0
  465. package/references/skill-tree/scraper/README.md +123 -0
  466. package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
  467. package/references/skill-tree/scraper/docs/PLAN.md +336 -0
  468. package/references/skill-tree/scraper/drizzle.config.ts +10 -0
  469. package/references/skill-tree/scraper/package-lock.json +6329 -0
  470. package/references/skill-tree/scraper/package.json +68 -0
  471. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
  472. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
  473. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
  474. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
  475. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
  476. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
  477. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
  478. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
  479. package/references/skill-tree/scraper/tsup.config.ts +14 -0
  480. package/references/skill-tree/scraper/vitest.config.ts +17 -0
  481. package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
  482. package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
  483. package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
  484. package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
  485. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
  486. package/references/skill-tree/test/run-all.ts +106 -0
  487. package/references/skill-tree/test/utils.ts +128 -0
  488. package/references/skill-tree/vitest.config.ts +16 -0
  489. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  490. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  491. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  492. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  493. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  494. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  495. package/src/acp/__tests__/integration.test.ts +56 -31
  496. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  497. package/src/acp/macro-agent.ts +170 -36
  498. package/src/acp/types.ts +46 -1
  499. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  500. package/src/agent/agent-manager.ts +809 -285
  501. package/src/agent/types.ts +12 -1
  502. package/src/api/__tests__/server.test.ts +203 -4
  503. package/src/api/server.ts +169 -10
  504. package/src/api/types.ts +3 -1
  505. package/src/auth/__tests__/token.test.ts +100 -0
  506. package/src/auth/index.ts +1 -0
  507. package/src/auth/token.ts +82 -0
  508. package/src/cli/__tests__/acp.test.ts +1 -1
  509. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  510. package/src/cli/acp.ts +197 -72
  511. package/src/cli/index.ts +125 -15
  512. package/src/cli/mcp.ts +315 -197
  513. package/src/cli/parse-args.ts +54 -0
  514. package/src/cli/stable-instance-id.ts +14 -0
  515. package/src/config/project-config.ts +214 -27
  516. package/src/index.ts +3 -0
  517. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  518. package/src/lifecycle/__tests__/handlers.test.ts +53 -0
  519. package/src/lifecycle/handlers/index.ts +25 -8
  520. package/src/lifecycle/types.ts +3 -0
  521. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
  522. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  523. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
  524. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  525. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  526. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  527. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  528. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  529. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  530. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  531. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  532. package/src/map/adapter/__tests__/stream-extensions.test.ts +494 -0
  533. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  534. package/src/map/adapter/acp-over-map.ts +678 -66
  535. package/src/map/adapter/connection-manager.ts +3 -0
  536. package/src/map/adapter/event-log.ts +208 -0
  537. package/src/map/adapter/event-translator.ts +6 -6
  538. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  539. package/src/map/adapter/extensions/index.ts +96 -0
  540. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  541. package/src/map/adapter/extensions/streams.ts +839 -0
  542. package/src/map/adapter/extensions/task.ts +11 -0
  543. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  544. package/src/map/adapter/index.ts +33 -0
  545. package/src/map/adapter/interface.ts +2 -0
  546. package/src/map/adapter/map-adapter.ts +312 -47
  547. package/src/map/adapter/subscription-manager.ts +5 -1
  548. package/src/map/adapter/types.ts +10 -1
  549. package/src/mcp/__tests__/map-client.test.ts +386 -0
  550. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  551. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  552. package/src/mcp/map-client.ts +177 -0
  553. package/src/mcp/mcp-server.ts +205 -103
  554. package/src/mcp/tools/done.ts +19 -0
  555. package/src/mcp/types.ts +6 -1
  556. package/src/metrics/metrics.ts +1 -1
  557. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  558. package/src/roles/__tests__/config-loader.test.ts +7 -7
  559. package/src/roles/builtin/coordinator.ts +2 -0
  560. package/src/roles/builtin/integrator.ts +2 -0
  561. package/src/roles/builtin/worker.ts +3 -0
  562. package/src/roles/capabilities.ts +28 -7
  563. package/src/roles/config-loader.ts +8 -7
  564. package/src/roles/registry.ts +2 -2
  565. package/src/roles/types.ts +7 -0
  566. package/src/server/__tests__/combined-server.test.ts +94 -21
  567. package/src/server/combined-server.ts +203 -33
  568. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  569. package/src/store/__tests__/event-store-oob.test.ts +109 -0
  570. package/src/store/__tests__/event-store.test.ts +196 -1
  571. package/src/store/__tests__/instance.test.ts +3 -3
  572. package/src/store/event-store.ts +92 -23
  573. package/src/store/instance.ts +2 -2
  574. package/src/store/types/agents.ts +20 -0
  575. package/src/store/types/events.ts +1 -1
  576. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  577. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  578. package/src/task/backend/__tests__/memory-pull-mode.test.ts +153 -0
  579. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  580. package/src/task/backend/index.ts +156 -106
  581. package/src/task/backend/memory.ts +4 -0
  582. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  583. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  584. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  585. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  586. package/src/task/backend/opentasks/backend.ts +1323 -0
  587. package/src/task/backend/opentasks/client.ts +652 -0
  588. package/src/task/backend/opentasks/daemon-manager.ts +256 -0
  589. package/src/task/backend/opentasks/index.ts +69 -0
  590. package/src/task/backend/opentasks/mapping.ts +94 -0
  591. package/src/task/backend/types.ts +42 -66
  592. package/src/task/backend/unified-tool-provider.ts +779 -0
  593. package/src/teams/CLAUDE.md +180 -0
  594. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  595. package/src/teams/__tests__/e2e/workspace-isolation.e2e.test.ts +1263 -0
  596. package/src/teams/__tests__/team-manager.test.ts +814 -0
  597. package/src/teams/__tests__/team-system.test.ts +1291 -8
  598. package/src/teams/index.ts +21 -3
  599. package/src/teams/seed-defaults.ts +79 -0
  600. package/src/teams/team-loader.ts +202 -236
  601. package/src/teams/team-manager.ts +387 -0
  602. package/src/teams/team-runtime.ts +592 -121
  603. package/src/teams/types.ts +99 -200
  604. package/test_fixtures/README.md +2 -3
  605. package/test_fixtures/fixtures/index.ts +0 -3
  606. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  607. package/test_fixtures/fixtures/repos/index.ts +1 -3
  608. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  609. package/test_fixtures/fixtures/repos/types.ts +0 -11
  610. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  611. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  612. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  613. package/vitest.config.ts +1 -1
  614. package/vitest.e2e.config.ts +1 -1
  615. package/vitest.setup.ts +1 -30
  616. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  617. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  618. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  619. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  620. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  621. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  622. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  623. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  624. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  625. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  626. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  627. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  628. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  629. package/.macro-agent/teams/structured/team.yaml +0 -89
  630. package/docs/sudocode-integration.md +0 -383
  631. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  632. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  633. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  634. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  635. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  636. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  637. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  638. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  639. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  640. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  641. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  642. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  643. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  644. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  645. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  646. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  647. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  648. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  649. package/src/task/backend/sudocode/backend.ts +0 -1237
  650. package/src/task/backend/sudocode/client.ts +0 -515
  651. package/src/task/backend/sudocode/index.ts +0 -120
  652. package/src/task/backend/sudocode/mapping.ts +0 -93
  653. package/src/task/backend/sudocode/server-client.ts +0 -522
  654. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  655. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  656. package/src/task/backend/sudocode/tools.ts +0 -896
  657. package/src/task/backend/tool-provider.ts +0 -506
  658. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  659. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  660. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
@@ -1,1194 +0,0 @@
1
- /**
2
- * SudocodeTaskBackend Tests
3
- *
4
- * Tests for the SudocodeTaskBackend implementation.
5
- */
6
-
7
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
8
- import {
9
- SudocodeTaskBackend,
10
- SudocodeTaskBackendError,
11
- createSudocodeTaskBackend,
12
- } from "../backend.js";
13
- import type { EventStore } from "../../../../store/event-store.js";
14
- import type { Task, TaskStatus } from "../../../../store/types/index.js";
15
- import type { SudocodeClient, IssueChangeCallback } from "../client.js";
16
- import type { Issue } from "../client.js";
17
-
18
- // Mock EventStore
19
- function createMockEventStore(): EventStore {
20
- const tasks = new Map<string, Task>();
21
- const taskChangeCallbacks: Array<(taskId: string, task: Task | null) => void> = [];
22
-
23
- return {
24
- instanceId: "test-instance",
25
- namespace: "test",
26
- instancePath: ":memory:",
27
- backendType: "memory",
28
- peerVisibility: { level: "none" },
29
-
30
- emit: vi.fn((event) => {
31
- if (event.type === "task") {
32
- const payload = event.payload as {
33
- task_id: string;
34
- action: string;
35
- details: Record<string, unknown>;
36
- };
37
- const taskId = payload.task_id;
38
-
39
- if (payload.action === "created") {
40
- const task: Task = {
41
- id: taskId,
42
- description: payload.details.description as string,
43
- status: "pending",
44
- created_at: new Date().toISOString(),
45
- created_by: event.source.agent_id,
46
- parent_task: payload.details.parent_task as string | undefined,
47
- blockers: [],
48
- subtasks: [],
49
- agent_history: [],
50
- outputs: payload.details.external_id
51
- ? { external_id: payload.details.external_id }
52
- : undefined,
53
- };
54
- tasks.set(taskId, task);
55
- } else if (payload.action === "assigned") {
56
- const task = tasks.get(taskId);
57
- if (task) {
58
- task.status = "assigned";
59
- task.assigned_agent = payload.details.agent_id as string;
60
- tasks.set(taskId, task);
61
- }
62
- } else if (payload.action === "unassigned") {
63
- const task = tasks.get(taskId);
64
- if (task) {
65
- task.status = "pending";
66
- task.assigned_agent = undefined;
67
- tasks.set(taskId, task);
68
- }
69
- } else if (payload.action === "status_change") {
70
- const task = tasks.get(taskId);
71
- if (task) {
72
- if (payload.details.status) {
73
- task.status = payload.details.status as TaskStatus;
74
- }
75
- if (payload.details.description) {
76
- task.description = payload.details.description as string;
77
- }
78
- if (payload.details.outputs) {
79
- task.outputs = {
80
- ...(task.outputs ?? {}),
81
- ...(payload.details.outputs as Record<string, unknown>),
82
- };
83
- }
84
- if (payload.details.artifacts) {
85
- task.artifacts = payload.details.artifacts as any[];
86
- }
87
- if (payload.details.subtask_added) {
88
- task.subtasks = [
89
- ...(task.subtasks ?? []),
90
- payload.details.subtask_added as string,
91
- ];
92
- }
93
- tasks.set(taskId, task);
94
- }
95
- } else if (payload.action === "completed") {
96
- const task = tasks.get(taskId);
97
- if (task) {
98
- task.status = "completed";
99
- task.completed_at = new Date().toISOString();
100
- tasks.set(taskId, task);
101
- }
102
- } else if (payload.action === "failed") {
103
- const task = tasks.get(taskId);
104
- if (task) {
105
- task.status = "failed";
106
- tasks.set(taskId, task);
107
- }
108
- } else if (payload.action === "blocker_added") {
109
- const task = tasks.get(taskId);
110
- if (task) {
111
- task.blockers = [
112
- ...(task.blockers ?? []),
113
- payload.details.blocker_id as string,
114
- ];
115
- tasks.set(taskId, task);
116
- }
117
- } else if (payload.action === "blocker_removed") {
118
- const task = tasks.get(taskId);
119
- if (task) {
120
- task.blockers = (task.blockers ?? []).filter(
121
- (b) => b !== payload.details.blocker_id
122
- );
123
- tasks.set(taskId, task);
124
- }
125
- }
126
-
127
- // Notify listeners
128
- const updatedTask = tasks.get(taskId) ?? null;
129
- for (const cb of taskChangeCallbacks) {
130
- cb(taskId, updatedTask);
131
- }
132
- }
133
-
134
- return {
135
- id: `event_${Date.now()}`,
136
- type: event.type,
137
- source: event.source,
138
- payload: event.payload,
139
- timestamp: new Date().toISOString(),
140
- version: 1,
141
- };
142
- }),
143
-
144
- query: vi.fn(() => []),
145
-
146
- getAgent: vi.fn(() => null),
147
- listAgents: vi.fn(() => []),
148
-
149
- getTask: vi.fn((taskId: string) => tasks.get(taskId) ?? null),
150
- listTasks: vi.fn(() => Array.from(tasks.values())),
151
-
152
- getMessages: vi.fn(() => []),
153
- getFullMessage: vi.fn(() => null),
154
-
155
- addSubscription: vi.fn(),
156
- removeSubscription: vi.fn(),
157
- getSubscriptions: vi.fn(() => []),
158
- getSubscribers: vi.fn(() => []),
159
-
160
- onAgentChange: vi.fn(() => () => {}),
161
- onTaskChange: vi.fn((callback: (taskId: string, task: Task | null) => void) => {
162
- taskChangeCallbacks.push(callback);
163
- return () => {
164
- const idx = taskChangeCallbacks.indexOf(callback);
165
- if (idx >= 0) taskChangeCallbacks.splice(idx, 1);
166
- };
167
- }),
168
- onMessageChange: vi.fn(() => () => {}),
169
-
170
- persist: vi.fn(async () => {}),
171
- reload: vi.fn(async () => {}),
172
- close: vi.fn(async () => {}),
173
-
174
- archive: vi.fn(async () => ({
175
- archivedCount: 0,
176
- archivePath: "",
177
- oldestRetained: "",
178
- })),
179
- loadArchive: vi.fn(async () => []),
180
- getArchiveInfo: vi.fn(async () => ({ archives: [], totalArchivedEvents: 0 })),
181
-
182
- exportEvents: vi.fn(() => []),
183
- importEvents: vi.fn(),
184
-
185
- getBackend: vi.fn(() => ({} as any)),
186
- } as unknown as EventStore;
187
- }
188
-
189
- // Mock SudocodeClient
190
- function createMockSudocodeClient(): SudocodeClient {
191
- const issues = new Map<string, Issue>();
192
- const issueBlockers = new Map<string, Issue[]>();
193
- const issueBlocking = new Map<string, Issue[]>();
194
- const issueChangeCallbacks: IssueChangeCallback[] = [];
195
-
196
- // Add some test issues
197
- issues.set("i-test1", {
198
- id: "i-test1",
199
- uuid: "uuid-1",
200
- title: "Test Issue 1",
201
- content: "Test content",
202
- status: "open",
203
- priority: 1,
204
- created_at: "2024-01-01T00:00:00Z",
205
- updated_at: "2024-01-01T00:00:00Z",
206
- });
207
- issues.set("i-test2", {
208
- id: "i-test2",
209
- uuid: "uuid-2",
210
- title: "Test Issue 2",
211
- content: "Test content",
212
- status: "open",
213
- priority: 2,
214
- created_at: "2024-01-01T00:00:00Z",
215
- updated_at: "2024-01-01T00:00:00Z",
216
- });
217
-
218
- return {
219
- getIssue: vi.fn(async (id: string) => issues.get(id) ?? null),
220
- listIssues: vi.fn(async () => Array.from(issues.values())),
221
- getReadyIssues: vi.fn(async () => Array.from(issues.values())),
222
- updateIssue: vi.fn(async (id: string, updates: any) => {
223
- const issue = issues.get(id);
224
- if (!issue) throw new Error("Issue not found");
225
- const updated = { ...issue, ...updates };
226
- issues.set(id, updated);
227
- return updated;
228
- }),
229
-
230
- createLink: vi.fn(async () => {}),
231
- removeLink: vi.fn(async () => {}),
232
- getBlockers: vi.fn(async (id: string) => issueBlockers.get(id) ?? []),
233
- getBlocking: vi.fn(async (id: string) => issueBlocking.get(id) ?? []),
234
-
235
- getSpec: vi.fn(async () => null),
236
- listSpecs: vi.fn(async () => []),
237
-
238
- addFeedback: vi.fn(async () => {}),
239
-
240
- onIssueChange: vi.fn((callbackOrId: IssueChangeCallback | string, maybeCallback?: IssueChangeCallback) => {
241
- const callback = typeof callbackOrId === "function" ? callbackOrId : maybeCallback!;
242
- issueChangeCallbacks.push(callback);
243
- return () => {
244
- const idx = issueChangeCallbacks.indexOf(callback);
245
- if (idx >= 0) issueChangeCallbacks.splice(idx, 1);
246
- };
247
- }),
248
-
249
- isReady: vi.fn(() => true),
250
- close: vi.fn(),
251
-
252
- // Test helpers
253
- _setIssue: (id: string, issue: Issue) => issues.set(id, issue),
254
- _setBlockers: (id: string, blockers: Issue[]) => issueBlockers.set(id, blockers),
255
- _setBlocking: (id: string, blocking: Issue[]) => issueBlocking.set(id, blocking),
256
- _notifyChange: (event: any) => {
257
- for (const cb of issueChangeCallbacks) {
258
- cb(event);
259
- }
260
- },
261
- } as unknown as SudocodeClient & {
262
- _setIssue: (id: string, issue: Issue) => void;
263
- _setBlockers: (id: string, blockers: Issue[]) => void;
264
- _setBlocking: (id: string, blocking: Issue[]) => void;
265
- _notifyChange: (event: any) => void;
266
- };
267
- }
268
-
269
- describe("SudocodeTaskBackend", () => {
270
- let eventStore: EventStore;
271
- let client: SudocodeClient & {
272
- _setIssue: (id: string, issue: Issue) => void;
273
- _setBlockers: (id: string, blockers: Issue[]) => void;
274
- _setBlocking: (id: string, blocking: Issue[]) => void;
275
- _notifyChange: (event: any) => void;
276
- };
277
- let backend: SudocodeTaskBackend;
278
-
279
- beforeEach(() => {
280
- eventStore = createMockEventStore();
281
- client = createMockSudocodeClient() as any;
282
- backend = new SudocodeTaskBackend(eventStore, client, {
283
- syncStatus: false, // Disable auto-sync for most tests
284
- });
285
- });
286
-
287
- afterEach(() => {
288
- backend.close();
289
- });
290
-
291
- describe("create", () => {
292
- it("should create a task", async () => {
293
- const task = await backend.create({
294
- description: "Test task",
295
- created_by: "agent-1",
296
- });
297
-
298
- expect(task.id).toMatch(/^task_/);
299
- expect(task.description).toBe("Test task");
300
- expect(task.status).toBe("pending");
301
- expect(task.created_by).toBe("agent-1");
302
- });
303
-
304
- it("should create a task bound to an issue", async () => {
305
- const task = await backend.create({
306
- description: "Test task",
307
- created_by: "agent-1",
308
- external_id: "i-test1",
309
- });
310
-
311
- expect(task.external_id).toBe("i-test1");
312
- });
313
-
314
- it("should throw when issue not found", async () => {
315
- await expect(
316
- backend.create({
317
- description: "Test task",
318
- created_by: "agent-1",
319
- external_id: "i-nonexistent",
320
- })
321
- ).rejects.toThrow("Issue not found");
322
- });
323
-
324
- it("should create a subtask", async () => {
325
- const parent = await backend.create({
326
- description: "Parent task",
327
- created_by: "agent-1",
328
- });
329
-
330
- const child = await backend.create({
331
- description: "Child task",
332
- created_by: "agent-1",
333
- parent_task: parent.id,
334
- });
335
-
336
- expect(child.parent_task).toBe(parent.id);
337
- });
338
-
339
- it("should throw when parent not found", async () => {
340
- await expect(
341
- backend.create({
342
- description: "Child task",
343
- created_by: "agent-1",
344
- parent_task: "nonexistent",
345
- })
346
- ).rejects.toThrow("Parent task not found");
347
- });
348
- });
349
-
350
- describe("get", () => {
351
- it("should get a task by ID", async () => {
352
- const created = await backend.create({
353
- description: "Test task",
354
- created_by: "agent-1",
355
- });
356
-
357
- const fetched = await backend.get(created.id);
358
-
359
- expect(fetched).not.toBeNull();
360
- expect(fetched!.id).toBe(created.id);
361
- });
362
-
363
- it("should return null for non-existent task", async () => {
364
- const fetched = await backend.get("nonexistent");
365
- expect(fetched).toBeNull();
366
- });
367
- });
368
-
369
- describe("update", () => {
370
- it("should update task description", async () => {
371
- const task = await backend.create({
372
- description: "Original",
373
- created_by: "agent-1",
374
- });
375
-
376
- const updated = await backend.update(task.id, {
377
- description: "Updated",
378
- });
379
-
380
- expect(updated.description).toBe("Updated");
381
- });
382
-
383
- it("should update task status", async () => {
384
- const task = await backend.create({
385
- description: "Test task",
386
- created_by: "agent-1",
387
- });
388
-
389
- // Assign first
390
- await backend.assign(task.id, "agent-1");
391
-
392
- const updated = await backend.update(task.id, {
393
- status: "in_progress",
394
- });
395
-
396
- expect(updated.status).toBe("in_progress");
397
- });
398
-
399
- it("should throw for invalid status transition", async () => {
400
- const task = await backend.create({
401
- description: "Test task",
402
- created_by: "agent-1",
403
- });
404
-
405
- await expect(
406
- backend.update(task.id, { status: "completed" })
407
- ).rejects.toThrow("Invalid status transition");
408
- });
409
-
410
- it("should throw for non-existent task", async () => {
411
- await expect(
412
- backend.update("nonexistent", { description: "Test" })
413
- ).rejects.toThrow("Task not found");
414
- });
415
- });
416
-
417
- describe("delete", () => {
418
- it("should throw not supported error", async () => {
419
- const task = await backend.create({
420
- description: "Test task",
421
- created_by: "agent-1",
422
- });
423
-
424
- // Delete is not supported - tasks are immutable in event-sourced system
425
- await expect(backend.delete(task.id)).rejects.toThrow("not supported");
426
-
427
- // Task should remain unchanged
428
- const unchanged = await backend.get(task.id);
429
- expect(unchanged!.status).toBe("pending");
430
- });
431
-
432
- it("should throw not supported even for tasks bound to issues", async () => {
433
- const task = await backend.create({
434
- description: "Test task",
435
- created_by: "agent-1",
436
- external_id: "i-test1",
437
- });
438
-
439
- // Delete is not supported regardless of issue binding
440
- await expect(backend.delete(task.id)).rejects.toThrow("not supported");
441
-
442
- // Task should still be in the issue index
443
- const taskIds = backend.getTasksByIssue("i-test1");
444
- expect(taskIds).toContain(task.id);
445
- });
446
-
447
- it("should throw not supported even for non-existent task", async () => {
448
- // Note: We throw "not supported" before checking if task exists
449
- // This matches InMemoryTaskBackend behavior for consistency
450
- await expect(backend.delete("nonexistent")).rejects.toThrow(
451
- "not supported"
452
- );
453
- });
454
- });
455
-
456
- describe("assign", () => {
457
- it("should assign a task to an agent", async () => {
458
- const task = await backend.create({
459
- description: "Test task",
460
- created_by: "agent-1",
461
- });
462
-
463
- await backend.assign(task.id, "agent-2");
464
-
465
- const updated = await backend.get(task.id);
466
- expect(updated!.status).toBe("assigned");
467
- expect(updated!.assigned_agent).toBe("agent-2");
468
- });
469
- });
470
-
471
- describe("unassign", () => {
472
- it("should unassign a task", async () => {
473
- const task = await backend.create({
474
- description: "Test task",
475
- created_by: "agent-1",
476
- });
477
-
478
- await backend.assign(task.id, "agent-2");
479
- await backend.unassign(task.id);
480
-
481
- const updated = await backend.get(task.id);
482
- expect(updated!.status).toBe("pending");
483
- expect(updated!.assigned_agent).toBeUndefined();
484
- });
485
-
486
- it("should throw when task is not assigned", async () => {
487
- const task = await backend.create({
488
- description: "Test task",
489
- created_by: "agent-1",
490
- });
491
-
492
- await expect(backend.unassign(task.id)).rejects.toThrow("not assigned");
493
- });
494
- });
495
-
496
- describe("start", () => {
497
- it("should start a task", async () => {
498
- const task = await backend.create({
499
- description: "Test task",
500
- created_by: "agent-1",
501
- });
502
-
503
- await backend.assign(task.id, "agent-1");
504
- await backend.start(task.id);
505
-
506
- const updated = await backend.get(task.id);
507
- expect(updated!.status).toBe("in_progress");
508
- });
509
- });
510
-
511
- describe("complete", () => {
512
- it("should complete a task", async () => {
513
- const task = await backend.create({
514
- description: "Test task",
515
- created_by: "agent-1",
516
- });
517
-
518
- await backend.assign(task.id, "agent-1");
519
- await backend.start(task.id);
520
- await backend.complete(task.id, { summary: "Done" });
521
-
522
- const updated = await backend.get(task.id);
523
- expect(updated!.status).toBe("completed");
524
- });
525
- });
526
-
527
- describe("fail", () => {
528
- it("should fail a task", async () => {
529
- const task = await backend.create({
530
- description: "Test task",
531
- created_by: "agent-1",
532
- });
533
-
534
- await backend.assign(task.id, "agent-1");
535
- await backend.start(task.id);
536
- await backend.fail(task.id, { message: "Something went wrong" });
537
-
538
- const updated = await backend.get(task.id);
539
- expect(updated!.status).toBe("failed");
540
- });
541
- });
542
-
543
- describe("list", () => {
544
- it("should list all tasks", async () => {
545
- await backend.create({ description: "Task 1", created_by: "agent-1" });
546
- await backend.create({ description: "Task 2", created_by: "agent-1" });
547
-
548
- const tasks = await backend.list();
549
- expect(tasks).toHaveLength(2);
550
- });
551
-
552
- it("should filter by status", async () => {
553
- const task1 = await backend.create({
554
- description: "Task 1",
555
- created_by: "agent-1",
556
- });
557
- await backend.create({ description: "Task 2", created_by: "agent-1" });
558
-
559
- await backend.assign(task1.id, "agent-1");
560
-
561
- const assigned = await backend.list({ status: "assigned" });
562
- expect(assigned).toHaveLength(1);
563
- expect(assigned[0].id).toBe(task1.id);
564
- });
565
-
566
- it("should filter by assigned_agent", async () => {
567
- const task1 = await backend.create({
568
- description: "Task 1",
569
- created_by: "agent-1",
570
- });
571
- await backend.create({ description: "Task 2", created_by: "agent-1" });
572
-
573
- await backend.assign(task1.id, "agent-2");
574
-
575
- const tasks = await backend.list({ assigned_agent: "agent-2" });
576
- expect(tasks).toHaveLength(1);
577
- expect(tasks[0].id).toBe(task1.id);
578
- });
579
-
580
- it("should exclude blocked tasks by default", async () => {
581
- const blocker = await backend.create({
582
- description: "Blocker",
583
- created_by: "agent-1",
584
- });
585
- const blocked = await backend.create({
586
- description: "Blocked",
587
- created_by: "agent-1",
588
- });
589
-
590
- await backend.addBlocker(blocked.id, blocker.id);
591
-
592
- const tasks = await backend.list();
593
- expect(tasks.map((t) => t.id)).not.toContain(blocked.id);
594
- });
595
-
596
- it("should include blocked tasks when requested", async () => {
597
- const blocker = await backend.create({
598
- description: "Blocker",
599
- created_by: "agent-1",
600
- });
601
- const blocked = await backend.create({
602
- description: "Blocked",
603
- created_by: "agent-1",
604
- });
605
-
606
- await backend.addBlocker(blocked.id, blocker.id);
607
-
608
- const tasks = await backend.list({ includeBlocked: true });
609
- expect(tasks.map((t) => t.id)).toContain(blocked.id);
610
- });
611
- });
612
-
613
- describe("listReady", () => {
614
- it("should return unblocked pending tasks", async () => {
615
- await backend.create({ description: "Task 1", created_by: "agent-1" });
616
- await backend.create({ description: "Task 2", created_by: "agent-1" });
617
-
618
- const ready = await backend.listReady();
619
- expect(ready).toHaveLength(2);
620
- });
621
-
622
- it("should exclude blocked tasks", async () => {
623
- const blocker = await backend.create({
624
- description: "Blocker",
625
- created_by: "agent-1",
626
- });
627
- const blocked = await backend.create({
628
- description: "Blocked",
629
- created_by: "agent-1",
630
- });
631
-
632
- await backend.addBlocker(blocked.id, blocker.id);
633
-
634
- const ready = await backend.listReady();
635
- expect(ready.map((t) => t.id)).not.toContain(blocked.id);
636
- });
637
- });
638
-
639
- describe("blockers", () => {
640
- it("should add and get blockers", async () => {
641
- const task1 = await backend.create({
642
- description: "Task 1",
643
- created_by: "agent-1",
644
- });
645
- const task2 = await backend.create({
646
- description: "Task 2",
647
- created_by: "agent-1",
648
- });
649
-
650
- await backend.addBlocker(task2.id, task1.id);
651
-
652
- const blockers = await backend.getBlockers(task2.id);
653
- expect(blockers).toHaveLength(1);
654
- expect(blockers[0].id).toBe(task1.id);
655
- });
656
-
657
- it("should remove blockers", async () => {
658
- const task1 = await backend.create({
659
- description: "Task 1",
660
- created_by: "agent-1",
661
- });
662
- const task2 = await backend.create({
663
- description: "Task 2",
664
- created_by: "agent-1",
665
- });
666
-
667
- await backend.addBlocker(task2.id, task1.id);
668
- await backend.removeBlocker(task2.id, task1.id);
669
-
670
- const blockers = await backend.getBlockers(task2.id);
671
- expect(blockers).toHaveLength(0);
672
- });
673
-
674
- it("should get tasks that this task blocks", async () => {
675
- const task1 = await backend.create({
676
- description: "Task 1",
677
- created_by: "agent-1",
678
- });
679
- const task2 = await backend.create({
680
- description: "Task 2",
681
- created_by: "agent-1",
682
- });
683
-
684
- await backend.addBlocker(task2.id, task1.id);
685
-
686
- const blocking = await backend.getBlocking(task1.id);
687
- expect(blocking).toHaveLength(1);
688
- expect(blocking[0].id).toBe(task2.id);
689
- });
690
-
691
- it("should compute isBlocked from local blockers", async () => {
692
- const blocker = await backend.create({
693
- description: "Blocker",
694
- created_by: "agent-1",
695
- });
696
- const blocked = await backend.create({
697
- description: "Blocked",
698
- created_by: "agent-1",
699
- });
700
-
701
- await backend.addBlocker(blocked.id, blocker.id);
702
-
703
- const task = await backend.get(blocked.id);
704
- expect(task!.isBlocked).toBe(true);
705
- });
706
-
707
- it("should not be blocked when blocker is completed", async () => {
708
- const blocker = await backend.create({
709
- description: "Blocker",
710
- created_by: "agent-1",
711
- });
712
- const blocked = await backend.create({
713
- description: "Blocked",
714
- created_by: "agent-1",
715
- });
716
-
717
- await backend.addBlocker(blocked.id, blocker.id);
718
-
719
- // Complete the blocker
720
- await backend.assign(blocker.id, "agent-1");
721
- await backend.start(blocker.id);
722
- await backend.complete(blocker.id);
723
-
724
- const task = await backend.get(blocked.id);
725
- expect(task!.isBlocked).toBe(false);
726
- });
727
- });
728
-
729
- describe("getChildren", () => {
730
- it("should get child tasks", async () => {
731
- const parent = await backend.create({
732
- description: "Parent",
733
- created_by: "agent-1",
734
- });
735
-
736
- await backend.create({
737
- description: "Child 1",
738
- created_by: "agent-1",
739
- parent_task: parent.id,
740
- });
741
- await backend.create({
742
- description: "Child 2",
743
- created_by: "agent-1",
744
- parent_task: parent.id,
745
- });
746
-
747
- const children = await backend.getChildren(parent.id);
748
- expect(children).toHaveLength(2);
749
- });
750
- });
751
-
752
- describe("getSubtaskStatus", () => {
753
- it("should aggregate subtask statuses", async () => {
754
- const parent = await backend.create({
755
- description: "Parent",
756
- created_by: "agent-1",
757
- });
758
-
759
- const child1 = await backend.create({
760
- description: "Child 1",
761
- created_by: "agent-1",
762
- parent_task: parent.id,
763
- });
764
- await backend.create({
765
- description: "Child 2",
766
- created_by: "agent-1",
767
- parent_task: parent.id,
768
- });
769
-
770
- await backend.assign(child1.id, "agent-1");
771
- await backend.start(child1.id);
772
- await backend.complete(child1.id);
773
-
774
- const status = await backend.getSubtaskStatus(parent.id);
775
- expect(status.total).toBe(2);
776
- expect(status.completed).toBe(1);
777
- expect(status.pending).toBe(1);
778
- expect(status.allCompleted).toBe(false);
779
- });
780
- });
781
-
782
- describe("getAgentHistory", () => {
783
- it("should return agent history", async () => {
784
- const task = await backend.create({
785
- description: "Test",
786
- created_by: "agent-1",
787
- });
788
-
789
- const history = await backend.getAgentHistory(task.id);
790
- expect(Array.isArray(history)).toBe(true);
791
- });
792
- });
793
-
794
- describe("onTaskChange", () => {
795
- it("should notify on task changes", async () => {
796
- const callback = vi.fn();
797
- const unsubscribe = backend.onTaskChange(callback);
798
-
799
- await backend.create({
800
- description: "Test",
801
- created_by: "agent-1",
802
- });
803
-
804
- expect(callback).toHaveBeenCalled();
805
-
806
- unsubscribe();
807
- });
808
- });
809
-
810
- describe("issue-bound tasks", () => {
811
- it("should check issue blockers for bound tasks", async () => {
812
- // Set up a blocker in sudocode
813
- const blockerIssue: Issue = {
814
- id: "i-blocker",
815
- uuid: "uuid-blocker",
816
- title: "Blocker Issue",
817
- content: "Blocks test1",
818
- status: "open",
819
- priority: 1,
820
- created_at: "2024-01-01T00:00:00Z",
821
- updated_at: "2024-01-01T00:00:00Z",
822
- };
823
- client._setIssue("i-blocker", blockerIssue);
824
- client._setBlockers("i-test1", [blockerIssue]);
825
-
826
- const task = await backend.create({
827
- description: "Test task",
828
- created_by: "agent-1",
829
- external_id: "i-test1",
830
- });
831
-
832
- const fetched = await backend.get(task.id);
833
- expect(fetched!.isBlocked).toBe(true);
834
- });
835
-
836
- it("should not be blocked when issue blocker is closed", async () => {
837
- const blockerIssue: Issue = {
838
- id: "i-blocker",
839
- uuid: "uuid-blocker",
840
- title: "Blocker Issue",
841
- content: "Blocks test1",
842
- status: "closed", // Closed - no longer blocks
843
- priority: 1,
844
- created_at: "2024-01-01T00:00:00Z",
845
- updated_at: "2024-01-01T00:00:00Z",
846
- };
847
- client._setIssue("i-blocker", blockerIssue);
848
- client._setBlockers("i-test1", [blockerIssue]);
849
-
850
- const task = await backend.create({
851
- description: "Test task",
852
- created_by: "agent-1",
853
- external_id: "i-test1",
854
- });
855
-
856
- const fetched = await backend.get(task.id);
857
- expect(fetched!.isBlocked).toBe(false);
858
- });
859
- });
860
-
861
- describe("task-issue index", () => {
862
- it("should track tasks by issue", async () => {
863
- const task1 = await backend.create({
864
- description: "Task 1",
865
- created_by: "agent-1",
866
- external_id: "i-test1",
867
- });
868
- const task2 = await backend.create({
869
- description: "Task 2",
870
- created_by: "agent-1",
871
- external_id: "i-test1",
872
- });
873
-
874
- const taskIds = backend.getTasksByIssue("i-test1");
875
- expect(taskIds).toHaveLength(2);
876
- expect(taskIds).toContain(task1.id);
877
- expect(taskIds).toContain(task2.id);
878
- });
879
-
880
- it("should track issue for each task", async () => {
881
- const task = await backend.create({
882
- description: "Test task",
883
- created_by: "agent-1",
884
- external_id: "i-test1",
885
- });
886
-
887
- const issueId = backend.getIssueForTask(task.id);
888
- expect(issueId).toBe("i-test1");
889
- });
890
-
891
- it("should return undefined for unbound task", async () => {
892
- const task = await backend.create({
893
- description: "Test task",
894
- created_by: "agent-1",
895
- });
896
-
897
- const issueId = backend.getIssueForTask(task.id);
898
- expect(issueId).toBeUndefined();
899
- });
900
- });
901
-
902
- describe("bindToIssue", () => {
903
- it("should bind a task to an issue", async () => {
904
- const task = await backend.create({
905
- description: "Test task",
906
- created_by: "agent-1",
907
- });
908
-
909
- await backend.bindToIssue(task.id, "i-test1");
910
-
911
- const issueId = backend.getIssueForTask(task.id);
912
- expect(issueId).toBe("i-test1");
913
-
914
- const taskIds = backend.getTasksByIssue("i-test1");
915
- expect(taskIds).toContain(task.id);
916
- });
917
-
918
- it("should throw when issue not found", async () => {
919
- const task = await backend.create({
920
- description: "Test task",
921
- created_by: "agent-1",
922
- });
923
-
924
- await expect(
925
- backend.bindToIssue(task.id, "i-nonexistent")
926
- ).rejects.toThrow("Issue not found");
927
- });
928
-
929
- it("should throw when task not found", async () => {
930
- await expect(
931
- backend.bindToIssue("nonexistent", "i-test1")
932
- ).rejects.toThrow("Task not found");
933
- });
934
-
935
- it("should rebind task to different issue", async () => {
936
- const task = await backend.create({
937
- description: "Test task",
938
- created_by: "agent-1",
939
- external_id: "i-test1",
940
- });
941
-
942
- await backend.bindToIssue(task.id, "i-test2");
943
-
944
- const issueId = backend.getIssueForTask(task.id);
945
- expect(issueId).toBe("i-test2");
946
-
947
- // Should no longer be in old issue's list
948
- const oldTaskIds = backend.getTasksByIssue("i-test1");
949
- expect(oldTaskIds).not.toContain(task.id);
950
-
951
- // Should be in new issue's list
952
- const newTaskIds = backend.getTasksByIssue("i-test2");
953
- expect(newTaskIds).toContain(task.id);
954
- });
955
- });
956
-
957
- describe("unbindFromIssue", () => {
958
- it("should unbind a task from its issue", async () => {
959
- const task = await backend.create({
960
- description: "Test task",
961
- created_by: "agent-1",
962
- external_id: "i-test1",
963
- });
964
-
965
- await backend.unbindFromIssue(task.id);
966
-
967
- const issueId = backend.getIssueForTask(task.id);
968
- expect(issueId).toBeUndefined();
969
-
970
- const taskIds = backend.getTasksByIssue("i-test1");
971
- expect(taskIds).not.toContain(task.id);
972
- });
973
-
974
- it("should do nothing for unbound task", async () => {
975
- const task = await backend.create({
976
- description: "Test task",
977
- created_by: "agent-1",
978
- });
979
-
980
- // Should not throw
981
- await backend.unbindFromIssue(task.id);
982
-
983
- const issueId = backend.getIssueForTask(task.id);
984
- expect(issueId).toBeUndefined();
985
- });
986
-
987
- it("should throw when task not found", async () => {
988
- await expect(backend.unbindFromIssue("nonexistent")).rejects.toThrow(
989
- "Task not found"
990
- );
991
- });
992
- });
993
-
994
- describe("sudocode relationship integration", () => {
995
- it("should create sudocode link when both tasks are bound to issues", async () => {
996
- // Create two tasks bound to different issues
997
- const blocker = await backend.create({
998
- description: "Blocker task",
999
- created_by: "agent-1",
1000
- external_id: "i-test1",
1001
- });
1002
- const blocked = await backend.create({
1003
- description: "Blocked task",
1004
- created_by: "agent-1",
1005
- external_id: "i-test2",
1006
- });
1007
-
1008
- await backend.addBlocker(blocked.id, blocker.id);
1009
-
1010
- // Verify sudocode createLink was called with correct args
1011
- expect(client.createLink).toHaveBeenCalledWith(
1012
- "i-test1", // blocker issue
1013
- "i-test2", // blocked issue
1014
- "blocks"
1015
- );
1016
- });
1017
-
1018
- it("should not create sudocode link when tasks are not bound", async () => {
1019
- // Create two tasks without external_id
1020
- const blocker = await backend.create({
1021
- description: "Blocker task",
1022
- created_by: "agent-1",
1023
- });
1024
- const blocked = await backend.create({
1025
- description: "Blocked task",
1026
- created_by: "agent-1",
1027
- });
1028
-
1029
- await backend.addBlocker(blocked.id, blocker.id);
1030
-
1031
- // createLink should not be called
1032
- expect(client.createLink).not.toHaveBeenCalled();
1033
- });
1034
-
1035
- it("should remove sudocode link when both tasks are bound to issues", async () => {
1036
- // Create two tasks bound to different issues
1037
- const blocker = await backend.create({
1038
- description: "Blocker task",
1039
- created_by: "agent-1",
1040
- external_id: "i-test1",
1041
- });
1042
- const blocked = await backend.create({
1043
- description: "Blocked task",
1044
- created_by: "agent-1",
1045
- external_id: "i-test2",
1046
- });
1047
-
1048
- await backend.addBlocker(blocked.id, blocker.id);
1049
- await backend.removeBlocker(blocked.id, blocker.id);
1050
-
1051
- // Verify sudocode removeLink was called with correct args
1052
- expect(client.removeLink).toHaveBeenCalledWith(
1053
- "i-test1", // blocker issue
1054
- "i-test2", // blocked issue
1055
- "blocks"
1056
- );
1057
- });
1058
-
1059
- it("should merge local and sudocode blockers in getBlockers", async () => {
1060
- // Create a task bound to i-test2
1061
- const task = await backend.create({
1062
- description: "Test task",
1063
- created_by: "agent-1",
1064
- external_id: "i-test2",
1065
- });
1066
-
1067
- // Create a local blocker (unbound task)
1068
- const localBlocker = await backend.create({
1069
- description: "Local blocker",
1070
- created_by: "agent-1",
1071
- });
1072
- await backend.addBlocker(task.id, localBlocker.id);
1073
-
1074
- // Create a task bound to i-test1 (sudocode blocker)
1075
- const sudocodeBlocker = await backend.create({
1076
- description: "Sudocode blocker",
1077
- created_by: "agent-1",
1078
- external_id: "i-test1",
1079
- });
1080
-
1081
- // Set up sudocode to report i-test1 as blocking i-test2
1082
- client._setBlockers("i-test2", [
1083
- {
1084
- id: "i-test1",
1085
- uuid: "uuid-1",
1086
- title: "Test Issue 1",
1087
- content: "Test content",
1088
- status: "open",
1089
- priority: 1,
1090
- created_at: "2024-01-01T00:00:00Z",
1091
- updated_at: "2024-01-01T00:00:00Z",
1092
- },
1093
- ]);
1094
-
1095
- const blockers = await backend.getBlockers(task.id);
1096
-
1097
- // Should have both local and sudocode blockers
1098
- expect(blockers).toHaveLength(2);
1099
- expect(blockers.map((b) => b.id)).toContain(localBlocker.id);
1100
- expect(blockers.map((b) => b.id)).toContain(sudocodeBlocker.id);
1101
- });
1102
-
1103
- it("should merge local and sudocode blocking in getBlocking", async () => {
1104
- // Create a task bound to i-test1
1105
- const task = await backend.create({
1106
- description: "Test task",
1107
- created_by: "agent-1",
1108
- external_id: "i-test1",
1109
- });
1110
-
1111
- // Create a local blocked task (unbound)
1112
- const localBlocked = await backend.create({
1113
- description: "Local blocked",
1114
- created_by: "agent-1",
1115
- });
1116
- await backend.addBlocker(localBlocked.id, task.id);
1117
-
1118
- // Create a task bound to i-test2 (sudocode blocked)
1119
- const sudocodeBlocked = await backend.create({
1120
- description: "Sudocode blocked",
1121
- created_by: "agent-1",
1122
- external_id: "i-test2",
1123
- });
1124
-
1125
- // Set up sudocode to report i-test1 blocks i-test2
1126
- client._setBlocking("i-test1", [
1127
- {
1128
- id: "i-test2",
1129
- uuid: "uuid-2",
1130
- title: "Test Issue 2",
1131
- content: "Test content",
1132
- status: "open",
1133
- priority: 2,
1134
- created_at: "2024-01-01T00:00:00Z",
1135
- updated_at: "2024-01-01T00:00:00Z",
1136
- },
1137
- ]);
1138
-
1139
- const blocking = await backend.getBlocking(task.id);
1140
-
1141
- // Should have both local and sudocode blocked tasks
1142
- expect(blocking).toHaveLength(2);
1143
- expect(blocking.map((b) => b.id)).toContain(localBlocked.id);
1144
- expect(blocking.map((b) => b.id)).toContain(sudocodeBlocked.id);
1145
- });
1146
-
1147
- it("should deduplicate when same task is both local and sudocode blocker", async () => {
1148
- // Create blocker bound to i-test1
1149
- const blocker = await backend.create({
1150
- description: "Blocker task",
1151
- created_by: "agent-1",
1152
- external_id: "i-test1",
1153
- });
1154
-
1155
- // Create blocked task bound to i-test2
1156
- const blocked = await backend.create({
1157
- description: "Blocked task",
1158
- created_by: "agent-1",
1159
- external_id: "i-test2",
1160
- });
1161
-
1162
- // Add as local blocker
1163
- await backend.addBlocker(blocked.id, blocker.id);
1164
-
1165
- // Also set up sudocode to report the same relationship
1166
- client._setBlockers("i-test2", [
1167
- {
1168
- id: "i-test1",
1169
- uuid: "uuid-1",
1170
- title: "Test Issue 1",
1171
- content: "Test content",
1172
- status: "open",
1173
- priority: 1,
1174
- created_at: "2024-01-01T00:00:00Z",
1175
- updated_at: "2024-01-01T00:00:00Z",
1176
- },
1177
- ]);
1178
-
1179
- const blockers = await backend.getBlockers(blocked.id);
1180
-
1181
- // Should only have one blocker (deduplicated)
1182
- expect(blockers).toHaveLength(1);
1183
- expect(blockers[0].id).toBe(blocker.id);
1184
- });
1185
- });
1186
-
1187
- describe("createSudocodeTaskBackend", () => {
1188
- it("should create a backend instance", () => {
1189
- const backend = createSudocodeTaskBackend(eventStore, client);
1190
- expect(backend).toBeInstanceOf(SudocodeTaskBackend);
1191
- backend.close();
1192
- });
1193
- });
1194
- });