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
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Team Runtime
3
3
  *
4
- * Wires a loaded TeamManifest into the running system: registers roles,
4
+ * Wires a loaded team template into the running system: registers roles,
5
5
  * sets up integration strategy, configures communication topology,
6
6
  * and manages the team lifecycle.
7
7
  *
@@ -11,15 +11,22 @@
11
11
  import type { EventStore } from "../store/event-store.js";
12
12
  import type { MessageRouter } from "../router/message-router.js";
13
13
  import type { AgentManager, SpawnInterceptor } from "../agent/agent-manager.js";
14
+ import type {
15
+ SignalFilter,
16
+ EmissionValidator,
17
+ EmissionValidatorResult,
18
+ } from "../router/message-router.js";
14
19
  import type { RoleRegistry } from "../roles/types.js";
15
20
  import type { SpawnAgentOptions } from "../agent/types.js";
16
21
  import type { AgentId } from "../store/types/index.js";
17
22
  import type {
18
23
  TeamManifest,
24
+ MacroResolvedTemplate,
19
25
  McpServerEntry,
20
26
  PeerConnection,
21
27
  } from "./types.js";
22
28
  import type { IntegrationStrategy } from "../workspace/strategies/types.js";
29
+ import { WORKSPACE_CAPABILITIES } from "../roles/capabilities.js";
23
30
 
24
31
  // =============================================================================
25
32
  // Types
@@ -29,6 +36,10 @@ export interface TeamServices {
29
36
  agentManager: AgentManager;
30
37
  messageRouter: MessageRouter;
31
38
  eventStore: EventStore;
39
+ /** Optional workspace manager for merge queue wiring */
40
+ workspaceManager?: import("../workspace/types.js").WorkspaceManager;
41
+ /** Optional task backend for auto-scaling queue depth checks */
42
+ taskBackend?: import("../task/backend/types.js").TaskBackend;
32
43
  }
33
44
 
34
45
  export interface TeamBootstrapResult {
@@ -36,6 +47,45 @@ export interface TeamBootstrapResult {
36
47
  companionIds: string[];
37
48
  }
38
49
 
50
+ // =============================================================================
51
+ // Conversion: TeamManifest → MacroResolvedTemplate
52
+ // =============================================================================
53
+
54
+ /**
55
+ * Convert a legacy TeamManifest (with _ prefixed fields) to MacroResolvedTemplate.
56
+ * Used for backward compatibility when TeamRuntime receives a TeamManifest.
57
+ */
58
+ function manifestToResolved(manifest: TeamManifest): MacroResolvedTemplate {
59
+ return {
60
+ template: {
61
+ manifest: {
62
+ name: manifest.name,
63
+ description: manifest.description,
64
+ version: manifest.version,
65
+ roles: manifest.roles,
66
+ topology: manifest.topology,
67
+ communication: manifest.communication,
68
+ },
69
+ roles: new Map(), // Not used — macro-agent uses resolvedRoles
70
+ prompts: new Map(), // Prompts are in _loadedPrompts
71
+ mcpServers: manifest._mcpServers,
72
+ sourcePath: "",
73
+ },
74
+ resolvedRoles: manifest._resolvedRoles,
75
+ macroAgent: manifest.macro_agent,
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Check if input is a MacroResolvedTemplate (has `template` field)
81
+ * vs a legacy TeamManifest (has `_resolvedRoles` field).
82
+ */
83
+ function isMacroResolvedTemplate(
84
+ input: TeamManifest | MacroResolvedTemplate
85
+ ): input is MacroResolvedTemplate {
86
+ return "template" in input && "resolvedRoles" in input;
87
+ }
88
+
39
89
  // =============================================================================
40
90
  // TeamRuntime
41
91
  // =============================================================================
@@ -46,6 +96,18 @@ export class TeamRuntime {
46
96
  private roleRegistry: RoleRegistry;
47
97
  private lifecycleUnsubscribe?: () => void;
48
98
  private integrationStrategy?: IntegrationStrategy;
99
+ private scalingTimer?: ReturnType<typeof setInterval>;
100
+ private lastScaleUpTime = 0;
101
+ private teamStreamId?: string;
102
+ private mergeQueueUnsub?: () => void;
103
+ private mergeRequestPollTimer?: ReturnType<typeof setInterval>;
104
+ private lastMergeRequestSeen = 0;
105
+
106
+ /** The resolved template (canonical internal representation) */
107
+ private readonly resolved: MacroResolvedTemplate;
108
+
109
+ /** Legacy loaded prompts map (path → content) for backward compat */
110
+ private readonly loadedPrompts: Map<string, string>;
49
111
 
50
112
  /** Role name → spawned agent ID mapping (populated during bootstrap) */
51
113
  private roleAgentMap = new Map<string, AgentId>();
@@ -59,16 +121,43 @@ export class TeamRuntime {
59
121
  /** Reverse mapping: agent ID → role name (for signal filter lookups) */
60
122
  private agentRoleMap = new Map<AgentId, string>();
61
123
 
124
+ /** Pre-computed per-role allowed signals from channel subscriptions */
125
+ private roleAllowedSignals = new Map<string, Set<string> | "all">();
126
+
62
127
  /** Lifecycle unsubscribe for deferred peer wiring */
63
128
  private peerWiringUnsubscribe?: () => void;
64
129
 
130
+ /**
131
+ * Create a TeamRuntime.
132
+ *
133
+ * Accepts either a MacroResolvedTemplate (new) or a TeamManifest (legacy).
134
+ * Internally always uses MacroResolvedTemplate.
135
+ */
65
136
  constructor(
66
- private readonly manifest: TeamManifest,
137
+ input: TeamManifest | MacroResolvedTemplate,
67
138
  private readonly services: TeamServices
68
139
  ) {
140
+ this.resolved = isMacroResolvedTemplate(input)
141
+ ? input
142
+ : manifestToResolved(input);
143
+
144
+ // Extract loaded prompts from legacy manifest if available
145
+ this.loadedPrompts = !isMacroResolvedTemplate(input)
146
+ ? input._loadedPrompts
147
+ : new Map();
148
+
69
149
  this.roleRegistry = services.agentManager.getRoleRegistry();
70
150
  }
71
151
 
152
+ // Convenience accessors
153
+ private get manifest() {
154
+ return this.resolved.template.manifest;
155
+ }
156
+
157
+ private get communication() {
158
+ return (this.manifest.communication ?? {}) as NonNullable<typeof this.manifest.communication>;
159
+ }
160
+
72
161
  // ─────────────────────────────────────────────────────────────
73
162
  // Initialization
74
163
  // ─────────────────────────────────────────────────────────────
@@ -78,25 +167,41 @@ export class TeamRuntime {
78
167
  *
79
168
  * 1. Register team roles into RoleRegistry
80
169
  * 2. Store team_config event in EventStore (for MCP subprocess discovery)
81
- * 3. Register spawn interceptor on AgentManager
170
+ * 3. Instantiate integration strategy
171
+ *
172
+ * Note: Does NOT install spawn interceptor, signal filter, or emission
173
+ * validator on services. Call installOnServices() for standalone use,
174
+ * or let TeamManager handle composite installation.
82
175
  */
83
- async initialize(): Promise<void> {
84
- const { agentManager, eventStore } = this.services;
176
+ async initialize(options?: { teamInstanceId?: string }): Promise<void> {
177
+ const { eventStore } = this.services;
85
178
 
86
179
  // 1. Register team roles into RoleRegistry (custom layer, highest priority)
87
- for (const [, resolved] of this.manifest._resolvedRoles) {
88
- this.roleRegistry.registerRole(resolved.roleDefinition);
180
+ for (const [, resolved] of this.resolved.resolvedRoles) {
181
+ const rd = resolved.roleDefinition;
182
+ const existing = this.roleRegistry.getRole(rd.name);
183
+ if (existing) {
184
+ const existingCaps = [...existing.capabilities].sort();
185
+ const newCaps = [...rd.capabilities].sort();
186
+ if (existingCaps.length !== newCaps.length || existingCaps.some((c, i) => c !== newCaps[i])) {
187
+ console.warn(
188
+ `[TeamRuntime] Role '${rd.name}' conflict: team '${this.manifest.name}' re-registers with different capabilities. ` +
189
+ `Existing: [${existingCaps.join(", ")}], New: [${newCaps.join(", ")}]`
190
+ );
191
+ }
192
+ }
193
+ this.roleRegistry.registerRole(rd);
89
194
  }
90
195
 
91
196
  // 2. Store team config in EventStore for cross-process access (RD2)
92
- const taskMode = this.manifest.macro_agent.task_assignment?.mode ?? "push";
93
- const strategyName = this.manifest.macro_agent.integration?.strategy ?? "queue";
94
- const strategyConfig = this.manifest.macro_agent.integration?.config ?? {};
95
- const enforcement = this.manifest.communication.enforcement ?? "permissive";
197
+ const taskMode = this.resolved.macroAgent.task_assignment?.mode ?? "push";
198
+ const strategyName = this.resolved.macroAgent.integration?.strategy ?? "queue";
199
+ const strategyConfig = this.resolved.macroAgent.integration?.config ?? {};
200
+ const enforcement = this.communication.enforcement ?? "permissive";
96
201
 
97
202
  // Serialize resolved roles for MCP subprocess capability checks
98
203
  const serializedRoles: Record<string, { name: string; capabilities: string[]; tools?: object; lifecycle?: object; description?: string }> = {};
99
- for (const [name, resolved] of this.manifest._resolvedRoles) {
204
+ for (const [name, resolved] of this.resolved.resolvedRoles) {
100
205
  const rd = resolved.roleDefinition;
101
206
  serializedRoles[name] = {
102
207
  name: rd.name,
@@ -115,32 +220,40 @@ export class TeamRuntime {
115
220
  summary: `Team '${this.manifest.name}' initialized`,
116
221
  team_config: {
117
222
  teamName: this.manifest.name,
223
+ ...(options?.teamInstanceId && { team_instance: options.teamInstanceId }),
118
224
  strategy: strategyName,
119
225
  strategyConfig,
120
226
  taskMode,
121
227
  enforcement,
122
228
  roles: serializedRoles,
123
- peerRoutes: this.manifest.communication.routing?.peers ?? [],
124
- emissions: this.manifest.communication.emissions ?? {},
229
+ peerRoutes: this.communication.routing?.peers ?? [],
230
+ emissions: this.communication.emissions ?? {},
125
231
  },
126
232
  },
127
233
  });
128
234
 
129
235
  await eventStore.persist();
130
236
 
131
- // 2b. Instantiate integration strategy and call lifecycle hook
237
+ // 3. Instantiate integration strategy and call lifecycle hook
132
238
  try {
133
239
  const { defaultStrategyRegistry } = await import("../workspace/strategies/registry.js");
134
240
  this.integrationStrategy = defaultStrategyRegistry.get(strategyName, strategyConfig as Record<string, unknown>);
135
241
  if (this.integrationStrategy.initialize) {
136
242
  await this.integrationStrategy.initialize();
137
243
  }
244
+
245
+ // Wire merge queue to queue strategy if workspace manager is available
246
+ if (
247
+ this.services.workspaceManager &&
248
+ strategyName === "queue" &&
249
+ "setMergeQueue" in this.integrationStrategy
250
+ ) {
251
+ const mergeQueue = this.services.workspaceManager.getMergeQueue();
252
+ (this.integrationStrategy as { setMergeQueue(q: typeof mergeQueue): void }).setMergeQueue(mergeQueue);
253
+ }
138
254
  } catch {
139
255
  // Strategy instantiation is best-effort — queue strategy needs merge queue set later
140
256
  }
141
-
142
- // 3. Register spawn interceptor
143
- agentManager.setSpawnInterceptor(this.createSpawnInterceptor());
144
257
  }
145
258
 
146
259
  // ─────────────────────────────────────────────────────────────
@@ -149,9 +262,13 @@ export class TeamRuntime {
149
262
 
150
263
  /**
151
264
  * Spawn root and companion agents per the team topology.
265
+ *
266
+ * Populates internal state (agentRoleMap, peerSignalFilters) used by
267
+ * createSignalFilter() and createEmissionValidator(). Call installOnServices()
268
+ * after bootstrap for standalone use, or let TeamManager handle installation.
152
269
  */
153
270
  async bootstrap(): Promise<TeamBootstrapResult> {
154
- const { agentManager, messageRouter } = this.services;
271
+ const { agentManager } = this.services;
155
272
  const { topology } = this.manifest;
156
273
 
157
274
  // 1. Spawn root agent
@@ -170,6 +287,10 @@ export class TeamRuntime {
170
287
  });
171
288
  this.rootAgentId = root.id;
172
289
 
290
+ // 1b. Set up workspace integration BEFORE companions spawn,
291
+ // so the spawn interceptor has teamStreamId for workspace injection
292
+ this.setupWorkspaceIntegration(root.id as AgentId);
293
+
173
294
  // 2. Spawn companions (peers, not children)
174
295
  const companionIds: string[] = [];
175
296
  for (const companion of topology.companions ?? []) {
@@ -197,15 +318,15 @@ export class TeamRuntime {
197
318
  }
198
319
  this.wirePeerRoutes();
199
320
 
200
- // 4. Install signal filter on message router
201
- this.installSignalFilter();
202
-
203
- // 5. Install emission validator on message router
204
- this.installEmissionValidator();
321
+ // 4. Pre-compute role allowed signals (used by createSignalFilter)
322
+ this.computeRoleAllowedSignals();
205
323
 
206
- // 6. Set up continuation monitoring for daemon agents (P4.2)
324
+ // 5. Set up continuation monitoring for daemon agents (P4.2)
207
325
  this.monitorContinuations();
208
326
 
327
+ // 6. Set up auto-scaling monitoring
328
+ this.monitorScaling();
329
+
209
330
  return {
210
331
  rootId: root.id,
211
332
  companionIds,
@@ -217,10 +338,13 @@ export class TeamRuntime {
217
338
  // ─────────────────────────────────────────────────────────────
218
339
 
219
340
  /**
220
- * Tear down team: remove spawn interceptor, stop continuation monitoring.
341
+ * Tear down team: stop continuation monitoring, clean up strategy.
342
+ *
343
+ * Note: Does NOT clear spawn interceptor or filters on services.
344
+ * The caller (TeamManager or standalone code) is responsible for
345
+ * removing the interceptor/filters from shared services.
221
346
  */
222
347
  async teardown(): Promise<void> {
223
- this.services.agentManager.setSpawnInterceptor(null);
224
348
  if (this.lifecycleUnsubscribe) {
225
349
  this.lifecycleUnsubscribe();
226
350
  this.lifecycleUnsubscribe = undefined;
@@ -229,6 +353,18 @@ export class TeamRuntime {
229
353
  this.peerWiringUnsubscribe();
230
354
  this.peerWiringUnsubscribe = undefined;
231
355
  }
356
+ if (this.scalingTimer) {
357
+ clearInterval(this.scalingTimer);
358
+ this.scalingTimer = undefined;
359
+ }
360
+ if (this.mergeQueueUnsub) {
361
+ this.mergeQueueUnsub();
362
+ this.mergeQueueUnsub = undefined;
363
+ }
364
+ if (this.mergeRequestPollTimer) {
365
+ clearInterval(this.mergeRequestPollTimer);
366
+ this.mergeRequestPollTimer = undefined;
367
+ }
232
368
  // Call strategy lifecycle close hook
233
369
  if (this.integrationStrategy?.close) {
234
370
  try {
@@ -245,17 +381,31 @@ export class TeamRuntime {
245
381
 
246
382
  /** Get task assignment mode */
247
383
  getTaskMode(): "push" | "pull" {
248
- return this.manifest.macro_agent.task_assignment?.mode ?? "push";
384
+ return this.resolved.macroAgent.task_assignment?.mode ?? "push";
249
385
  }
250
386
 
251
387
  /** Get integration strategy name */
252
388
  getStrategyName(): string {
253
- return this.manifest.macro_agent.integration?.strategy ?? "queue";
389
+ return this.resolved.macroAgent.integration?.strategy ?? "queue";
254
390
  }
255
391
 
256
392
  /** Get the active manifest (for API) */
257
393
  getManifest(): TeamManifest {
258
- return this.manifest;
394
+ // Build a backward-compatible TeamManifest from the resolved template
395
+ return {
396
+ ...this.manifest,
397
+ description: this.manifest.description ?? "",
398
+ communication: this.communication,
399
+ macro_agent: this.resolved.macroAgent,
400
+ _resolvedRoles: this.resolved.resolvedRoles,
401
+ _loadedPrompts: this.loadedPrompts,
402
+ _mcpServers: this.resolved.template.mcpServers,
403
+ } as TeamManifest;
404
+ }
405
+
406
+ /** Get the resolved template */
407
+ getResolvedTemplate(): MacroResolvedTemplate {
408
+ return this.resolved;
259
409
  }
260
410
 
261
411
  /** Get root agent ID (after bootstrap) */
@@ -273,11 +423,32 @@ export class TeamRuntime {
273
423
  return this.integrationStrategy;
274
424
  }
275
425
 
426
+ /** Get team-wide integration stream ID (after bootstrap) */
427
+ getTeamStreamId(): string | undefined {
428
+ return this.teamStreamId;
429
+ }
430
+
276
431
  /** Get signal filters for peer connections (for use by signal filtering - i-3o8g) */
277
432
  getPeerSignalFilters(): ReadonlyMap<string, string[]> {
278
433
  return this.peerSignalFilters;
279
434
  }
280
435
 
436
+ /** Get the agent → role mapping (for TeamManager agent-team lookups) */
437
+ getAgentRoleMap(): ReadonlyMap<AgentId, string> {
438
+ return this.agentRoleMap;
439
+ }
440
+
441
+ /** Register an agent's role mapping (for TeamManager to track dynamically spawned agents) */
442
+ registerAgent(agentId: AgentId, roleName: string): void {
443
+ this.agentRoleMap.set(agentId, roleName);
444
+ this.roleAgentMap.set(roleName, agentId);
445
+ }
446
+
447
+ /** Check if this team owns a given agent */
448
+ hasAgent(agentId: string): boolean {
449
+ return this.agentRoleMap.has(agentId as AgentId);
450
+ }
451
+
281
452
  // ─────────────────────────────────────────────────────────────
282
453
  // Continuation Monitoring (P4.2)
283
454
  // ─────────────────────────────────────────────────────────────
@@ -289,7 +460,7 @@ export class TeamRuntime {
289
460
  * lifecycle config enables continuations, automatically spawn a continuation.
290
461
  */
291
462
  private monitorContinuations(): void {
292
- const lifecycleConfig = this.manifest.macro_agent.lifecycle;
463
+ const lifecycleConfig = this.resolved.macroAgent.lifecycle;
293
464
  if (!lifecycleConfig?.continuations?.enabled) return;
294
465
 
295
466
  const { agentManager } = this.services;
@@ -329,19 +500,252 @@ export class TeamRuntime {
329
500
  });
330
501
  }
331
502
 
503
+ // ─────────────────────────────────────────────────────────────
504
+ // Auto-Scaling
505
+ // ─────────────────────────────────────────────────────────────
506
+
507
+ /** Minimum interval between scale-up actions (ms) */
508
+ private static readonly SCALE_COOLDOWN_MS = 10_000;
509
+
510
+ /** Default scaling check interval (ms) */
511
+ private static readonly SCALE_CHECK_INTERVAL_MS = 5_000;
512
+
513
+ /**
514
+ * Monitor task queue depth and auto-scale workers.
515
+ *
516
+ * Follows the same lifecycle pattern as monitorContinuations().
517
+ * Only active when `scaling.scale_on === "task_queue_depth"` and
518
+ * a task backend is available.
519
+ */
520
+ private monitorScaling(): void {
521
+ const scalingConfig = this.resolved.macroAgent.lifecycle?.scaling;
522
+ if (!scalingConfig || scalingConfig.scale_on !== "task_queue_depth") return;
523
+
524
+ const { taskBackend } = this.services;
525
+ if (!taskBackend?.listClaimable) return; // Need claimable task counting
526
+
527
+ const maxWorkers = scalingConfig.max_workers ?? Infinity;
528
+ const minWorkers = scalingConfig.min_workers ?? 0;
529
+
530
+ // Determine which role names are worker-derived (for counting active workers)
531
+ const workerRoleNames = new Set<string>();
532
+ for (const [name, resolved] of this.resolved.resolvedRoles) {
533
+ if (resolved.baseRole === "worker") {
534
+ workerRoleNames.add(name);
535
+ }
536
+ }
537
+ if (workerRoleNames.size === 0) return; // No worker roles to scale
538
+
539
+ // Pick the first worker role for spawning (most common pattern: single worker role)
540
+ const spawnRole = [...workerRoleNames][0];
541
+
542
+ this.scalingTimer = setInterval(async () => {
543
+ try {
544
+ // Count claimable tasks
545
+ const claimable = await taskBackend.listClaimable!();
546
+ const pendingCount = claimable.length;
547
+
548
+ // Count active workers in this team
549
+ const allAgents = this.services.agentManager.list({ state: "running" });
550
+ let activeWorkers = 0;
551
+ for (const agent of allAgents) {
552
+ if (agent.role && workerRoleNames.has(agent.role) && this.agentRoleMap.has(agent.id as AgentId)) {
553
+ activeWorkers++;
554
+ }
555
+ }
556
+
557
+ // Scale up: more pending tasks than active workers, under max cap
558
+ if (pendingCount > activeWorkers && activeWorkers < maxWorkers) {
559
+ const now = Date.now();
560
+ if (now - this.lastScaleUpTime < TeamRuntime.SCALE_COOLDOWN_MS) {
561
+ return; // Cooldown not elapsed
562
+ }
563
+
564
+ if (!this.rootAgentId) return; // No root to spawn from
565
+
566
+ try {
567
+ await this.services.agentManager.spawn({
568
+ task: `[${this.manifest.name}] auto-scaled ${spawnRole}`,
569
+ role: spawnRole,
570
+ parent: this.rootAgentId,
571
+ });
572
+ this.lastScaleUpTime = now;
573
+
574
+ // Emit scaling event for observability
575
+ this.services.eventStore.emit({
576
+ type: "status",
577
+ source: { agent_id: "system" },
578
+ payload: {
579
+ status_type: "scaling",
580
+ summary: `Auto-scaled: spawned ${spawnRole} (pending=${pendingCount}, active=${activeWorkers}, max=${maxWorkers})`,
581
+ },
582
+ });
583
+ } catch {
584
+ // Spawn failed — will retry on next tick
585
+ }
586
+ }
587
+
588
+ // Scale down is handled by idle_drain: workers self-terminate after idle_timeout_s
589
+ // No active termination needed from the scaling monitor
590
+ } catch {
591
+ // Best-effort — don't crash the scaling loop
592
+ }
593
+ }, TeamRuntime.SCALE_CHECK_INTERVAL_MS);
594
+
595
+ // Ensure timer doesn't prevent process exit
596
+ if (this.scalingTimer.unref) {
597
+ this.scalingTimer.unref();
598
+ }
599
+ }
600
+
601
+ // ─────────────────────────────────────────────────────────────
602
+ // Workspace Integration
603
+ // ─────────────────────────────────────────────────────────────
604
+
605
+ /**
606
+ * Create the team-wide integration stream and subscribe to merge queue events.
607
+ *
608
+ * When a worker submits to the merge queue, the integrator agent is
609
+ * automatically prompted to process it.
610
+ */
611
+ private setupWorkspaceIntegration(rootAgentId: AgentId): void {
612
+ const { workspaceManager } = this.services;
613
+ if (!workspaceManager || !this.integrationStrategy) return;
614
+
615
+ // Create integration stream owned by root agent
616
+ try {
617
+ this.teamStreamId = workspaceManager.createIntegrationStream(
618
+ rootAgentId,
619
+ { name: this.manifest.name, forkFrom: "main" }
620
+ );
621
+ } catch {
622
+ // Workspace isolation unavailable (e.g., not a git repo)
623
+ return;
624
+ }
625
+
626
+ // Subscribe to merge queue events — wake integrator on mr:submitted
627
+ try {
628
+ const mergeQueue = workspaceManager.getMergeQueue();
629
+ if (mergeQueue?.onEvent) {
630
+ this.mergeQueueUnsub = mergeQueue.onEvent((event) => {
631
+ if (event.type !== "mr:submitted") return;
632
+
633
+ // Find agent with workspace.integrate capability in this team
634
+ for (const [agentId, roleName] of this.agentRoleMap) {
635
+ const resolved = this.resolved.resolvedRoles.get(roleName);
636
+ const caps = resolved?.capabilities ?? [];
637
+ if (caps.includes(WORKSPACE_CAPABILITIES.INTEGRATE)) {
638
+ try {
639
+ this.services.agentManager.prompt(
640
+ agentId,
641
+ `Merge request ${(event as { data?: Record<string, unknown> }).data?.mrId} submitted ` +
642
+ `by worker ${(event as { data?: Record<string, unknown> }).data?.workerAgentId} ` +
643
+ `for branch ${(event as { data?: Record<string, unknown> }).data?.workerBranch}. ` +
644
+ `Process the merge queue.`
645
+ );
646
+ } catch {
647
+ // Best-effort wake
648
+ }
649
+ break;
650
+ }
651
+ }
652
+ });
653
+ }
654
+ } catch {
655
+ // Merge queue not available — workspace isolation without merge queue
656
+ }
657
+
658
+ // Poll EventStore for MERGE_REQUEST signals from worker subprocesses.
659
+ // Workers in MCP subprocess emit to shared SQLite; main process must reload to see them.
660
+ this.startMergeRequestPolling();
661
+ }
662
+
663
+ /**
664
+ * Poll EventStore for MERGE_REQUEST signals emitted by worker subprocesses.
665
+ *
666
+ * Workers call done() in their MCP subprocess, which emits MERGE_REQUEST to
667
+ * the shared EventStore. This polling picks up those signals and submits to
668
+ * the merge queue on the main server.
669
+ */
670
+ private startMergeRequestPolling(): void {
671
+ const { workspaceManager, eventStore } = this.services;
672
+ if (!workspaceManager || !this.teamStreamId) return;
673
+
674
+ const mergeQueue = workspaceManager.getMergeQueue();
675
+ if (!mergeQueue) return;
676
+
677
+ this.mergeRequestPollTimer = setInterval(async () => {
678
+ try {
679
+ // Reload to see events written by subprocesses
680
+ if (eventStore.reload) {
681
+ await eventStore.reload();
682
+ }
683
+
684
+ const events = eventStore.query({ type: "status", limit: 100 });
685
+ for (const event of events) {
686
+ // Skip already-processed events
687
+ if (event.timestamp <= this.lastMergeRequestSeen) continue;
688
+
689
+ const details = event.payload?.details as Record<string, unknown> | undefined;
690
+ if (details?.signal !== "MERGE_REQUEST") continue;
691
+
692
+ // Check this agent belongs to our team
693
+ const sourceAgentId = event.source?.agent_id;
694
+ if (!sourceAgentId) continue;
695
+
696
+ // Check if agent is a team member OR a child of a team member
697
+ const isTeamMember = this.agentRoleMap.has(sourceAgentId as AgentId);
698
+ const parentAgent = eventStore.getAgent(sourceAgentId);
699
+ const isChildOfTeamMember = parentAgent?.parent
700
+ ? this.agentRoleMap.has(parentAgent.parent as AgentId)
701
+ : false;
702
+
703
+ if (!isTeamMember && !isChildOfTeamMember) continue;
704
+
705
+ this.lastMergeRequestSeen = event.timestamp;
706
+
707
+ // Extract merge request details
708
+ const sourceBranch = details.sourceBranch as string | undefined;
709
+ const taskId = details.taskId as string | undefined;
710
+ const workerId = details.workerId as string | undefined;
711
+
712
+ if (!sourceBranch || !workerId) continue;
713
+
714
+ // Submit to merge queue
715
+ try {
716
+ mergeQueue.submit({
717
+ streamId: this.teamStreamId!,
718
+ taskId: taskId ?? `task-${workerId}`,
719
+ workerBranch: sourceBranch,
720
+ workerAgentId: workerId,
721
+ });
722
+ } catch {
723
+ // Already submitted or other error — best-effort
724
+ }
725
+ }
726
+ } catch {
727
+ // Best-effort polling
728
+ }
729
+ }, 2000);
730
+
731
+ if (this.mergeRequestPollTimer.unref) {
732
+ this.mergeRequestPollTimer.unref();
733
+ }
734
+ }
735
+
332
736
  // ─────────────────────────────────────────────────────────────
333
737
  // Spawn Interceptor
334
738
  // ─────────────────────────────────────────────────────────────
335
739
 
336
740
  /**
337
- * Create the spawn interceptor that injects team context into spawn options.
741
+ * Internal: Create the spawn interceptor that injects team context into spawn options.
338
742
  */
339
- private createSpawnInterceptor(): SpawnInterceptor {
743
+ private _createSpawnInterceptor(): SpawnInterceptor {
340
744
  return (options: SpawnAgentOptions): SpawnAgentOptions => {
341
745
  const roleName = options.role;
342
746
  if (!roleName) return options;
343
747
 
344
- const resolved = this.manifest._resolvedRoles.get(roleName);
748
+ const resolved = this.resolved.resolvedRoles.get(roleName);
345
749
  if (!resolved) return options; // Unknown role — pass through
346
750
 
347
751
  // Compute topics from communication topology
@@ -365,8 +769,31 @@ export class TeamRuntime {
365
769
  // Task backend config is propagated by AgentManager.buildMacroAgentMcp()
366
770
  // from its taskBackend/openTasksSocketPath config options.
367
771
 
772
+ // Inject workspace fields based on capabilities (never overwrite explicit values)
773
+ const capabilities = resolved.capabilities;
774
+ let streamId = options.streamId;
775
+ let streamConfig = options.streamConfig;
776
+ let dataplaneTaskId = options.dataplaneTaskId;
777
+
778
+ if (this.teamStreamId && capabilities) {
779
+ if (capabilities.includes(WORKSPACE_CAPABILITIES.WORKTREE)) {
780
+ streamId = streamId ?? this.teamStreamId;
781
+ // Pull-mode workers use agentId as workspace identifier (one worktree per lifetime)
782
+ dataplaneTaskId = dataplaneTaskId ?? `worker-${Date.now()}`;
783
+ } else if (capabilities.includes(WORKSPACE_CAPABILITIES.INTEGRATE)) {
784
+ streamId = streamId ?? this.teamStreamId;
785
+ }
786
+ // workspace.stream: stream creation is managed by TeamRuntime.setupWorkspaceIntegration(),
787
+ // not auto-injected. Coordinators that need sub-streams pass explicit streamConfig.
788
+ }
789
+
368
790
  return {
369
791
  ...options,
792
+ // Workspace fields
793
+ streamId,
794
+ streamConfig,
795
+ dataplaneTaskId,
796
+ capabilities: capabilities ?? options.capabilities,
370
797
  // Merge topics
371
798
  topics: [
372
799
  ...(options.topics ?? []),
@@ -406,7 +833,7 @@ export class TeamRuntime {
406
833
  */
407
834
  private getTopicsForRole(roleName: string): string[] {
408
835
  const topics: string[] = [];
409
- const subs = this.manifest.communication.subscriptions?.[roleName] ?? [];
836
+ const subs = this.communication.subscriptions?.[roleName] ?? [];
410
837
 
411
838
  for (const sub of subs) {
412
839
  // Channel name becomes the topic name
@@ -422,16 +849,16 @@ export class TeamRuntime {
422
849
  * Get MCP servers configured for a role.
423
850
  */
424
851
  private getMcpServersForRole(roleName: string): McpServerEntry[] {
425
- return this.manifest._mcpServers.get(roleName) ?? [];
852
+ return this.resolved.template.mcpServers.get(roleName) ?? [];
426
853
  }
427
854
 
428
855
  /**
429
856
  * Get the loaded prompt content for a role.
430
857
  */
431
858
  private getPromptForRole(roleName: string): string | undefined {
432
- const resolved = this.manifest._resolvedRoles.get(roleName);
859
+ const resolved = this.resolved.resolvedRoles.get(roleName);
433
860
  if (!resolved?.prompt) return undefined;
434
- return this.manifest._loadedPrompts.get(resolved.prompt);
861
+ return this.loadedPrompts.get(resolved.prompt);
435
862
  }
436
863
 
437
864
  /**
@@ -442,7 +869,7 @@ export class TeamRuntime {
442
869
  ): string | undefined {
443
870
  // Prefer topology-level prompt reference
444
871
  if (node.prompt) {
445
- return this.manifest._loadedPrompts.get(node.prompt);
872
+ return this.loadedPrompts.get(node.prompt);
446
873
  }
447
874
  // Fall back to role-level prompt
448
875
  return this.getPromptForRole(node.role);
@@ -456,7 +883,7 @@ export class TeamRuntime {
456
883
  const taskMode = this.getTaskMode();
457
884
 
458
885
  if (taskMode === "pull") {
459
- const pullConfig = this.manifest.macro_agent.task_assignment?.pull;
886
+ const pullConfig = this.resolved.macroAgent.task_assignment?.pull;
460
887
  const idleTimeout = pullConfig?.idle_timeout_s ?? 300;
461
888
 
462
889
  patterns.push(`## Task Claiming
@@ -490,114 +917,156 @@ Focus on correctness — your changes go live immediately.`);
490
917
  }
491
918
 
492
919
  // ─────────────────────────────────────────────────────────────
493
- // Signal Filtering
920
+ // Exposed Interceptor / Filter / Validator Factories
494
921
  // ─────────────────────────────────────────────────────────────
495
922
 
496
923
  /**
497
- * Install a signal filter on the message router.
924
+ * Create the spawn interceptor for this team.
925
+ *
926
+ * Returns a function that injects team context (topics, MCP servers,
927
+ * env vars, prompt, interaction patterns) into spawn options.
928
+ * The caller (TeamManager or installOnServices) is responsible for
929
+ * installing it on AgentManager.
930
+ */
931
+ createSpawnInterceptor(): SpawnInterceptor {
932
+ return this._createSpawnInterceptor();
933
+ }
934
+
935
+ /**
936
+ * Create the signal filter for this team.
498
937
  *
499
938
  * Combines two filter sources:
500
- * 1. Channel subscription filters (per-role, per-topic): from communication.subscriptions
501
- * 2. Peer connection filters (per-agent-pair): from communication.routing.peers
939
+ * 1. Channel subscription filters (per-role, per-topic)
940
+ * 2. Peer connection filters (per-agent-pair)
502
941
  *
503
- * Status events with no details.signal always pass through (backwards compat).
942
+ * Must be called after bootstrap() so that agentRoleMap and
943
+ * peerSignalFilters are populated. Returns null if no filtering needed.
504
944
  */
505
- private installSignalFilter(): void {
506
- const { messageRouter } = this.services;
945
+ createSignalFilter(): SignalFilter | null {
946
+ return (from: AgentId, to: AgentId, signal: string | undefined): boolean => {
947
+ // Untagged status events always pass through
948
+ if (!signal) return true;
949
+
950
+ // Check peer connection filter (directional: from→to)
951
+ const peerFilter = this.peerSignalFilters.get(`${from}→${to}`);
952
+ if (peerFilter) {
953
+ return peerFilter.includes(signal);
954
+ }
507
955
 
508
- // Pre-compute per-role allowed signals from channel subscriptions.
509
- // Key: role name, Value: Set of allowed signal names.
510
- // If a role has any subscription without a signals filter, it receives all signals.
511
- const roleAllowedSignals = new Map<string, Set<string> | "all">();
956
+ // Check channel subscription filter for recipient's role
957
+ const recipientRole = this.agentRoleMap.get(to);
958
+ if (recipientRole) {
959
+ const allowed = this.roleAllowedSignals.get(recipientRole);
960
+ if (allowed && allowed !== "all") {
961
+ return allowed.has(signal);
962
+ }
963
+ }
512
964
 
513
- for (const [roleName, subs] of Object.entries(this.manifest.communication.subscriptions ?? {})) {
514
- let allowed: Set<string> | "all" = new Set<string>();
965
+ // No filter configured allow delivery
966
+ return true;
967
+ };
968
+ }
515
969
 
516
- for (const sub of subs) {
517
- if (!sub.signals || sub.signals.length === 0) {
518
- // No filter on this subscription — role receives all signals
519
- allowed = "all";
520
- break;
521
- }
522
- for (const sig of sub.signals) {
523
- (allowed as Set<string>).add(sig);
524
- }
970
+ /**
971
+ * Create the emission validator for this team.
972
+ *
973
+ * Checks whether an agent's emitted signal is in its role's allowed
974
+ * emissions list. Behavior depends on enforcement mode.
975
+ * Returns null if no emissions config exists.
976
+ */
977
+ createEmissionValidator(): EmissionValidator | null {
978
+ const emissions = this.communication.emissions;
979
+ const enforcement = this.communication.enforcement ?? "permissive";
980
+
981
+ // No emissions config — nothing to enforce
982
+ if (!emissions || Object.keys(emissions).length === 0) return null;
983
+
984
+ return (agentId: AgentId, signal: string | undefined): EmissionValidatorResult => {
985
+ // Untagged status events are always allowed
986
+ if (!signal) return { action: "allow" };
987
+
988
+ const role = this.agentRoleMap.get(agentId);
989
+ if (!role) return { action: "allow" };
990
+
991
+ const allowedSignals = emissions[role];
992
+ if (!allowedSignals) return { action: "allow" };
993
+
994
+ if (allowedSignals.includes(signal)) {
995
+ return { action: "allow" };
525
996
  }
526
997
 
527
- roleAllowedSignals.set(roleName, allowed);
528
- }
998
+ // Signal not in allowed list — enforce
999
+ const message = `Agent '${agentId}' (role: ${role}) emitted disallowed signal '${signal}'. Allowed: [${allowedSignals.join(", ")}]`;
1000
+
1001
+ switch (enforcement) {
1002
+ case "strict":
1003
+ return { action: "reject", message };
1004
+ case "audit":
1005
+ return { action: "audit", message };
1006
+ case "permissive":
1007
+ default:
1008
+ return { action: "warn", message };
1009
+ }
1010
+ };
1011
+ }
529
1012
 
530
- if (messageRouter.setSignalFilter) {
531
- messageRouter.setSignalFilter((from, to, signal) => {
532
- // Untagged status events always pass through
533
- if (!signal) return true;
1013
+ /**
1014
+ * Convenience method: install interceptor, signal filter, and emission
1015
+ * validator directly on the shared services.
1016
+ *
1017
+ * Use this for standalone operation (without TeamManager).
1018
+ * TeamManager uses the individual create* methods for composite dispatch.
1019
+ */
1020
+ installOnServices(): void {
1021
+ const { agentManager, messageRouter } = this.services;
534
1022
 
535
- // Check peer connection filter (directional: from→to)
536
- const peerFilter = this.peerSignalFilters.get(`${from}→${to}`);
537
- if (peerFilter) {
538
- return peerFilter.includes(signal);
539
- }
1023
+ agentManager.setSpawnInterceptor(this.createSpawnInterceptor());
540
1024
 
541
- // Check channel subscription filter for recipient's role
542
- const recipientRole = this.agentRoleMap.get(to);
543
- if (recipientRole) {
544
- const allowed = roleAllowedSignals.get(recipientRole);
545
- if (allowed && allowed !== "all") {
546
- return allowed.has(signal);
547
- }
548
- }
1025
+ const signalFilter = this.createSignalFilter();
1026
+ if (signalFilter && messageRouter.setSignalFilter) {
1027
+ messageRouter.setSignalFilter(signalFilter);
1028
+ }
549
1029
 
550
- // No filter configured — allow delivery
551
- return true;
552
- });
1030
+ const emissionValidator = this.createEmissionValidator();
1031
+ if (emissionValidator && messageRouter.setEmissionValidator) {
1032
+ messageRouter.setEmissionValidator(emissionValidator);
553
1033
  }
554
1034
  }
555
1035
 
1036
+ /**
1037
+ * Convenience method: uninstall interceptor and filters from services.
1038
+ * Use on teardown for standalone operation.
1039
+ */
1040
+ uninstallFromServices(): void {
1041
+ this.services.agentManager.setSpawnInterceptor(null);
1042
+ }
1043
+
556
1044
  // ─────────────────────────────────────────────────────────────
557
- // Emission Validation
1045
+ // Internal: Pre-compute role allowed signals
558
1046
  // ─────────────────────────────────────────────────────────────
559
1047
 
560
1048
  /**
561
- * Install emission validator on the message router.
562
- * Checks whether an agent's emitted signal is in its role's allowed emissions list.
563
- * Behavior depends on enforcement mode: strict (reject), permissive (warn), audit (record).
1049
+ * Pre-compute per-role allowed signals from channel subscriptions.
1050
+ * Called during bootstrap() so createSignalFilter() can use the result.
564
1051
  */
565
- private installEmissionValidator(): void {
566
- const { messageRouter } = this.services;
567
- const emissions = this.manifest.communication.emissions;
568
- const enforcement = this.manifest.communication.enforcement ?? "permissive";
569
-
570
- // No emissions config — nothing to enforce
571
- if (!emissions || Object.keys(emissions).length === 0) return;
1052
+ private computeRoleAllowedSignals(): void {
1053
+ this.roleAllowedSignals.clear();
572
1054
 
573
- if (messageRouter.setEmissionValidator) {
574
- messageRouter.setEmissionValidator((agentId, signal) => {
575
- // Untagged status events are always allowed
576
- if (!signal) return { action: "allow" };
577
-
578
- const role = this.agentRoleMap.get(agentId);
579
- if (!role) return { action: "allow" };
580
-
581
- const allowedSignals = emissions[role];
582
- if (!allowedSignals) return { action: "allow" };
1055
+ for (const [roleName, subs] of Object.entries(this.communication.subscriptions ?? {})) {
1056
+ let allowed: Set<string> | "all" = new Set<string>();
583
1057
 
584
- if (allowedSignals.includes(signal)) {
585
- return { action: "allow" };
1058
+ for (const sub of subs) {
1059
+ if (!sub.signals || sub.signals.length === 0) {
1060
+ // No filter on this subscription — role receives all signals
1061
+ allowed = "all";
1062
+ break;
586
1063
  }
587
-
588
- // Signal not in allowed list — enforce
589
- const message = `Agent '${agentId}' (role: ${role}) emitted disallowed signal '${signal}'. Allowed: [${allowedSignals.join(", ")}]`;
590
-
591
- switch (enforcement) {
592
- case "strict":
593
- return { action: "reject", message };
594
- case "audit":
595
- return { action: "audit", message };
596
- case "permissive":
597
- default:
598
- return { action: "warn", message };
1064
+ for (const sig of sub.signals) {
1065
+ (allowed as Set<string>).add(sig);
599
1066
  }
600
- });
1067
+ }
1068
+
1069
+ this.roleAllowedSignals.set(roleName, allowed);
601
1070
  }
602
1071
  }
603
1072
 
@@ -610,7 +1079,7 @@ Focus on correctness — your changes go live immediately.`);
610
1079
  * Falls back to legacy bidirectional subtree subs when no peers config exists.
611
1080
  */
612
1081
  private wirePeerRoutes(): void {
613
- const peers = this.manifest.communication.routing?.peers;
1082
+ const peers = this.communication.routing?.peers;
614
1083
 
615
1084
  if (!peers || peers.length === 0) {
616
1085
  // Fallback: hardcoded mutual subtree subscriptions (backwards compat)