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
@@ -0,0 +1,1023 @@
1
+ /**
2
+ * OpenTasksTaskBackend Implementation
3
+ *
4
+ * Implements TaskBackend using OpenTasks as the source of truth for task storage,
5
+ * with EventStore for local event tracking and subscriptions.
6
+ *
7
+ * Tasks are stored as OpenTasks issues. Blocking dependencies use OpenTasks
8
+ * 'blocks' edges. The pull model uses OpenTasks' ready query and claimed_by field.
9
+ *
10
+ * @module task/backend/opentasks/backend
11
+ */
12
+ import { nanoid } from "nanoid";
13
+ import { mapOpenTasksStatus, mapTaskStatus, isIssueComplete } from "./mapping.js";
14
+ // Valid status transitions
15
+ const VALID_STATUS_TRANSITIONS = {
16
+ pending: ["assigned", "in_progress", "failed"],
17
+ assigned: ["in_progress", "pending", "failed"],
18
+ in_progress: ["completed", "failed", "pending"],
19
+ completed: [],
20
+ failed: ["pending"],
21
+ };
22
+ /**
23
+ * Error thrown by OpenTasksTaskBackend operations
24
+ */
25
+ export class OpenTasksBackendError extends Error {
26
+ code;
27
+ taskId;
28
+ constructor(message, code, taskId) {
29
+ super(message);
30
+ this.code = code;
31
+ this.taskId = taskId;
32
+ this.name = "OpenTasksBackendError";
33
+ }
34
+ }
35
+ const DEFAULT_CONFIG = {
36
+ socketPath: "",
37
+ syncStatus: true,
38
+ sourceLabel: "macro-agent",
39
+ };
40
+ /**
41
+ * OpenTasksTaskBackend implements TaskBackend using:
42
+ * - OpenTasks daemon for issue storage and graph relationships
43
+ * - EventStore for local event tracking and subscriptions
44
+ *
45
+ * Key features:
46
+ * - Tasks are stored as OpenTasks issues with macro-agent metadata
47
+ * - Blocking dependencies use OpenTasks 'blocks' edges
48
+ * - Pull model uses OpenTasks ready query and claimed_by
49
+ * - Bidirectional ID mapping (task_id <-> issue_id) via metadata
50
+ */
51
+ export class OpenTasksTaskBackend {
52
+ eventStore;
53
+ client;
54
+ config;
55
+ closed = false;
56
+ /** Map from macro-agent task ID to OpenTasks issue ID */
57
+ taskToIssue = new Map();
58
+ /** Map from OpenTasks issue ID to macro-agent task ID */
59
+ issueToTask = new Map();
60
+ constructor(eventStore, client, config) {
61
+ this.eventStore = eventStore;
62
+ this.client = client;
63
+ this.config = { ...DEFAULT_CONFIG, ...config };
64
+ }
65
+ /**
66
+ * Throw if the backend has been closed.
67
+ */
68
+ ensureOpen() {
69
+ if (this.closed) {
70
+ throw new OpenTasksBackendError("Backend is closed", "BACKEND_CLOSED");
71
+ }
72
+ }
73
+ // ─────────────────────────────────────────────────────────────────────────────
74
+ // Lifecycle
75
+ // ─────────────────────────────────────────────────────────────────────────────
76
+ async close() {
77
+ this.closed = true;
78
+ }
79
+ async create(options) {
80
+ this.ensureOpen();
81
+ const taskId = `task_${nanoid(12)}`;
82
+ // Resolve parent issue ID if parent task specified
83
+ let parentIssueId;
84
+ if (options.parent_task) {
85
+ parentIssueId = this.taskToIssue.get(options.parent_task);
86
+ if (!parentIssueId) {
87
+ // Check EventStore as fallback
88
+ const parent = this.eventStore.getTask(options.parent_task);
89
+ if (!parent) {
90
+ throw new OpenTasksBackendError(`Parent task not found: ${options.parent_task}`, "PARENT_TASK_NOT_FOUND", options.parent_task);
91
+ }
92
+ }
93
+ }
94
+ // Create issue in OpenTasks
95
+ const issue = await this.client.createIssue({
96
+ title: options.description,
97
+ status: "open",
98
+ tags: options.tags,
99
+ parent_id: parentIssueId,
100
+ metadata: {
101
+ macro_agent_task_id: taskId,
102
+ created_by: options.created_by,
103
+ source: this.config.sourceLabel,
104
+ },
105
+ });
106
+ // Store bidirectional mapping
107
+ this.taskToIssue.set(taskId, issue.id);
108
+ this.issueToTask.set(issue.id, taskId);
109
+ // Emit to EventStore for local tracking
110
+ this.eventStore.emit({
111
+ type: "task",
112
+ source: { agent_id: options.created_by },
113
+ payload: {
114
+ task_id: taskId,
115
+ action: "created",
116
+ details: {
117
+ description: options.description,
118
+ parent_task: options.parent_task,
119
+ tags: options.tags,
120
+ external_id: issue.id,
121
+ },
122
+ },
123
+ });
124
+ // Update parent subtasks in EventStore
125
+ if (options.parent_task) {
126
+ this.eventStore.emit({
127
+ type: "task",
128
+ source: { agent_id: options.created_by },
129
+ payload: {
130
+ task_id: options.parent_task,
131
+ action: "status_change",
132
+ details: { subtask_added: taskId },
133
+ },
134
+ });
135
+ }
136
+ // Return from EventStore (which has the canonical local state)
137
+ const task = this.eventStore.getTask(taskId);
138
+ return this.toExtendedTask(task);
139
+ }
140
+ async get(id) {
141
+ // EventStore is the local mirror with richer state
142
+ // (assigned status, outputs, agent_history, etc.)
143
+ const task = this.eventStore.getTask(id);
144
+ if (!task)
145
+ return null;
146
+ return this.toExtendedTask(task);
147
+ }
148
+ async update(id, updates) {
149
+ this.ensureOpen();
150
+ const task = this.eventStore.getTask(id);
151
+ if (!task) {
152
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
153
+ }
154
+ const source = task.assigned_agent ?? task.created_by;
155
+ // Handle status update with validation
156
+ if (updates.status !== undefined) {
157
+ const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
158
+ if (!validTransitions.includes(updates.status)) {
159
+ throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> ${updates.status}`, "INVALID_STATUS_TRANSITION", id);
160
+ }
161
+ this.eventStore.emit({
162
+ type: "task",
163
+ source: { agent_id: source },
164
+ payload: {
165
+ task_id: id,
166
+ action: "status_change",
167
+ details: { status: updates.status },
168
+ },
169
+ });
170
+ // Sync to OpenTasks
171
+ await this.syncStatusToOpenTasks(id, updates.status);
172
+ }
173
+ // Handle other updates
174
+ if (updates.outputs !== undefined) {
175
+ this.eventStore.emit({
176
+ type: "task",
177
+ source: { agent_id: source },
178
+ payload: {
179
+ task_id: id,
180
+ action: "status_change",
181
+ details: { outputs: updates.outputs },
182
+ },
183
+ });
184
+ }
185
+ if (updates.artifacts !== undefined) {
186
+ this.eventStore.emit({
187
+ type: "task",
188
+ source: { agent_id: source },
189
+ payload: {
190
+ task_id: id,
191
+ action: "status_change",
192
+ details: { artifacts: updates.artifacts },
193
+ },
194
+ });
195
+ }
196
+ if (updates.description !== undefined) {
197
+ this.eventStore.emit({
198
+ type: "task",
199
+ source: { agent_id: source },
200
+ payload: {
201
+ task_id: id,
202
+ action: "status_change",
203
+ details: { description: updates.description },
204
+ },
205
+ });
206
+ // Sync description to OpenTasks
207
+ const issueId = this.taskToIssue.get(id);
208
+ if (issueId) {
209
+ await this.client.updateIssue(issueId, {
210
+ title: updates.description,
211
+ });
212
+ }
213
+ }
214
+ const updated = this.eventStore.getTask(id);
215
+ return this.toExtendedTask(updated);
216
+ }
217
+ async delete(id) {
218
+ this.ensureOpen();
219
+ const issueId = this.taskToIssue.get(id);
220
+ if (issueId) {
221
+ await this.client.deleteIssue(issueId);
222
+ this.taskToIssue.delete(id);
223
+ this.issueToTask.delete(issueId);
224
+ }
225
+ }
226
+ // ─────────────────────────────────────────────────────────────────────────────
227
+ // Status Transitions
228
+ // ─────────────────────────────────────────────────────────────────────────────
229
+ async assign(id, agentId, options) {
230
+ this.ensureOpen();
231
+ const task = this.eventStore.getTask(id);
232
+ if (!task) {
233
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
234
+ }
235
+ this.eventStore.emit({
236
+ type: "task",
237
+ source: { agent_id: agentId },
238
+ payload: {
239
+ task_id: id,
240
+ action: "assigned",
241
+ details: {
242
+ agent_id: agentId,
243
+ role: options?.role,
244
+ },
245
+ },
246
+ });
247
+ // Sync assignee to OpenTasks
248
+ const issueId = this.taskToIssue.get(id);
249
+ if (issueId) {
250
+ await this.client.updateIssue(issueId, {
251
+ assignee: agentId,
252
+ metadata: { claimed_by: agentId },
253
+ });
254
+ }
255
+ }
256
+ async unassign(id) {
257
+ this.ensureOpen();
258
+ const task = this.eventStore.getTask(id);
259
+ if (!task) {
260
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
261
+ }
262
+ if (!task.assigned_agent) {
263
+ throw new OpenTasksBackendError(`Task is not assigned: ${id}`, "TASK_NOT_ASSIGNED", id);
264
+ }
265
+ this.eventStore.emit({
266
+ type: "task",
267
+ source: { agent_id: task.assigned_agent },
268
+ payload: {
269
+ task_id: id,
270
+ action: "unassigned",
271
+ details: { agent_id: task.assigned_agent },
272
+ },
273
+ });
274
+ // Clear assignee in OpenTasks
275
+ const issueId = this.taskToIssue.get(id);
276
+ if (issueId) {
277
+ await this.client.updateIssue(issueId, {
278
+ assignee: null,
279
+ metadata: { claimed_by: null },
280
+ });
281
+ }
282
+ }
283
+ async start(id) {
284
+ this.ensureOpen();
285
+ const task = this.eventStore.getTask(id);
286
+ if (!task) {
287
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
288
+ }
289
+ const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
290
+ if (!validTransitions.includes("in_progress")) {
291
+ throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> in_progress`, "INVALID_STATUS_TRANSITION", id);
292
+ }
293
+ this.eventStore.emit({
294
+ type: "task",
295
+ source: { agent_id: task.assigned_agent ?? task.created_by },
296
+ payload: {
297
+ task_id: id,
298
+ action: "status_change",
299
+ details: { status: "in_progress" },
300
+ },
301
+ });
302
+ await this.syncStatusToOpenTasks(id, "in_progress");
303
+ }
304
+ async complete(id, outputs) {
305
+ this.ensureOpen();
306
+ const task = this.eventStore.getTask(id);
307
+ if (!task) {
308
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
309
+ }
310
+ const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
311
+ if (!validTransitions.includes("completed")) {
312
+ throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> completed`, "INVALID_STATUS_TRANSITION", id);
313
+ }
314
+ const agent = task.assigned_agent ?? task.created_by;
315
+ // Store outputs
316
+ if (outputs) {
317
+ const outputsToStore = {
318
+ ...(outputs.data ?? {}),
319
+ };
320
+ if (outputs.summary !== undefined) {
321
+ outputsToStore.summary = outputs.summary;
322
+ }
323
+ if (Object.keys(outputsToStore).length > 0) {
324
+ this.eventStore.emit({
325
+ type: "task",
326
+ source: { agent_id: agent },
327
+ payload: {
328
+ task_id: id,
329
+ action: "status_change",
330
+ details: { outputs: outputsToStore },
331
+ },
332
+ });
333
+ }
334
+ if (outputs.artifacts) {
335
+ this.eventStore.emit({
336
+ type: "task",
337
+ source: { agent_id: agent },
338
+ payload: {
339
+ task_id: id,
340
+ action: "status_change",
341
+ details: { artifacts: outputs.artifacts },
342
+ },
343
+ });
344
+ }
345
+ }
346
+ this.eventStore.emit({
347
+ type: "task",
348
+ source: { agent_id: agent },
349
+ payload: {
350
+ task_id: id,
351
+ action: "completed",
352
+ details: {},
353
+ },
354
+ });
355
+ // Close the issue in OpenTasks
356
+ await this.syncStatusToOpenTasks(id, "completed");
357
+ }
358
+ async fail(id, error) {
359
+ this.ensureOpen();
360
+ const task = this.eventStore.getTask(id);
361
+ if (!task) {
362
+ throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
363
+ }
364
+ const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
365
+ if (!validTransitions.includes("failed")) {
366
+ throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> failed`, "INVALID_STATUS_TRANSITION", id);
367
+ }
368
+ const agent = task.assigned_agent ?? task.created_by;
369
+ // Store error in outputs
370
+ this.eventStore.emit({
371
+ type: "task",
372
+ source: { agent_id: agent },
373
+ payload: {
374
+ task_id: id,
375
+ action: "status_change",
376
+ details: {
377
+ outputs: {
378
+ error: {
379
+ message: error.message,
380
+ code: error.code,
381
+ details: error.details,
382
+ },
383
+ },
384
+ },
385
+ },
386
+ });
387
+ this.eventStore.emit({
388
+ type: "task",
389
+ source: { agent_id: agent },
390
+ payload: {
391
+ task_id: id,
392
+ action: "failed",
393
+ details: {},
394
+ },
395
+ });
396
+ // Close in OpenTasks with error metadata
397
+ const issueId = this.taskToIssue.get(id);
398
+ if (issueId) {
399
+ await this.client.updateIssue(issueId, {
400
+ status: "closed",
401
+ metadata: {
402
+ macro_agent_failed: true,
403
+ macro_agent_error: error.message,
404
+ },
405
+ });
406
+ }
407
+ }
408
+ // ─────────────────────────────────────────────────────────────────────────────
409
+ // Queries
410
+ // ─────────────────────────────────────────────────────────────────────────────
411
+ async list(filter) {
412
+ let tasks = this.eventStore.listTasks();
413
+ if (filter) {
414
+ if (filter.status) {
415
+ const statuses = Array.isArray(filter.status)
416
+ ? filter.status
417
+ : [filter.status];
418
+ tasks = tasks.filter((t) => statuses.includes(t.status));
419
+ }
420
+ if (filter.assigned_agent) {
421
+ tasks = tasks.filter((t) => t.assigned_agent === filter.assigned_agent);
422
+ }
423
+ if (filter.parent_task) {
424
+ tasks = tasks.filter((t) => t.parent_task === filter.parent_task);
425
+ }
426
+ if (filter.created_by) {
427
+ tasks = tasks.filter((t) => t.created_by === filter.created_by);
428
+ }
429
+ if (filter.rootTasksOnly) {
430
+ tasks = tasks.filter((t) => !t.parent_task);
431
+ }
432
+ if (filter.tags && filter.tags.length > 0) {
433
+ const filterTags = new Set(filter.tags);
434
+ tasks = tasks.filter((t) => t.tags?.some((tag) => filterTags.has(tag)));
435
+ }
436
+ }
437
+ // Compute isBlocked using OpenTasks graph for mapped tasks,
438
+ // EventStore blockers for unmapped tasks
439
+ const extended = await Promise.all(tasks.map((t) => this.toExtendedTaskAsync(t)));
440
+ if (!filter?.includeBlocked) {
441
+ return extended.filter((t) => !t.isBlocked);
442
+ }
443
+ return extended;
444
+ }
445
+ async listReady(filter) {
446
+ return this.list({
447
+ ...filter,
448
+ status: filter?.status ?? ["pending", "assigned"],
449
+ includeBlocked: false,
450
+ });
451
+ }
452
+ async getChildren(parentId) {
453
+ const tasks = this.eventStore.listTasks();
454
+ const children = tasks.filter((t) => t.parent_task === parentId);
455
+ return Promise.all(children.map((t) => this.toExtendedTaskAsync(t)));
456
+ }
457
+ async getSubtaskStatus(parentId) {
458
+ const children = await this.getChildren(parentId);
459
+ const status = {
460
+ total: children.length,
461
+ pending: 0,
462
+ assigned: 0,
463
+ in_progress: 0,
464
+ completed: 0,
465
+ failed: 0,
466
+ allCompleted: false,
467
+ anyFailed: false,
468
+ };
469
+ for (const task of children) {
470
+ switch (task.status) {
471
+ case "pending":
472
+ status.pending++;
473
+ break;
474
+ case "assigned":
475
+ status.assigned++;
476
+ break;
477
+ case "in_progress":
478
+ status.in_progress++;
479
+ break;
480
+ case "completed":
481
+ status.completed++;
482
+ break;
483
+ case "failed":
484
+ status.failed++;
485
+ break;
486
+ }
487
+ }
488
+ status.allCompleted =
489
+ status.total > 0 && status.completed === status.total;
490
+ status.anyFailed = status.failed > 0;
491
+ return status;
492
+ }
493
+ // ─────────────────────────────────────────────────────────────────────────────
494
+ // Hierarchy
495
+ // ─────────────────────────────────────────────────────────────────────────────
496
+ async createSubtask(parentId, options) {
497
+ return this.create({
498
+ ...options,
499
+ parent_task: parentId,
500
+ });
501
+ }
502
+ // ─────────────────────────────────────────────────────────────────────────────
503
+ // Dependencies (via OpenTasks edges)
504
+ // ─────────────────────────────────────────────────────────────────────────────
505
+ async addBlocker(taskId, blockerId) {
506
+ this.ensureOpen();
507
+ const task = this.eventStore.getTask(taskId);
508
+ if (!task) {
509
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
510
+ }
511
+ const blocker = this.eventStore.getTask(blockerId);
512
+ if (!blocker) {
513
+ throw new OpenTasksBackendError(`Blocker task not found: ${blockerId}`, "TASK_NOT_FOUND", blockerId);
514
+ }
515
+ // Record in EventStore
516
+ this.eventStore.emit({
517
+ type: "task",
518
+ source: { agent_id: task.assigned_agent ?? task.created_by },
519
+ payload: {
520
+ task_id: taskId,
521
+ action: "blocker_added",
522
+ details: { blocker_id: blockerId },
523
+ },
524
+ });
525
+ // Create 'blocks' edge in OpenTasks if both tasks are mapped
526
+ const blockerIssueId = this.taskToIssue.get(blockerId);
527
+ const taskIssueId = this.taskToIssue.get(taskId);
528
+ if (blockerIssueId && taskIssueId) {
529
+ await this.client.createEdge(blockerIssueId, taskIssueId, "blocks");
530
+ }
531
+ }
532
+ async removeBlocker(taskId, blockerId) {
533
+ this.ensureOpen();
534
+ const task = this.eventStore.getTask(taskId);
535
+ if (!task) {
536
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
537
+ }
538
+ // Record in EventStore
539
+ this.eventStore.emit({
540
+ type: "task",
541
+ source: { agent_id: task.assigned_agent ?? task.created_by },
542
+ payload: {
543
+ task_id: taskId,
544
+ action: "blocker_removed",
545
+ details: { blocker_id: blockerId },
546
+ },
547
+ });
548
+ // Remove 'blocks' edge in OpenTasks if both are mapped
549
+ const blockerIssueId = this.taskToIssue.get(blockerId);
550
+ const taskIssueId = this.taskToIssue.get(taskId);
551
+ if (blockerIssueId && taskIssueId) {
552
+ await this.client.removeEdge(blockerIssueId, taskIssueId, "blocks");
553
+ }
554
+ }
555
+ async getBlockers(taskId) {
556
+ const task = this.eventStore.getTask(taskId);
557
+ if (!task) {
558
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
559
+ }
560
+ // Try OpenTasks first for mapped tasks
561
+ const issueId = this.taskToIssue.get(taskId);
562
+ if (issueId) {
563
+ try {
564
+ const blockerSummaries = await this.client.getBlockers(issueId);
565
+ const blockers = [];
566
+ for (const summary of blockerSummaries) {
567
+ const blockerTaskId = this.issueToTask.get(summary.id);
568
+ if (blockerTaskId) {
569
+ const blockerTask = this.eventStore.getTask(blockerTaskId);
570
+ if (blockerTask) {
571
+ blockers.push(this.toExtendedTask(blockerTask));
572
+ }
573
+ }
574
+ }
575
+ return blockers;
576
+ }
577
+ catch {
578
+ // Fall through to EventStore
579
+ }
580
+ }
581
+ // Fallback: use EventStore blockers
582
+ const blockerIds = task.blockers ?? [];
583
+ const blockers = [];
584
+ for (const blockerId of blockerIds) {
585
+ const blocker = this.eventStore.getTask(blockerId);
586
+ if (blocker) {
587
+ blockers.push(this.toExtendedTask(blocker));
588
+ }
589
+ }
590
+ return blockers;
591
+ }
592
+ async getBlocking(taskId) {
593
+ const task = this.eventStore.getTask(taskId);
594
+ if (!task) {
595
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
596
+ }
597
+ // Try OpenTasks first for mapped tasks
598
+ const issueId = this.taskToIssue.get(taskId);
599
+ if (issueId) {
600
+ try {
601
+ const blockingSummaries = await this.client.getBlocking(issueId);
602
+ const blocking = [];
603
+ for (const summary of blockingSummaries) {
604
+ const blockedTaskId = this.issueToTask.get(summary.id);
605
+ if (blockedTaskId) {
606
+ const blockedTask = this.eventStore.getTask(blockedTaskId);
607
+ if (blockedTask) {
608
+ blocking.push(this.toExtendedTask(blockedTask));
609
+ }
610
+ }
611
+ }
612
+ return blocking;
613
+ }
614
+ catch {
615
+ // Fall through to EventStore
616
+ }
617
+ }
618
+ // Fallback: scan EventStore
619
+ const allTasks = this.eventStore.listTasks();
620
+ const blocking = allTasks.filter((t) => t.blockers?.includes(taskId));
621
+ return blocking.map((t) => this.toExtendedTask(t));
622
+ }
623
+ // ─────────────────────────────────────────────────────────────────────────────
624
+ // Pull Model (Claim/Unclaim)
625
+ // ─────────────────────────────────────────────────────────────────────────────
626
+ async claim(agentId, filter) {
627
+ this.ensureOpen();
628
+ const candidates = await this.listClaimable(filter);
629
+ if (candidates.length === 0) {
630
+ return null;
631
+ }
632
+ const task = candidates[0];
633
+ // Re-check for contention
634
+ const current = this.eventStore.getTask(task.id);
635
+ if (!current || current.status !== "pending" || current.assigned_agent) {
636
+ return null;
637
+ }
638
+ // Assign locally
639
+ this.eventStore.emit({
640
+ type: "task",
641
+ source: { agent_id: agentId },
642
+ payload: {
643
+ task_id: task.id,
644
+ action: "assigned",
645
+ details: { agent_id: agentId },
646
+ },
647
+ });
648
+ // Claim in OpenTasks
649
+ const issueId = this.taskToIssue.get(task.id);
650
+ if (issueId) {
651
+ await this.client.updateIssue(issueId, {
652
+ assignee: agentId,
653
+ metadata: { claimed_by: agentId },
654
+ });
655
+ }
656
+ const assigned = this.eventStore.getTask(task.id);
657
+ return this.toExtendedTask(assigned);
658
+ }
659
+ async unclaim(taskId) {
660
+ this.ensureOpen();
661
+ const task = this.eventStore.getTask(taskId);
662
+ if (!task) {
663
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
664
+ }
665
+ if (!task.assigned_agent) {
666
+ throw new OpenTasksBackendError(`Task is not assigned: ${taskId}`, "TASK_NOT_ASSIGNED", taskId);
667
+ }
668
+ this.eventStore.emit({
669
+ type: "task",
670
+ source: { agent_id: task.assigned_agent },
671
+ payload: {
672
+ task_id: taskId,
673
+ action: "unassigned",
674
+ details: { agent_id: task.assigned_agent },
675
+ },
676
+ });
677
+ // Unclaim in OpenTasks
678
+ const issueId = this.taskToIssue.get(taskId);
679
+ if (issueId) {
680
+ await this.client.updateIssue(issueId, {
681
+ assignee: null,
682
+ metadata: { claimed_by: null },
683
+ });
684
+ }
685
+ }
686
+ async listClaimable(filter) {
687
+ let tasks = this.eventStore.listTasks();
688
+ // Only pending, unassigned tasks
689
+ tasks = tasks.filter((t) => t.status === "pending" && !t.assigned_agent);
690
+ if (filter) {
691
+ if (filter.tags && filter.tags.length > 0) {
692
+ const filterTags = new Set(filter.tags);
693
+ tasks = tasks.filter((t) => t.tags?.some((tag) => filterTags.has(tag)));
694
+ }
695
+ if (filter.rootTasksOnly) {
696
+ tasks = tasks.filter((t) => !t.parent_task);
697
+ }
698
+ if (filter.created_by) {
699
+ tasks = tasks.filter((t) => t.created_by === filter.created_by);
700
+ }
701
+ }
702
+ // Filter out blocked tasks
703
+ const extended = await Promise.all(tasks.map((t) => this.toExtendedTaskAsync(t)));
704
+ return extended.filter((t) => !t.isBlocked);
705
+ }
706
+ // ─────────────────────────────────────────────────────────────────────────────
707
+ // History
708
+ // ─────────────────────────────────────────────────────────────────────────────
709
+ async getAgentHistory(taskId) {
710
+ const task = this.eventStore.getTask(taskId);
711
+ if (!task) {
712
+ throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
713
+ }
714
+ return task.agent_history ?? [];
715
+ }
716
+ onTaskChange(callbackOrTaskId, maybeCallback) {
717
+ const filterTaskId = typeof callbackOrTaskId === "string" ? callbackOrTaskId : undefined;
718
+ const callback = typeof callbackOrTaskId === "function"
719
+ ? callbackOrTaskId
720
+ : maybeCallback;
721
+ const seenTaskIds = new Set();
722
+ return this.eventStore.onTaskChange((taskId, task) => {
723
+ if (filterTaskId && taskId !== filterTaskId)
724
+ return;
725
+ let eventType;
726
+ if (!task) {
727
+ eventType = "deleted";
728
+ }
729
+ else if (seenTaskIds.has(taskId)) {
730
+ eventType = "updated";
731
+ }
732
+ else {
733
+ eventType = "created";
734
+ seenTaskIds.add(taskId);
735
+ }
736
+ const event = {
737
+ type: eventType,
738
+ taskId,
739
+ task: task ? this.toExtendedTask(task) : {},
740
+ };
741
+ callback(event);
742
+ });
743
+ }
744
+ // ─────────────────────────────────────────────────────────────────────────────
745
+ // Public Utility Methods
746
+ // ─────────────────────────────────────────────────────────────────────────────
747
+ /**
748
+ * Get the OpenTasks issue ID for a macro-agent task.
749
+ * Returns undefined if the task is not mapped to an issue.
750
+ */
751
+ getIssueForTask(taskId) {
752
+ return this.taskToIssue.get(taskId);
753
+ }
754
+ /**
755
+ * Get the macro-agent task ID for an OpenTasks issue.
756
+ * Returns undefined if the issue is not mapped to a task.
757
+ */
758
+ getTaskForIssue(issueId) {
759
+ return this.issueToTask.get(issueId);
760
+ }
761
+ /**
762
+ * Import an existing OpenTasks issue as a macro-agent task.
763
+ * This is useful for pulling tasks from OpenTasks into macro-agent.
764
+ */
765
+ async importIssue(issueId, createdBy) {
766
+ this.ensureOpen();
767
+ // Check if already imported
768
+ const existingTaskId = this.issueToTask.get(issueId);
769
+ if (existingTaskId) {
770
+ const existing = await this.get(existingTaskId);
771
+ if (existing)
772
+ return existing;
773
+ }
774
+ const issue = await this.client.getIssue(issueId);
775
+ if (!issue) {
776
+ throw new OpenTasksBackendError(`OpenTasks issue not found: ${issueId}`, "NOT_FOUND");
777
+ }
778
+ const taskId = `task_${nanoid(12)}`;
779
+ // Store mapping
780
+ this.taskToIssue.set(taskId, issueId);
781
+ this.issueToTask.set(issueId, taskId);
782
+ // Determine task status from issue
783
+ const taskStatus = mapOpenTasksStatus(issue.status);
784
+ // Create in EventStore
785
+ this.eventStore.emit({
786
+ type: "task",
787
+ source: { agent_id: createdBy },
788
+ payload: {
789
+ task_id: taskId,
790
+ action: "created",
791
+ details: {
792
+ description: issue.title,
793
+ tags: issue.tags,
794
+ external_id: issueId,
795
+ },
796
+ },
797
+ });
798
+ // If issue is not open/pending, transition to the right status
799
+ if (taskStatus === "in_progress") {
800
+ this.eventStore.emit({
801
+ type: "task",
802
+ source: { agent_id: createdBy },
803
+ payload: {
804
+ task_id: taskId,
805
+ action: "status_change",
806
+ details: { status: "in_progress" },
807
+ },
808
+ });
809
+ }
810
+ else if (taskStatus === "completed") {
811
+ this.eventStore.emit({
812
+ type: "task",
813
+ source: { agent_id: createdBy },
814
+ payload: {
815
+ task_id: taskId,
816
+ action: "completed",
817
+ details: {},
818
+ },
819
+ });
820
+ }
821
+ // If issue has an assignee, assign
822
+ if (issue.assignee) {
823
+ this.eventStore.emit({
824
+ type: "task",
825
+ source: { agent_id: issue.assignee },
826
+ payload: {
827
+ task_id: taskId,
828
+ action: "assigned",
829
+ details: { agent_id: issue.assignee },
830
+ },
831
+ });
832
+ }
833
+ return this.issueToExtendedTask(issue, taskId);
834
+ }
835
+ /**
836
+ * Bulk import all open issues from OpenTasks as tasks.
837
+ */
838
+ async importOpenIssues(createdBy) {
839
+ this.ensureOpen();
840
+ const issues = await this.client.listIssues({
841
+ status: ["open", "in_progress"],
842
+ archived: false,
843
+ });
844
+ const tasks = [];
845
+ for (const issue of issues) {
846
+ // Skip already-imported issues
847
+ if (this.issueToTask.has(issue.id))
848
+ continue;
849
+ // Skip issues not created by macro-agent (unless they have no source)
850
+ // This allows importing issues from other sources too
851
+ const task = await this.importIssue(issue.id, createdBy);
852
+ tasks.push(task);
853
+ }
854
+ return tasks;
855
+ }
856
+ // ─────────────────────────────────────────────────────────────────────────────
857
+ // Private Helpers
858
+ // ─────────────────────────────────────────────────────────────────────────────
859
+ /**
860
+ * Sync a task status change to OpenTasks.
861
+ */
862
+ async syncStatusToOpenTasks(taskId, status) {
863
+ if (!this.config.syncStatus)
864
+ return;
865
+ const issueId = this.taskToIssue.get(taskId);
866
+ if (!issueId)
867
+ return;
868
+ const openTasksStatus = mapTaskStatus(status);
869
+ try {
870
+ await this.client.updateIssue(issueId, {
871
+ status: openTasksStatus,
872
+ });
873
+ }
874
+ catch (error) {
875
+ // Log but don't fail - sync is best-effort
876
+ console.warn(`Failed to sync status to OpenTasks for ${taskId} (${issueId}): ${error}`);
877
+ }
878
+ }
879
+ /**
880
+ * Sync a transition that happened via the opentasks daemon's `task` tool.
881
+ * Updates the EventStore without re-syncing back to opentasks (since the
882
+ * daemon already processed the transition).
883
+ *
884
+ * Accepts either an opentasks issue ID (e.g., "i-xxxx") or an EventStore
885
+ * task ID (e.g., "task-xxx") — resolves to the EventStore ID either way.
886
+ *
887
+ * @param externalId - The opentasks issue ID or EventStore task ID
888
+ * @param action - The transition action ("complete", "start", "close", "block", "reopen", "assign")
889
+ * @param agentId - The agent that performed the transition or the assignee for "assign"
890
+ */
891
+ async syncExternalTransition(externalId, action, agentId) {
892
+ // Resolve to EventStore task ID: try opentasks ID lookup first, then direct
893
+ const taskId = this.issueToTask.get(externalId)
894
+ ?? (this.eventStore.getTask(externalId) ? externalId : undefined);
895
+ if (!taskId)
896
+ return;
897
+ const task = this.eventStore.getTask(taskId);
898
+ if (!task)
899
+ return;
900
+ const agent = agentId ?? task.assigned_agent ?? task.created_by;
901
+ // Handle assignment separately — it updates assignee, not status
902
+ if (action === "assign") {
903
+ if (task.assigned_agent !== agent) {
904
+ this.eventStore.emit({
905
+ type: "task",
906
+ source: { agent_id: agent },
907
+ payload: {
908
+ task_id: taskId,
909
+ action: "assigned",
910
+ details: { agent_id: agent },
911
+ },
912
+ });
913
+ }
914
+ return;
915
+ }
916
+ // Map action to target status
917
+ const ACTION_TO_STATUS = {
918
+ complete: "completed",
919
+ close: "completed",
920
+ start: "in_progress",
921
+ block: "pending",
922
+ reopen: "pending",
923
+ };
924
+ const targetStatus = ACTION_TO_STATUS[action];
925
+ if (!targetStatus || task.status === targetStatus)
926
+ return;
927
+ // Emit the appropriate EventStore event
928
+ if (targetStatus === "completed") {
929
+ this.eventStore.emit({
930
+ type: "task",
931
+ source: { agent_id: agent },
932
+ payload: { task_id: taskId, action: "completed", details: {} },
933
+ });
934
+ }
935
+ else {
936
+ this.eventStore.emit({
937
+ type: "task",
938
+ source: { agent_id: agent },
939
+ payload: {
940
+ task_id: taskId,
941
+ action: "status_change",
942
+ details: { status: targetStatus },
943
+ },
944
+ });
945
+ }
946
+ }
947
+ /**
948
+ * Convert an EventStore Task to ExtendedTask with isBlocked computed
949
+ * from local blockers.
950
+ */
951
+ toExtendedTask(task) {
952
+ const blockerIds = task.blockers ?? [];
953
+ let isBlocked = false;
954
+ for (const blockerId of blockerIds) {
955
+ const blocker = this.eventStore.getTask(blockerId);
956
+ if (blocker && blocker.status !== "completed") {
957
+ isBlocked = true;
958
+ break;
959
+ }
960
+ }
961
+ return {
962
+ ...task,
963
+ isBlocked,
964
+ external_id: this.taskToIssue.get(task.id),
965
+ };
966
+ }
967
+ /**
968
+ * Convert an EventStore Task to ExtendedTask with isBlocked computed
969
+ * from OpenTasks graph (async, checks remote blockers).
970
+ */
971
+ async toExtendedTaskAsync(task) {
972
+ const issueId = this.taskToIssue.get(task.id);
973
+ // If mapped to OpenTasks, use graph-based blocking
974
+ if (issueId) {
975
+ try {
976
+ const blockers = await this.client.getBlockers(issueId);
977
+ const hasActiveBlockers = blockers.some((b) => b.status && !isIssueComplete(b.status));
978
+ return {
979
+ ...task,
980
+ isBlocked: hasActiveBlockers,
981
+ external_id: issueId,
982
+ };
983
+ }
984
+ catch {
985
+ // Fall through to local check
986
+ }
987
+ }
988
+ return this.toExtendedTask(task);
989
+ }
990
+ /**
991
+ * Convert an OpenTasks issue to an ExtendedTask.
992
+ */
993
+ issueToExtendedTask(issue, taskId) {
994
+ const taskStatus = mapOpenTasksStatus(issue.status);
995
+ return {
996
+ id: taskId,
997
+ description: issue.title,
998
+ status: taskStatus,
999
+ assigned_agent: issue.assignee,
1000
+ parent_task: undefined, // Resolved separately if needed
1001
+ subtasks: undefined,
1002
+ blockers: undefined,
1003
+ created_at: new Date(issue.created_at).getTime(),
1004
+ started_at: taskStatus === "in_progress"
1005
+ ? new Date(issue.updated_at).getTime()
1006
+ : undefined,
1007
+ completed_at: issue.closed_at
1008
+ ? new Date(issue.closed_at).getTime()
1009
+ : undefined,
1010
+ created_by: issue.metadata?.created_by ?? "unknown",
1011
+ tags: issue.tags,
1012
+ isBlocked: issue.status === "blocked",
1013
+ external_id: issue.id,
1014
+ };
1015
+ }
1016
+ }
1017
+ /**
1018
+ * Create an OpenTasksTaskBackend instance.
1019
+ */
1020
+ export function createOpenTasksTaskBackend(eventStore, client, config) {
1021
+ return new OpenTasksTaskBackend(eventStore, client, config);
1022
+ }
1023
+ //# sourceMappingURL=backend.js.map