macro-agent 0.1.1 → 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 (406) hide show
  1. package/.sudocode/issues.jsonl +28 -0
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +9 -3
  4. package/dist/agent/agent-manager.d.ts.map +1 -1
  5. package/dist/agent/agent-manager.js +111 -48
  6. package/dist/agent/agent-manager.js.map +1 -1
  7. package/dist/agent/types.d.ts +7 -0
  8. package/dist/agent/types.d.ts.map +1 -1
  9. package/dist/agent/types.js.map +1 -1
  10. package/dist/api/server.d.ts +5 -1
  11. package/dist/api/server.d.ts.map +1 -1
  12. package/dist/api/server.js +100 -3
  13. package/dist/api/server.js.map +1 -1
  14. package/dist/api/types.d.ts +1 -1
  15. package/dist/api/types.d.ts.map +1 -1
  16. package/dist/cli/acp.d.ts.map +1 -1
  17. package/dist/cli/acp.js +71 -1
  18. package/dist/cli/acp.js.map +1 -1
  19. package/dist/cli/index.js +5 -1
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/cli/mcp.js +27 -8
  22. package/dist/cli/mcp.js.map +1 -1
  23. package/dist/config/project-config.d.ts +13 -2
  24. package/dist/config/project-config.d.ts.map +1 -1
  25. package/dist/config/project-config.js +12 -2
  26. package/dist/config/project-config.js.map +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/lifecycle/handlers/index.d.ts +7 -3
  32. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  33. package/dist/lifecycle/handlers/index.js +25 -8
  34. package/dist/lifecycle/handlers/index.js.map +1 -1
  35. package/dist/lifecycle/types.d.ts +2 -0
  36. package/dist/lifecycle/types.d.ts.map +1 -1
  37. package/dist/lifecycle/types.js.map +1 -1
  38. package/dist/map/adapter/extensions/index.d.ts +4 -1
  39. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  40. package/dist/map/adapter/extensions/index.js +27 -0
  41. package/dist/map/adapter/extensions/index.js.map +1 -1
  42. package/dist/map/adapter/extensions/streams.d.ts +95 -0
  43. package/dist/map/adapter/extensions/streams.d.ts.map +1 -0
  44. package/dist/map/adapter/extensions/streams.js +515 -0
  45. package/dist/map/adapter/extensions/streams.js.map +1 -0
  46. package/dist/map/adapter/index.d.ts +1 -1
  47. package/dist/map/adapter/index.d.ts.map +1 -1
  48. package/dist/map/adapter/index.js +3 -1
  49. package/dist/map/adapter/index.js.map +1 -1
  50. package/dist/map/adapter/types.d.ts +1 -1
  51. package/dist/map/adapter/types.d.ts.map +1 -1
  52. package/dist/mcp/mcp-server.d.ts +2 -0
  53. package/dist/mcp/mcp-server.d.ts.map +1 -1
  54. package/dist/mcp/mcp-server.js +12 -3
  55. package/dist/mcp/mcp-server.js.map +1 -1
  56. package/dist/mcp/tools/done.d.ts.map +1 -1
  57. package/dist/mcp/tools/done.js +18 -0
  58. package/dist/mcp/tools/done.js.map +1 -1
  59. package/dist/roles/builtin/coordinator.d.ts.map +1 -1
  60. package/dist/roles/builtin/coordinator.js +2 -1
  61. package/dist/roles/builtin/coordinator.js.map +1 -1
  62. package/dist/roles/builtin/integrator.d.ts.map +1 -1
  63. package/dist/roles/builtin/integrator.js +2 -1
  64. package/dist/roles/builtin/integrator.js.map +1 -1
  65. package/dist/roles/builtin/worker.d.ts.map +1 -1
  66. package/dist/roles/builtin/worker.js +3 -1
  67. package/dist/roles/builtin/worker.js.map +1 -1
  68. package/dist/roles/capabilities.d.ts +6 -0
  69. package/dist/roles/capabilities.d.ts.map +1 -1
  70. package/dist/roles/capabilities.js +10 -0
  71. package/dist/roles/capabilities.js.map +1 -1
  72. package/dist/roles/config-loader.d.ts +1 -1
  73. package/dist/roles/config-loader.d.ts.map +1 -1
  74. package/dist/roles/config-loader.js +3 -2
  75. package/dist/roles/config-loader.js.map +1 -1
  76. package/dist/roles/types.d.ts +3 -1
  77. package/dist/roles/types.d.ts.map +1 -1
  78. package/dist/server/combined-server.d.ts +8 -1
  79. package/dist/server/combined-server.d.ts.map +1 -1
  80. package/dist/server/combined-server.js +6 -2
  81. package/dist/server/combined-server.js.map +1 -1
  82. package/dist/store/event-store.d.ts.map +1 -1
  83. package/dist/store/event-store.js +12 -5
  84. package/dist/store/event-store.js.map +1 -1
  85. package/dist/store/instance.d.ts +1 -1
  86. package/dist/store/instance.d.ts.map +1 -1
  87. package/dist/store/instance.js +2 -2
  88. package/dist/store/instance.js.map +1 -1
  89. package/dist/store/types/agents.d.ts +5 -0
  90. package/dist/store/types/agents.d.ts.map +1 -1
  91. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -1
  92. package/dist/task/backend/opentasks/daemon-manager.js +1 -1
  93. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -1
  94. package/dist/teams/index.d.ts +3 -1
  95. package/dist/teams/index.d.ts.map +1 -1
  96. package/dist/teams/index.js +2 -0
  97. package/dist/teams/index.js.map +1 -1
  98. package/dist/teams/seed-defaults.d.ts +20 -0
  99. package/dist/teams/seed-defaults.d.ts.map +1 -0
  100. package/dist/teams/seed-defaults.js +71 -0
  101. package/dist/teams/seed-defaults.js.map +1 -0
  102. package/dist/teams/team-loader.d.ts +6 -2
  103. package/dist/teams/team-loader.d.ts.map +1 -1
  104. package/dist/teams/team-loader.js +154 -162
  105. package/dist/teams/team-loader.js.map +1 -1
  106. package/dist/teams/team-manager.d.ts +112 -0
  107. package/dist/teams/team-manager.d.ts.map +1 -0
  108. package/dist/teams/team-manager.js +305 -0
  109. package/dist/teams/team-manager.js.map +1 -0
  110. package/dist/teams/team-runtime.d.ts +125 -19
  111. package/dist/teams/team-runtime.d.ts.map +1 -1
  112. package/dist/teams/team-runtime.js +527 -119
  113. package/dist/teams/team-runtime.js.map +1 -1
  114. package/dist/teams/types.d.ts +41 -151
  115. package/dist/teams/types.d.ts.map +1 -1
  116. package/dist/teams/types.js +2 -3
  117. package/dist/teams/types.js.map +1 -1
  118. package/docs/teams.md +73 -0
  119. package/package.json +2 -1
  120. package/references/minimem/.claude/settings.json +7 -0
  121. package/references/minimem/.sudocode/issues.jsonl +18 -0
  122. package/references/minimem/.sudocode/specs.jsonl +1 -0
  123. package/references/minimem/CLAUDE.md +310 -0
  124. package/references/minimem/README.md +562 -0
  125. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
  126. package/references/minimem/claude-plugin/.mcp.json +7 -0
  127. package/references/minimem/claude-plugin/README.md +158 -0
  128. package/references/minimem/claude-plugin/commands/recall.md +47 -0
  129. package/references/minimem/claude-plugin/commands/remember.md +41 -0
  130. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
  131. package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
  132. package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
  133. package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
  134. package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
  135. package/references/minimem/media/banner.png +0 -0
  136. package/references/minimem/package-lock.json +5373 -0
  137. package/references/minimem/package.json +72 -0
  138. package/references/minimem/scripts/postbuild.js +35 -0
  139. package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
  140. package/references/minimem/src/__tests__/errors.test.ts +265 -0
  141. package/references/minimem/src/__tests__/helpers.ts +199 -0
  142. package/references/minimem/src/__tests__/internal.test.ts +407 -0
  143. package/references/minimem/src/__tests__/knowledge.test.ts +287 -0
  144. package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
  145. package/references/minimem/src/__tests__/session.test.ts +190 -0
  146. package/references/minimem/src/cli/__tests__/commands.test.ts +759 -0
  147. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
  148. package/references/minimem/src/cli/commands/append.ts +76 -0
  149. package/references/minimem/src/cli/commands/config.ts +262 -0
  150. package/references/minimem/src/cli/commands/conflicts.ts +413 -0
  151. package/references/minimem/src/cli/commands/daemon.ts +169 -0
  152. package/references/minimem/src/cli/commands/index.ts +12 -0
  153. package/references/minimem/src/cli/commands/init.ts +88 -0
  154. package/references/minimem/src/cli/commands/mcp.ts +177 -0
  155. package/references/minimem/src/cli/commands/push-pull.ts +213 -0
  156. package/references/minimem/src/cli/commands/search.ts +158 -0
  157. package/references/minimem/src/cli/commands/status.ts +84 -0
  158. package/references/minimem/src/cli/commands/sync-init.ts +290 -0
  159. package/references/minimem/src/cli/commands/sync.ts +70 -0
  160. package/references/minimem/src/cli/commands/upsert.ts +197 -0
  161. package/references/minimem/src/cli/config.ts +584 -0
  162. package/references/minimem/src/cli/index.ts +264 -0
  163. package/references/minimem/src/cli/shared.ts +161 -0
  164. package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
  165. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
  166. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
  167. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
  168. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
  169. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
  170. package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
  171. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
  172. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
  173. package/references/minimem/src/cli/sync/central.ts +292 -0
  174. package/references/minimem/src/cli/sync/conflicts.ts +204 -0
  175. package/references/minimem/src/cli/sync/daemon.ts +407 -0
  176. package/references/minimem/src/cli/sync/detection.ts +138 -0
  177. package/references/minimem/src/cli/sync/index.ts +107 -0
  178. package/references/minimem/src/cli/sync/operations.ts +373 -0
  179. package/references/minimem/src/cli/sync/registry.ts +279 -0
  180. package/references/minimem/src/cli/sync/state.ts +355 -0
  181. package/references/minimem/src/cli/sync/validation.ts +206 -0
  182. package/references/minimem/src/cli/sync/watcher.ts +234 -0
  183. package/references/minimem/src/cli/version.ts +34 -0
  184. package/references/minimem/src/core/index.ts +9 -0
  185. package/references/minimem/src/core/indexer.ts +628 -0
  186. package/references/minimem/src/core/searcher.ts +221 -0
  187. package/references/minimem/src/db/schema.ts +183 -0
  188. package/references/minimem/src/db/sqlite-vec.ts +24 -0
  189. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
  190. package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
  191. package/references/minimem/src/embeddings/batch-openai.ts +409 -0
  192. package/references/minimem/src/embeddings/embeddings.ts +434 -0
  193. package/references/minimem/src/index.ts +109 -0
  194. package/references/minimem/src/internal.ts +299 -0
  195. package/references/minimem/src/minimem.ts +1276 -0
  196. package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
  197. package/references/minimem/src/search/graph.ts +234 -0
  198. package/references/minimem/src/search/hybrid.ts +151 -0
  199. package/references/minimem/src/search/search.ts +256 -0
  200. package/references/minimem/src/server/__tests__/mcp.test.ts +341 -0
  201. package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
  202. package/references/minimem/src/server/mcp.ts +326 -0
  203. package/references/minimem/src/server/tools.ts +720 -0
  204. package/references/minimem/src/session.ts +460 -0
  205. package/references/minimem/tsconfig.json +19 -0
  206. package/references/minimem/tsup.config.ts +26 -0
  207. package/references/minimem/vitest.config.ts +24 -0
  208. package/references/openteams/.claude/settings.json +6 -0
  209. package/references/openteams/README.md +1 -0
  210. package/references/openteams/SKILL.md +341 -0
  211. package/references/openteams/design.md +411 -0
  212. package/references/openteams/examples/bmad-method/prompts/analyst/ROLE.md +16 -0
  213. package/references/openteams/examples/bmad-method/prompts/analyst/SOUL.md +5 -0
  214. package/references/openteams/examples/bmad-method/prompts/architect/ROLE.md +24 -0
  215. package/references/openteams/examples/bmad-method/prompts/architect/SOUL.md +5 -0
  216. package/references/openteams/examples/bmad-method/prompts/developer/ROLE.md +25 -0
  217. package/references/openteams/examples/bmad-method/prompts/developer/SOUL.md +5 -0
  218. package/references/openteams/examples/bmad-method/prompts/master/ROLE.md +21 -0
  219. package/references/openteams/examples/bmad-method/prompts/master/SOUL.md +5 -0
  220. package/references/openteams/examples/bmad-method/prompts/pm/ROLE.md +20 -0
  221. package/references/openteams/examples/bmad-method/prompts/pm/SOUL.md +5 -0
  222. package/references/openteams/examples/bmad-method/prompts/qa/ROLE.md +17 -0
  223. package/references/openteams/examples/bmad-method/prompts/qa/SOUL.md +5 -0
  224. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/ROLE.md +23 -0
  225. package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/SOUL.md +5 -0
  226. package/references/openteams/examples/bmad-method/prompts/scrum-master/ROLE.md +27 -0
  227. package/references/openteams/examples/bmad-method/prompts/scrum-master/SOUL.md +5 -0
  228. package/references/openteams/examples/bmad-method/prompts/tech-writer/ROLE.md +21 -0
  229. package/references/openteams/examples/bmad-method/prompts/tech-writer/SOUL.md +5 -0
  230. package/references/openteams/examples/bmad-method/prompts/ux-designer/ROLE.md +16 -0
  231. package/references/openteams/examples/bmad-method/prompts/ux-designer/SOUL.md +5 -0
  232. package/references/openteams/examples/bmad-method/roles/analyst.yaml +9 -0
  233. package/references/openteams/examples/bmad-method/roles/architect.yaml +9 -0
  234. package/references/openteams/examples/bmad-method/roles/developer.yaml +8 -0
  235. package/references/openteams/examples/bmad-method/roles/master.yaml +8 -0
  236. package/references/openteams/examples/bmad-method/roles/pm.yaml +9 -0
  237. package/references/openteams/examples/bmad-method/roles/qa.yaml +8 -0
  238. package/references/openteams/examples/bmad-method/roles/quick-flow-dev.yaml +8 -0
  239. package/references/openteams/examples/bmad-method/roles/scrum-master.yaml +9 -0
  240. package/references/openteams/examples/bmad-method/roles/tech-writer.yaml +8 -0
  241. package/references/openteams/examples/bmad-method/roles/ux-designer.yaml +8 -0
  242. package/references/openteams/examples/bmad-method/team.yaml +161 -0
  243. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/ROLE.md +17 -0
  244. package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/SOUL.md +5 -0
  245. package/references/openteams/examples/get-shit-done/prompts/debugger/ROLE.md +25 -0
  246. package/references/openteams/examples/get-shit-done/prompts/debugger/SOUL.md +5 -0
  247. package/references/openteams/examples/get-shit-done/prompts/executor/ROLE.md +34 -0
  248. package/references/openteams/examples/get-shit-done/prompts/executor/SOUL.md +5 -0
  249. package/references/openteams/examples/get-shit-done/prompts/integration-checker/ROLE.md +18 -0
  250. package/references/openteams/examples/get-shit-done/prompts/integration-checker/SOUL.md +3 -0
  251. package/references/openteams/examples/get-shit-done/prompts/orchestrator/ROLE.md +42 -0
  252. package/references/openteams/examples/get-shit-done/prompts/orchestrator/SOUL.md +5 -0
  253. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/ROLE.md +15 -0
  254. package/references/openteams/examples/get-shit-done/prompts/phase-researcher/SOUL.md +3 -0
  255. package/references/openteams/examples/get-shit-done/prompts/plan-checker/ROLE.md +17 -0
  256. package/references/openteams/examples/get-shit-done/prompts/plan-checker/SOUL.md +3 -0
  257. package/references/openteams/examples/get-shit-done/prompts/planner/ROLE.md +28 -0
  258. package/references/openteams/examples/get-shit-done/prompts/planner/SOUL.md +5 -0
  259. package/references/openteams/examples/get-shit-done/prompts/project-researcher/ROLE.md +16 -0
  260. package/references/openteams/examples/get-shit-done/prompts/project-researcher/SOUL.md +3 -0
  261. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/ROLE.md +13 -0
  262. package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/SOUL.md +3 -0
  263. package/references/openteams/examples/get-shit-done/prompts/roadmapper/ROLE.md +14 -0
  264. package/references/openteams/examples/get-shit-done/prompts/roadmapper/SOUL.md +3 -0
  265. package/references/openteams/examples/get-shit-done/prompts/verifier/ROLE.md +19 -0
  266. package/references/openteams/examples/get-shit-done/prompts/verifier/SOUL.md +5 -0
  267. package/references/openteams/examples/get-shit-done/roles/codebase-mapper.yaml +8 -0
  268. package/references/openteams/examples/get-shit-done/roles/debugger.yaml +8 -0
  269. package/references/openteams/examples/get-shit-done/roles/executor.yaml +8 -0
  270. package/references/openteams/examples/get-shit-done/roles/integration-checker.yaml +8 -0
  271. package/references/openteams/examples/get-shit-done/roles/orchestrator.yaml +9 -0
  272. package/references/openteams/examples/get-shit-done/roles/phase-researcher.yaml +7 -0
  273. package/references/openteams/examples/get-shit-done/roles/plan-checker.yaml +8 -0
  274. package/references/openteams/examples/get-shit-done/roles/planner.yaml +8 -0
  275. package/references/openteams/examples/get-shit-done/roles/project-researcher.yaml +8 -0
  276. package/references/openteams/examples/get-shit-done/roles/research-synthesizer.yaml +7 -0
  277. package/references/openteams/examples/get-shit-done/roles/roadmapper.yaml +7 -0
  278. package/references/openteams/examples/get-shit-done/roles/verifier.yaml +8 -0
  279. package/references/openteams/examples/get-shit-done/team.yaml +154 -0
  280. package/references/openteams/package-lock.json +2181 -0
  281. package/references/openteams/package.json +48 -0
  282. package/references/openteams/schema/role.schema.json +125 -0
  283. package/references/openteams/schema/team.schema.json +284 -0
  284. package/references/openteams/src/cli/agent.ts +104 -0
  285. package/references/openteams/src/cli/cli.test.ts +381 -0
  286. package/references/openteams/src/cli/generate.ts +220 -0
  287. package/references/openteams/src/cli/message.ts +241 -0
  288. package/references/openteams/src/cli/task.ts +154 -0
  289. package/references/openteams/src/cli/team.ts +104 -0
  290. package/references/openteams/src/cli/template.ts +207 -0
  291. package/references/openteams/src/cli.ts +45 -0
  292. package/references/openteams/src/db/database.test.ts +185 -0
  293. package/references/openteams/src/db/database.ts +240 -0
  294. package/references/openteams/src/generators/agent-prompt-generator.test.ts +332 -0
  295. package/references/openteams/src/generators/agent-prompt-generator.ts +521 -0
  296. package/references/openteams/src/generators/package-generator.test.ts +129 -0
  297. package/references/openteams/src/generators/package-generator.ts +102 -0
  298. package/references/openteams/src/generators/skill-generator.test.ts +246 -0
  299. package/references/openteams/src/generators/skill-generator.ts +374 -0
  300. package/references/openteams/src/index.ts +104 -0
  301. package/references/openteams/src/services/agent-service.test.ts +158 -0
  302. package/references/openteams/src/services/agent-service.ts +84 -0
  303. package/references/openteams/src/services/communication-service.test.ts +455 -0
  304. package/references/openteams/src/services/communication-service.ts +371 -0
  305. package/references/openteams/src/services/message-service.test.ts +342 -0
  306. package/references/openteams/src/services/message-service.ts +203 -0
  307. package/references/openteams/src/services/task-service.test.ts +434 -0
  308. package/references/openteams/src/services/task-service.ts +239 -0
  309. package/references/openteams/src/services/team-service.test.ts +181 -0
  310. package/references/openteams/src/services/team-service.ts +139 -0
  311. package/references/openteams/src/services/template-service.test.ts +306 -0
  312. package/references/openteams/src/services/template-service.ts +182 -0
  313. package/references/openteams/src/spawner/acp-factory.ts +96 -0
  314. package/references/openteams/src/spawner/interface.ts +31 -0
  315. package/references/openteams/src/spawner/mock.test.ts +93 -0
  316. package/references/openteams/src/spawner/mock.ts +59 -0
  317. package/references/openteams/src/template/loader.test.ts +1319 -0
  318. package/references/openteams/src/template/loader.ts +698 -0
  319. package/references/openteams/src/template/types.ts +200 -0
  320. package/references/openteams/src/types.ts +205 -0
  321. package/references/openteams/tsconfig.json +18 -0
  322. package/references/openteams/vitest.config.ts +9 -0
  323. package/references/skill-tree/.claude/settings.json +6 -0
  324. package/references/skill-tree/.sudocode/issues.jsonl +11 -0
  325. package/references/skill-tree/.sudocode/specs.jsonl +1 -0
  326. package/references/skill-tree/CLAUDE.md +150 -0
  327. package/references/skill-tree/README.md +324 -0
  328. package/references/skill-tree/docs/GAPS_v1.md +221 -0
  329. package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
  330. package/references/skill-tree/docs/TODOS.md +91 -0
  331. package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
  332. package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
  333. package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
  334. package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
  335. package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
  336. package/references/skill-tree/docs/scraper/README.md +170 -0
  337. package/references/skill-tree/examples/basic-usage.ts +190 -0
  338. package/references/skill-tree/package-lock.json +1509 -0
  339. package/references/skill-tree/package.json +66 -0
  340. package/references/skill-tree/scraper/README.md +123 -0
  341. package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
  342. package/references/skill-tree/scraper/docs/PLAN.md +336 -0
  343. package/references/skill-tree/scraper/drizzle.config.ts +10 -0
  344. package/references/skill-tree/scraper/package-lock.json +6329 -0
  345. package/references/skill-tree/scraper/package.json +68 -0
  346. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
  347. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
  348. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
  349. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
  350. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
  351. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
  352. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
  353. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
  354. package/references/skill-tree/scraper/tsup.config.ts +14 -0
  355. package/references/skill-tree/scraper/vitest.config.ts +17 -0
  356. package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
  357. package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
  358. package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
  359. package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
  360. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
  361. package/references/skill-tree/test/run-all.ts +106 -0
  362. package/references/skill-tree/test/utils.ts +128 -0
  363. package/references/skill-tree/vitest.config.ts +16 -0
  364. package/src/agent/agent-manager.ts +143 -72
  365. package/src/agent/types.ts +9 -0
  366. package/src/api/__tests__/server.test.ts +203 -4
  367. package/src/api/server.ts +130 -5
  368. package/src/api/types.ts +3 -1
  369. package/src/cli/acp.ts +68 -1
  370. package/src/cli/index.ts +5 -1
  371. package/src/cli/mcp.ts +27 -13
  372. package/src/config/project-config.ts +27 -3
  373. package/src/index.ts +3 -0
  374. package/src/lifecycle/__tests__/handlers.test.ts +53 -0
  375. package/src/lifecycle/handlers/index.ts +25 -8
  376. package/src/lifecycle/types.ts +3 -0
  377. package/src/map/adapter/__tests__/stream-extensions.test.ts +494 -0
  378. package/src/map/adapter/extensions/index.ts +36 -0
  379. package/src/map/adapter/extensions/streams.ts +839 -0
  380. package/src/map/adapter/index.ts +5 -0
  381. package/src/map/adapter/types.ts +8 -1
  382. package/src/mcp/mcp-server.ts +14 -3
  383. package/src/mcp/tools/done.ts +19 -0
  384. package/src/roles/builtin/coordinator.ts +2 -0
  385. package/src/roles/builtin/integrator.ts +2 -0
  386. package/src/roles/builtin/worker.ts +3 -0
  387. package/src/roles/capabilities.ts +11 -0
  388. package/src/roles/config-loader.ts +3 -2
  389. package/src/roles/types.ts +7 -0
  390. package/src/server/combined-server.ts +15 -1
  391. package/src/store/__tests__/event-store-oob.test.ts +109 -0
  392. package/src/store/event-store.ts +13 -3
  393. package/src/store/instance.ts +2 -2
  394. package/src/store/types/agents.ts +5 -0
  395. package/src/task/backend/__tests__/memory-pull-mode.test.ts +153 -0
  396. package/src/task/backend/opentasks/daemon-manager.ts +4 -1
  397. package/src/teams/CLAUDE.md +180 -0
  398. package/src/teams/__tests__/e2e/workspace-isolation.e2e.test.ts +1263 -0
  399. package/src/teams/__tests__/team-manager.test.ts +814 -0
  400. package/src/teams/__tests__/team-system.test.ts +1291 -8
  401. package/src/teams/index.ts +21 -3
  402. package/src/teams/seed-defaults.ts +79 -0
  403. package/src/teams/team-loader.ts +200 -234
  404. package/src/teams/team-manager.ts +387 -0
  405. package/src/teams/team-runtime.ts +590 -121
  406. package/src/teams/types.ts +99 -200
@@ -155,4 +155,9 @@ export {
155
155
  registerResumeExtension,
156
156
  unregisterResumeExtension,
157
157
  type ResumeExtensionServices,
158
+ // Stream/checkpoint/diffStack/mergeQueue
159
+ registerStreamExtensions,
160
+ unregisterStreamExtensions,
161
+ STREAM_EXTENSION_METHODS,
162
+ type StreamExtensionServices,
158
163
  } from "./extensions/index.js";
@@ -168,7 +168,14 @@ export type MAPEventType =
168
168
  | "task.created"
169
169
  | "task.assigned"
170
170
  | "task.completed"
171
- | "task.failed";
171
+ | "task.failed"
172
+ // Stream/checkpoint/merge events (git-cascade)
173
+ | "stream.updated"
174
+ | "checkpoint.created"
175
+ | "diffstack.created"
176
+ | "diffstack.updated"
177
+ | "merge_request.created"
178
+ | "merge_request.updated";
172
179
 
173
180
  /**
174
181
  * Filter for event subscriptions.
@@ -103,6 +103,8 @@ export interface MCPServices {
103
103
  integrationStrategy?: import("../workspace/strategies/types.js").IntegrationStrategy;
104
104
  /** Optional task backend for pull model tools (claim/unclaim) */
105
105
  taskBackend?: import("../task/backend/types.js").TaskBackend;
106
+ /** Optional workspace manager for workspace isolation */
107
+ workspaceManager?: import("../workspace/types.js").WorkspaceManager;
106
108
  }
107
109
 
108
110
  // ─────────────────────────────────────────────────────────────────
@@ -1046,6 +1048,7 @@ export function createMCPServer(
1046
1048
  roleRegistry,
1047
1049
  integrationStrategy: services.integrationStrategy,
1048
1050
  taskMode: services.taskMode,
1051
+ workspaceManager: services.workspaceManager,
1049
1052
  });
1050
1053
 
1051
1054
  try {
@@ -1056,6 +1059,14 @@ export function createMCPServer(
1056
1059
  task_id?: string;
1057
1060
  });
1058
1061
 
1062
+ // Persist events emitted by the done handler (MERGE_REQUEST, WORKER_DONE, etc.)
1063
+ // so the main process polling can see them via EventStore reload.
1064
+ try {
1065
+ await eventStore.persist();
1066
+ } catch {
1067
+ // Best-effort — events may still be picked up on next reload
1068
+ }
1069
+
1059
1070
  // If shouldTerminate is true, schedule termination after this tool returns
1060
1071
  // The agent will be terminated after the tool execution completes
1061
1072
  if (result.shouldTerminate) {
@@ -1091,7 +1102,7 @@ export function createMCPServer(
1091
1102
  // Tools: claim_task, unclaim_task, list_claimable_tasks (pull model)
1092
1103
  // ─────────────────────────────────────────────────────────────────
1093
1104
 
1094
- if (services.taskBackend && shouldRegisterTool("claim_task")) {
1105
+ if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("claim_task")) {
1095
1106
  server.registerTool(CLAIM_TASK_TOOL_INFO.name, {
1096
1107
  description: CLAIM_TASK_TOOL_INFO.description,
1097
1108
  inputSchema: ClaimTaskSchema,
@@ -1104,7 +1115,7 @@ export function createMCPServer(
1104
1115
  });
1105
1116
  }
1106
1117
 
1107
- if (services.taskBackend && shouldRegisterTool("unclaim_task")) {
1118
+ if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("unclaim_task")) {
1108
1119
  server.registerTool(UNCLAIM_TASK_TOOL_INFO.name, {
1109
1120
  description: UNCLAIM_TASK_TOOL_INFO.description,
1110
1121
  inputSchema: UnclaimTaskSchema,
@@ -1117,7 +1128,7 @@ export function createMCPServer(
1117
1128
  });
1118
1129
  }
1119
1130
 
1120
- if (services.taskBackend && shouldRegisterTool("list_claimable_tasks")) {
1131
+ if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("list_claimable_tasks")) {
1121
1132
  server.registerTool(LIST_CLAIMABLE_TASKS_TOOL_INFO.name, {
1122
1133
  description: LIST_CLAIMABLE_TASKS_TOOL_INFO.description,
1123
1134
  inputSchema: ListClaimableTasksSchema,
@@ -147,6 +147,13 @@ export function buildLifecycleContext(
147
147
  streamId = workspace?.streamId;
148
148
  }
149
149
 
150
+ // Fallback: read streamId from env var (set by buildMacroAgentMcp during spawn).
151
+ // WorkspaceManager is not available in MCP subprocesses, but the streamId is
152
+ // needed for MERGE_REQUEST signal details so the team runtime can submit to the merge queue.
153
+ if (!streamId && process.env.MACRO_STREAM_ID) {
154
+ streamId = process.env.MACRO_STREAM_ID;
155
+ }
156
+
150
157
  return {
151
158
  agentId: toolContext.agent_id,
152
159
  role,
@@ -206,6 +213,18 @@ export function createDoneHandler(context: ToolContext, deps: DoneToolDeps) {
206
213
  workspaceManager
207
214
  );
208
215
 
216
+ // Resolve capabilities for capability-based handler dispatch (team roles)
217
+ if (roleRegistry) {
218
+ try {
219
+ const resolvedRole = roleRegistry.resolveRole(role);
220
+ if (resolvedRole?.capabilities) {
221
+ lifecycleContext.capabilities = [...resolvedRole.capabilities];
222
+ }
223
+ } catch {
224
+ // Role not in registry — capabilities stay undefined
225
+ }
226
+ }
227
+
209
228
  const cleanupStatus = detectCleanupStatus(lifecycleContext, {
210
229
  messageRouter,
211
230
  });
@@ -11,6 +11,7 @@ import {
11
11
  TASK_CAPABILITIES,
12
12
  AGENT_CAPABILITIES,
13
13
  MSG_CAPABILITIES,
14
+ WORKSPACE_CAPABILITIES,
14
15
  } from "../capabilities.js";
15
16
 
16
17
  /**
@@ -42,6 +43,7 @@ export const CoordinatorRole: RoleDefinition = {
42
43
  MSG_CAPABILITIES.SEND,
43
44
  MSG_CAPABILITIES.BROADCAST,
44
45
  MSG_CAPABILITIES.SUBSCRIBE,
46
+ WORKSPACE_CAPABILITIES.STREAM,
45
47
  // Note: lifecycle.done is optional, configured per-coordinator
46
48
  ],
47
49
 
@@ -12,6 +12,7 @@ import {
12
12
  AGENT_CAPABILITIES,
13
13
  LIFECYCLE_CAPABILITIES,
14
14
  MSG_CAPABILITIES,
15
+ WORKSPACE_CAPABILITIES,
15
16
  } from "../capabilities.js";
16
17
 
17
18
  /**
@@ -39,6 +40,7 @@ export const IntegratorRole: RoleDefinition = {
39
40
  LIFECYCLE_CAPABILITIES.DONE,
40
41
  MSG_CAPABILITIES.SEND,
41
42
  MSG_CAPABILITIES.SUBSCRIBE,
43
+ WORKSPACE_CAPABILITIES.INTEGRATE,
42
44
  ],
43
45
 
44
46
  workspace: {
@@ -13,6 +13,7 @@ import {
13
13
  LIFECYCLE_CAPABILITIES,
14
14
  AGENT_CAPABILITIES,
15
15
  MSG_CAPABILITIES,
16
+ WORKSPACE_CAPABILITIES,
16
17
  } from "../capabilities.js";
17
18
 
18
19
  /** 30 minutes in milliseconds (stale timeout) */
@@ -45,6 +46,7 @@ export const WorkerRole: RoleDefinition = {
45
46
  LIFECYCLE_CAPABILITIES.DONE,
46
47
  AGENT_CAPABILITIES.SPAWN_WORKER,
47
48
  MSG_CAPABILITIES.SEND,
49
+ WORKSPACE_CAPABILITIES.WORKTREE,
48
50
  ],
49
51
 
50
52
  workspace: {
@@ -100,6 +102,7 @@ export const ResolverWorkerRole: RoleDefinition = {
100
102
  LIFECYCLE_CAPABILITIES.DONE,
101
103
  AGENT_CAPABILITIES.SPAWN_WORKER,
102
104
  MSG_CAPABILITIES.SEND,
105
+ WORKSPACE_CAPABILITIES.WORKTREE,
103
106
  ],
104
107
 
105
108
  // Inherits workspace from worker
@@ -66,6 +66,13 @@ export const MSG_CAPABILITIES = {
66
66
  SUBSCRIBE: "msg.subscribe" as const,
67
67
  };
68
68
 
69
+ /** Workspace capabilities */
70
+ export const WORKSPACE_CAPABILITIES = {
71
+ WORKTREE: "workspace.worktree" as const, // Gets own git worktree; done() submits to merge queue
72
+ STREAM: "workspace.stream" as const, // Creates integration stream at spawn
73
+ INTEGRATE: "workspace.integrate" as const, // Joins stream; processes merge queue entries
74
+ };
75
+
69
76
  /** Wildcard capability */
70
77
  export const WILDCARD_CAPABILITY = "*" as const;
71
78
 
@@ -112,6 +119,10 @@ export const ALL_CAPABILITIES: Set<Capability> = new Set([
112
119
  MSG_CAPABILITIES.SEND,
113
120
  MSG_CAPABILITIES.BROADCAST,
114
121
  MSG_CAPABILITIES.SUBSCRIBE,
122
+ // Workspace
123
+ WORKSPACE_CAPABILITIES.WORKTREE,
124
+ WORKSPACE_CAPABILITIES.STREAM,
125
+ WORKSPACE_CAPABILITIES.INTEGRATE,
115
126
  // Wildcard
116
127
  WILDCARD_CAPABILITY,
117
128
  ]);
@@ -126,10 +126,11 @@ export function getProjectConfigPath(projectPath?: string): string {
126
126
  /**
127
127
  * Get the user-level config file path
128
128
  *
129
- * @returns Path to ~/.multiagent/roles.json
129
+ * @returns Path to ~/.multiagent/roles.json (or MACRO_AGENT_HOME/roles.json)
130
130
  */
131
131
  export function getUserConfigPath(): string {
132
- return path.join(os.homedir(), USER_CONFIG_DIR, CONFIG_FILE_NAME);
132
+ const globalDir = process.env.MACRO_AGENT_HOME || path.join(os.homedir(), USER_CONFIG_DIR);
133
+ return path.join(globalDir, CONFIG_FILE_NAME);
133
134
  }
134
135
 
135
136
  // =============================================================================
@@ -54,6 +54,12 @@ export type ExecCapability =
54
54
  /** Communication capabilities */
55
55
  export type MsgCapability = "msg.send" | "msg.broadcast" | "msg.subscribe";
56
56
 
57
+ /** Workspace capabilities */
58
+ export type WorkspaceCapability =
59
+ | "workspace.worktree"
60
+ | "workspace.stream"
61
+ | "workspace.integrate";
62
+
57
63
  /** All capability types combined, plus wildcard */
58
64
  export type Capability =
59
65
  | FileCapability
@@ -63,6 +69,7 @@ export type Capability =
63
69
  | TaskCapability
64
70
  | ExecCapability
65
71
  | MsgCapability
72
+ | WorkspaceCapability
66
73
  | "*"; // Wildcard for all capabilities
67
74
 
68
75
  // =============================================================================
@@ -31,9 +31,11 @@ import {
31
31
  registerTaskExtensions,
32
32
  registerResumeExtension,
33
33
  registerAgentLifecycleExtensions,
34
+ registerStreamExtensions,
34
35
  type MAPAdapter,
35
36
  type MAPAdapterServices,
36
37
  type MAPWebSocketHandler,
38
+ type StreamExtensionServices,
37
39
  } from "../map/adapter/index.js";
38
40
  import type { Agent, AgentId } from "../store/types/index.js";
39
41
  import type { Address, SendOptions } from "../map/types.js";
@@ -49,6 +51,7 @@ import {
49
51
  secureCompare,
50
52
  } from "../auth/token.js";
51
53
  import { TaskBackend, TaskToolProvider } from "../task/backend/types.js";
54
+ import type { TeamManager } from "../teams/team-manager.js";
52
55
 
53
56
  // ─────────────────────────────────────────────────────────────────
54
57
  // Types
@@ -73,6 +76,12 @@ export interface CombinedServerServices {
73
76
  agentTokenManager?: AgentTokenManager;
74
77
  /** Get connected opentasks project paths (for health endpoint) */
75
78
  getConnectedProjects?: () => string[];
79
+ /** Optional stream extension services for git-cascade stream/checkpoint/merge-queue features */
80
+ streamExtensions?: StreamExtensionServices;
81
+ /** Optional team manager for dynamic team management */
82
+ teamManager?: TeamManager;
83
+ /** Optional workspace manager for workspace isolation and merge queue */
84
+ workspaceManager?: import("../workspace/types.js").WorkspaceManager;
76
85
  }
77
86
 
78
87
  export interface CombinedServerConfig {
@@ -258,7 +267,7 @@ export function createCombinedServer(
258
267
  // Create Express app with API routes (include mail services)
259
268
  const app = createAPIApp(
260
269
  { ...services, mailService, conversationMap },
261
- { cors, serverToken: resolvedServerToken },
270
+ { cors, serverToken: resolvedServerToken, defaultCwd },
262
271
  );
263
272
 
264
273
  // Create HTTP server with Express
@@ -369,6 +378,11 @@ export function createCombinedServer(
369
378
  agentTokenManager: services.agentTokenManager,
370
379
  });
371
380
 
381
+ // Register stream/checkpoint/diffStack/mergeQueue extensions
382
+ if (services.streamExtensions) {
383
+ registerStreamExtensions(mapAdapter, services.streamExtensions);
384
+ }
385
+
372
386
  mapHandler = createMAPWebSocketHandler(mapAdapter);
373
387
  }
374
388
 
@@ -0,0 +1,109 @@
1
+ /**
2
+ * EventStore Out-of-Band Field Preservation Tests
3
+ *
4
+ * Tests that fields written via updateAgentMetadata() (out-of-band,
5
+ * not through events) survive the rebuildViews() cycle that occurs
6
+ * on every auto-load (every 1 second) and on reload().
7
+ *
8
+ * The preservation relies on OUT_OF_BAND_FIELDS in rebuildViews()
9
+ * which saves these values before clearing views, replays all events,
10
+ * then restores the saved values.
11
+ *
12
+ * @module store/__tests__/event-store-oob
13
+ */
14
+
15
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
16
+ import { createEventStore, type EventStore } from "../event-store.js";
17
+ import type { AgentId } from "../types/index.js";
18
+
19
+ describe("EventStore — Out-of-Band Field Preservation", () => {
20
+ let eventStore: EventStore;
21
+
22
+ const AGENT_ID = "oob-test-001" as AgentId;
23
+
24
+ beforeEach(async () => {
25
+ eventStore = await createEventStore({ instanceId: `oob-test-${Date.now()}` });
26
+
27
+ // Create an agent via spawn event
28
+ eventStore.emit({
29
+ type: "spawn",
30
+ source: { agent_id: AGENT_ID },
31
+ payload: {
32
+ agent_id: AGENT_ID,
33
+ task: "Test task",
34
+ role: "worker",
35
+ cwd: "/original/path",
36
+ },
37
+ });
38
+ await eventStore.persist();
39
+ });
40
+
41
+ afterEach(async () => {
42
+ try { await eventStore.close(); } catch { /* ignore */ }
43
+ });
44
+
45
+ it("cwd survives rebuildViews after updateAgentMetadata", async () => {
46
+ // Verify initial cwd from spawn event
47
+ expect(eventStore.getAgent(AGENT_ID)?.cwd).toBe("/original/path");
48
+
49
+ // Update cwd out-of-band
50
+ eventStore.updateAgentMetadata(AGENT_ID, { cwd: "/workspace/worktree-001" });
51
+ expect(eventStore.getAgent(AGENT_ID)?.cwd).toBe("/workspace/worktree-001");
52
+
53
+ // Persist and reload (triggers rebuildViews)
54
+ await eventStore.persist();
55
+ await eventStore.reload();
56
+
57
+ // cwd should survive the rebuild
58
+ const agent = eventStore.getAgent(AGENT_ID);
59
+ expect(agent).not.toBeNull();
60
+ expect(agent!.cwd).toBe("/workspace/worktree-001");
61
+ });
62
+
63
+ it("team_instance survives rebuildViews", async () => {
64
+ // Set team_instance out-of-band
65
+ eventStore.updateAgentMetadata(AGENT_ID, { team_instance: "team-alpha-001" });
66
+ expect(eventStore.getAgent(AGENT_ID)?.team_instance).toBe("team-alpha-001");
67
+
68
+ // Persist and reload
69
+ await eventStore.persist();
70
+ await eventStore.reload();
71
+
72
+ // team_instance should survive
73
+ expect(eventStore.getAgent(AGENT_ID)?.team_instance).toBe("team-alpha-001");
74
+ });
75
+
76
+ it("all OUT_OF_BAND_FIELDS preserved together", async () => {
77
+ // Set all out-of-band fields simultaneously
78
+ eventStore.updateAgentMetadata(AGENT_ID, {
79
+ name: "Developer Alpha",
80
+ plan: [{ content: "Step 1: do the thing", priority: "high", status: "pending" }],
81
+ metadata: { custom_key: "custom_value" },
82
+ cwd: "/workspace/worktree-002",
83
+ team_instance: "team-beta-002",
84
+ });
85
+
86
+ // Verify all set correctly
87
+ const before = eventStore.getAgent(AGENT_ID)!;
88
+ expect(before.name).toBe("Developer Alpha");
89
+ expect(before.cwd).toBe("/workspace/worktree-002");
90
+ expect(before.team_instance).toBe("team-beta-002");
91
+
92
+ // Persist and reload (triggers rebuildViews)
93
+ await eventStore.persist();
94
+ await eventStore.reload();
95
+
96
+ // All fields should survive
97
+ const after = eventStore.getAgent(AGENT_ID)!;
98
+ expect(after.name).toBe("Developer Alpha");
99
+ expect(after.cwd).toBe("/workspace/worktree-002");
100
+ expect(after.team_instance).toBe("team-beta-002");
101
+
102
+ // plan and metadata may be stored as JSON strings or objects depending on TinyBase internals
103
+ const plan = typeof after.plan === "string" ? JSON.parse(after.plan) : after.plan;
104
+ expect(plan).toEqual([{ content: "Step 1: do the thing", priority: "high", status: "pending" }]);
105
+
106
+ const metadata = typeof after.metadata === "string" ? JSON.parse(after.metadata) : after.metadata;
107
+ expect(metadata).toEqual({ custom_key: "custom_value" });
108
+ });
109
+ });
@@ -58,6 +58,7 @@ import {
58
58
  readInstanceMeta,
59
59
  touchInstance,
60
60
  registerInstance,
61
+ DEFAULT_BASE_DIR,
61
62
  DEFAULT_NAMESPACE,
62
63
  DEFAULT_PEER_VISIBILITY,
63
64
  filterEventsForPeer,
@@ -308,7 +309,7 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
308
309
  }
309
310
 
310
311
  // Track baseDir for MCP subprocess communication
311
- const baseDir = config.baseDir ?? path.join(os.homedir(), '.multiagent');
312
+ const baseDir = config.baseDir ?? DEFAULT_BASE_DIR;
312
313
 
313
314
  // Get peer visibility config (default is restrictive)
314
315
  const peerVisibility: PeerVisibilityConfig =
@@ -382,7 +383,7 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
382
383
 
383
384
  // Register in namespace for discovery
384
385
  registerInstance(
385
- config.baseDir ?? path.join(os.homedir(), '.multiagent'),
386
+ config.baseDir ?? DEFAULT_BASE_DIR,
386
387
  namespace,
387
388
  instanceId,
388
389
  { label: config.label }
@@ -548,6 +549,12 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
548
549
  const existing = row.metadata ? JSON.parse(row.metadata as string) : {};
549
550
  partial.metadata = JSON.stringify({ ...existing, ...updates.metadata });
550
551
  }
552
+ if (updates.team_instance !== undefined) {
553
+ partial.team_instance = updates.team_instance;
554
+ }
555
+ if (updates.cwd !== undefined) {
556
+ partial.cwd = updates.cwd;
557
+ }
551
558
 
552
559
  store.setPartialRow('agents', agentId, partial);
553
560
 
@@ -1332,7 +1339,7 @@ function rebuildViews(store: Store): void {
1332
1339
  // Preserve out-of-band agent fields that aren't derived from events.
1333
1340
  // These fields are written directly (not through events),
1334
1341
  // so they would be lost when we clear and replay.
1335
- const OUT_OF_BAND_FIELDS = ['plan', 'name', 'metadata'] as const;
1342
+ const OUT_OF_BAND_FIELDS = ['plan', 'name', 'metadata', 'cwd', 'team_instance'] as const;
1336
1343
  const savedOutOfBand = new Map<string, Record<string, string>>();
1337
1344
  for (const rowId of store.getRowIds('agents')) {
1338
1345
  const row = store.getRow('agents', rowId);
@@ -1478,6 +1485,7 @@ function applySpawnEvent(
1478
1485
  task_id?: TaskId;
1479
1486
  parent?: AgentId | null;
1480
1487
  role?: string;
1488
+ team_instance?: string;
1481
1489
  config?: Record<string, unknown>;
1482
1490
  cwd?: string;
1483
1491
  };
@@ -1508,6 +1516,7 @@ function applySpawnEvent(
1508
1516
  task: payload.task,
1509
1517
  task_id: payload.task_id ?? '',
1510
1518
  role: payload.role ?? '',
1519
+ team_instance: payload.team_instance ?? '',
1511
1520
  config: JSON.stringify(payload.config ?? {}),
1512
1521
  cwd: payload.cwd ?? process.cwd(),
1513
1522
  plan: '[]',
@@ -1866,6 +1875,7 @@ function rowToAgent(row: Record<string, unknown>): Agent {
1866
1875
  task: row.task as string,
1867
1876
  task_id: (row.task_id as string) || undefined,
1868
1877
  role: (row.role as string) || undefined,
1878
+ team_instance: (row.team_instance as string) || undefined,
1869
1879
  config: row.config ? JSON.parse(row.config as string) : {},
1870
1880
  cwd: (row.cwd as string) || process.cwd(),
1871
1881
  plan: row.plan ? JSON.parse(row.plan as string) : [],
@@ -221,8 +221,8 @@ export interface ResolvedInstance {
221
221
  // Constants
222
222
  // ─────────────────────────────────────────────────────────────────────────────
223
223
 
224
- /** Default base directory */
225
- export const DEFAULT_BASE_DIR = path.join(os.homedir(), '.multiagent');
224
+ /** Default base directory (override with MACRO_AGENT_HOME env var) */
225
+ export const DEFAULT_BASE_DIR = process.env.MACRO_AGENT_HOME || path.join(os.homedir(), '.multiagent');
226
226
 
227
227
  /** Default namespace */
228
228
  export const DEFAULT_NAMESPACE = 'default';
@@ -40,6 +40,8 @@ export interface Agent {
40
40
  task: string;
41
41
  task_id?: TaskId;
42
42
  role?: string;
43
+ /** Team instance ID this agent belongs to (set by TeamManager) */
44
+ team_instance?: string;
43
45
  config: AgentConfig;
44
46
  cwd: string;
45
47
  plan: Array<{ content: string; priority: string; status: string }>;
@@ -61,4 +63,7 @@ export interface AgentMetadataUpdate {
61
63
  name?: string;
62
64
  plan?: Array<{ content: string; priority: string; status: string }>;
63
65
  metadata?: Record<string, unknown>;
66
+ team_instance?: string;
67
+ /** Override the agent's working directory (e.g., to workspace worktree path) */
68
+ cwd?: string;
64
69
  }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Pull-Mode Task Backend Tests
3
+ *
4
+ * Tests the claim/unclaim/listClaimable methods of InMemoryTaskBackend
5
+ * which enable the pull model where workers claim tasks from a pool.
6
+ *
7
+ * @module task/backend/__tests__/memory-pull-mode
8
+ */
9
+
10
+ import { describe, it, expect, beforeEach } from "vitest";
11
+ import { createEventStore, type EventStore } from "../../../store/event-store.js";
12
+ import { InMemoryTaskBackend } from "../memory.js";
13
+ import type { AgentId, TaskId } from "../../../store/types/index.js";
14
+
15
+ describe("InMemoryTaskBackend — Pull Mode", () => {
16
+ let eventStore: EventStore;
17
+ let backend: InMemoryTaskBackend;
18
+
19
+ const AGENT_A = "agent-a" as AgentId;
20
+ const AGENT_B = "agent-b" as AgentId;
21
+ const CREATOR = "creator-001" as AgentId;
22
+
23
+ beforeEach(async () => {
24
+ eventStore = await createEventStore({ instanceId: `pull-test-${Date.now()}` });
25
+ backend = new InMemoryTaskBackend(eventStore);
26
+ });
27
+
28
+ // ─────────────────────────────────────────────────────────────────
29
+ // claim()
30
+ // ─────────────────────────────────────────────────────────────────
31
+
32
+ it("claim returns first pending unblocked task", async () => {
33
+ const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
34
+ const t2 = await backend.create({ description: "Task 2", created_by: CREATOR });
35
+ const t3 = await backend.create({ description: "Task 3", created_by: CREATOR });
36
+
37
+ const claimed = await backend.claim!(AGENT_A);
38
+ expect(claimed).not.toBeNull();
39
+ expect(claimed!.id).toBe(t1.id);
40
+ expect(claimed!.assigned_agent).toBe(AGENT_A);
41
+
42
+ // Second claim should return t2
43
+ const claimed2 = await backend.claim!(AGENT_B);
44
+ expect(claimed2).not.toBeNull();
45
+ expect(claimed2!.id).toBe(t2.id);
46
+ expect(claimed2!.assigned_agent).toBe(AGENT_B);
47
+ });
48
+
49
+ it("claim skips assigned tasks", async () => {
50
+ const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
51
+ const t2 = await backend.create({ description: "Task 2", created_by: CREATOR });
52
+
53
+ // Assign t1 directly
54
+ await backend.assign(t1.id, { agent_id: AGENT_A });
55
+
56
+ // claim should skip t1 and return t2
57
+ const claimed = await backend.claim!(AGENT_B);
58
+ expect(claimed).not.toBeNull();
59
+ expect(claimed!.id).toBe(t2.id);
60
+ });
61
+
62
+ it("claim skips blocked tasks", async () => {
63
+ const blocker = await backend.create({ description: "Blocker task", created_by: CREATOR });
64
+ const blocked = await backend.create({ description: "Blocked task", created_by: CREATOR });
65
+ const available = await backend.create({ description: "Available task", created_by: CREATOR });
66
+
67
+ // Add blocker dependency
68
+ await backend.addBlocker(blocked.id, blocker.id);
69
+
70
+ // claim should skip blocked and return available
71
+ const claimed = await backend.claim!(AGENT_A);
72
+ expect(claimed).not.toBeNull();
73
+ // Should return either blocker or available (blocker is pending+unblocked, so it comes first)
74
+ // blocker is pending + not assigned + not blocked → claimable
75
+ // blocked is pending + not assigned but IS blocked → not claimable
76
+ // available is pending + not assigned + not blocked → claimable
77
+ expect([blocker.id, available.id]).toContain(claimed!.id);
78
+ expect(claimed!.id).not.toBe(blocked.id);
79
+ });
80
+
81
+ it("claim returns null when no claimable tasks", async () => {
82
+ // Create a task and assign it
83
+ const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
84
+ await backend.assign(t1.id, { agent_id: AGENT_A });
85
+
86
+ // No unassigned pending tasks left
87
+ const claimed = await backend.claim!(AGENT_B);
88
+ expect(claimed).toBeNull();
89
+ });
90
+
91
+ // ─────────────────────────────────────────────────────────────────
92
+ // unclaim()
93
+ // ─────────────────────────────────────────────────────────────────
94
+
95
+ it("unclaim returns task to pending pool", async () => {
96
+ const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
97
+
98
+ // Claim it
99
+ const claimed = await backend.claim!(AGENT_A);
100
+ expect(claimed!.id).toBe(t1.id);
101
+ expect(claimed!.assigned_agent).toBe(AGENT_A);
102
+
103
+ // Unclaim it
104
+ await backend.unclaim!(t1.id);
105
+
106
+ // Task should be claimable again
107
+ const reClaimed = await backend.claim!(AGENT_B);
108
+ expect(reClaimed).not.toBeNull();
109
+ expect(reClaimed!.id).toBe(t1.id);
110
+ expect(reClaimed!.assigned_agent).toBe(AGENT_B);
111
+ });
112
+
113
+ it("unclaim throws on unassigned task", async () => {
114
+ const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
115
+
116
+ await expect(backend.unclaim!(t1.id)).rejects.toThrow("not assigned");
117
+ });
118
+
119
+ // ─────────────────────────────────────────────────────────────────
120
+ // listClaimable()
121
+ // ─────────────────────────────────────────────────────────────────
122
+
123
+ it("listClaimable filters by tags", async () => {
124
+ await backend.create({
125
+ description: "Frontend task",
126
+ created_by: CREATOR,
127
+ tags: ["frontend", "ui"],
128
+ });
129
+ await backend.create({
130
+ description: "Backend task",
131
+ created_by: CREATOR,
132
+ tags: ["backend", "api"],
133
+ });
134
+ await backend.create({
135
+ description: "Untagged task",
136
+ created_by: CREATOR,
137
+ });
138
+
139
+ // Filter by "backend" tag
140
+ const claimable = await backend.listClaimable!({ tags: ["backend"] });
141
+ expect(claimable.length).toBe(1);
142
+ expect(claimable[0].description).toBe("Backend task");
143
+
144
+ // Filter by "frontend" tag
145
+ const frontendTasks = await backend.listClaimable!({ tags: ["frontend"] });
146
+ expect(frontendTasks.length).toBe(1);
147
+ expect(frontendTasks[0].description).toBe("Frontend task");
148
+
149
+ // No filter returns all claimable
150
+ const allClaimable = await backend.listClaimable!();
151
+ expect(allClaimable.length).toBe(3);
152
+ });
153
+ });
@@ -54,7 +54,10 @@ export interface DaemonManagerResult {
54
54
  // Constants
55
55
  // =============================================================================
56
56
 
57
- const DEFAULT_CENTRAL_PATH = path.join(os.homedir(), ".multiagent", "opentasks");
57
+ const DEFAULT_CENTRAL_PATH = path.join(
58
+ process.env.MACRO_AGENT_HOME || path.join(os.homedir(), ".multiagent"),
59
+ "opentasks",
60
+ );
58
61
 
59
62
  /** Grace period (ms) between client disconnect and daemon.stop() to let children finish disconnecting */
60
63
  const DAEMON_DRAIN_MS = 500;