macro-agent 0.1.0 → 0.1.1

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 (337) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +16 -14
  4. package/README.md +11 -29
  5. package/dist/acp/macro-agent.d.ts +15 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +131 -35
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +32 -1
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts +65 -1
  13. package/dist/agent/agent-manager.d.ts.map +1 -1
  14. package/dist/agent/agent-manager.js +464 -183
  15. package/dist/agent/agent-manager.js.map +1 -1
  16. package/dist/agent/types.d.ts +1 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/api/server.d.ts +3 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +37 -6
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/auth/index.d.ts +2 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +2 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/token.d.ts +41 -0
  27. package/dist/auth/token.d.ts.map +1 -0
  28. package/dist/auth/token.js +73 -0
  29. package/dist/auth/token.js.map +1 -0
  30. package/dist/cli/acp.d.ts +2 -23
  31. package/dist/cli/acp.d.ts.map +1 -1
  32. package/dist/cli/acp.js +127 -61
  33. package/dist/cli/acp.js.map +1 -1
  34. package/dist/cli/index.js +147 -15
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/mcp.d.ts +6 -0
  37. package/dist/cli/mcp.d.ts.map +1 -1
  38. package/dist/cli/mcp.js +268 -181
  39. package/dist/cli/mcp.js.map +1 -1
  40. package/dist/cli/parse-args.d.ts +20 -0
  41. package/dist/cli/parse-args.d.ts.map +1 -0
  42. package/dist/cli/parse-args.js +43 -0
  43. package/dist/cli/parse-args.js.map +1 -0
  44. package/dist/cli/stable-instance-id.d.ts +8 -0
  45. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  46. package/dist/cli/stable-instance-id.js +14 -0
  47. package/dist/cli/stable-instance-id.js.map +1 -0
  48. package/dist/config/project-config.d.ts +74 -7
  49. package/dist/config/project-config.d.ts.map +1 -1
  50. package/dist/config/project-config.js +123 -20
  51. package/dist/config/project-config.js.map +1 -1
  52. package/dist/map/adapter/acp-over-map.d.ts +17 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +384 -23
  55. package/dist/map/adapter/acp-over-map.js.map +1 -1
  56. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  57. package/dist/map/adapter/connection-manager.js +3 -0
  58. package/dist/map/adapter/connection-manager.js.map +1 -1
  59. package/dist/map/adapter/event-log.d.ts +87 -0
  60. package/dist/map/adapter/event-log.d.ts.map +1 -0
  61. package/dist/map/adapter/event-log.js +122 -0
  62. package/dist/map/adapter/event-log.js.map +1 -0
  63. package/dist/map/adapter/event-translator.js +6 -6
  64. package/dist/map/adapter/event-translator.js.map +1 -1
  65. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  66. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  67. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  68. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  69. package/dist/map/adapter/extensions/index.d.ts +10 -1
  70. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  71. package/dist/map/adapter/extensions/index.js +34 -0
  72. package/dist/map/adapter/extensions/index.js.map +1 -1
  73. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  74. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  75. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  76. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  77. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  78. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  79. package/dist/map/adapter/extensions/rename.js +49 -0
  80. package/dist/map/adapter/extensions/rename.js.map +1 -0
  81. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  82. package/dist/map/adapter/extensions/task.js +10 -0
  83. package/dist/map/adapter/extensions/task.js.map +1 -1
  84. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  85. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  86. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  87. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  88. package/dist/map/adapter/index.d.ts +2 -1
  89. package/dist/map/adapter/index.d.ts.map +1 -1
  90. package/dist/map/adapter/index.js +8 -2
  91. package/dist/map/adapter/index.js.map +1 -1
  92. package/dist/map/adapter/interface.d.ts +2 -0
  93. package/dist/map/adapter/interface.d.ts.map +1 -1
  94. package/dist/map/adapter/map-adapter.d.ts +3 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +258 -35
  97. package/dist/map/adapter/map-adapter.js.map +1 -1
  98. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  99. package/dist/map/adapter/subscription-manager.js +5 -1
  100. package/dist/map/adapter/subscription-manager.js.map +1 -1
  101. package/dist/map/adapter/types.d.ts +2 -0
  102. package/dist/map/adapter/types.d.ts.map +1 -1
  103. package/dist/mcp/map-client.d.ts +39 -0
  104. package/dist/mcp/map-client.d.ts.map +1 -0
  105. package/dist/mcp/map-client.js +129 -0
  106. package/dist/mcp/map-client.js.map +1 -0
  107. package/dist/mcp/mcp-server.d.ts +14 -0
  108. package/dist/mcp/mcp-server.d.ts.map +1 -1
  109. package/dist/mcp/mcp-server.js +113 -85
  110. package/dist/mcp/mcp-server.js.map +1 -1
  111. package/dist/mcp/types.d.ts +9 -1
  112. package/dist/mcp/types.d.ts.map +1 -1
  113. package/dist/mcp/types.js.map +1 -1
  114. package/dist/metrics/metrics.js +1 -1
  115. package/dist/metrics/metrics.js.map +1 -1
  116. package/dist/roles/capabilities.d.ts +3 -1
  117. package/dist/roles/capabilities.d.ts.map +1 -1
  118. package/dist/roles/capabilities.js +17 -7
  119. package/dist/roles/capabilities.js.map +1 -1
  120. package/dist/roles/config-loader.d.ts +6 -6
  121. package/dist/roles/config-loader.d.ts.map +1 -1
  122. package/dist/roles/config-loader.js +6 -6
  123. package/dist/roles/config-loader.js.map +1 -1
  124. package/dist/roles/registry.d.ts +2 -2
  125. package/dist/roles/registry.js +2 -2
  126. package/dist/server/combined-server.d.ts +20 -0
  127. package/dist/server/combined-server.d.ts.map +1 -1
  128. package/dist/server/combined-server.js +107 -8
  129. package/dist/server/combined-server.js.map +1 -1
  130. package/dist/store/event-store.d.ts +2 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +69 -20
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +18 -0
  135. package/dist/store/types/agents.d.ts.map +1 -1
  136. package/dist/store/types/events.d.ts +1 -1
  137. package/dist/store/types/events.d.ts.map +1 -1
  138. package/dist/task/backend/index.d.ts +47 -29
  139. package/dist/task/backend/index.d.ts.map +1 -1
  140. package/dist/task/backend/index.js +109 -71
  141. package/dist/task/backend/index.js.map +1 -1
  142. package/dist/task/backend/memory.d.ts +1 -0
  143. package/dist/task/backend/memory.d.ts.map +1 -1
  144. package/dist/task/backend/memory.js +3 -0
  145. package/dist/task/backend/memory.js.map +1 -1
  146. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  147. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  148. package/dist/task/backend/opentasks/backend.js +1023 -0
  149. package/dist/task/backend/opentasks/backend.js.map +1 -0
  150. package/dist/task/backend/opentasks/client.d.ts +337 -0
  151. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  152. package/dist/task/backend/opentasks/client.js +225 -0
  153. package/dist/task/backend/opentasks/client.js.map +1 -0
  154. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  155. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  156. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  157. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  158. package/dist/task/backend/opentasks/index.d.ts +21 -0
  159. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  160. package/dist/task/backend/opentasks/index.js +21 -0
  161. package/dist/task/backend/opentasks/index.js.map +1 -0
  162. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  163. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  164. package/dist/task/backend/opentasks/mapping.js +77 -0
  165. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  166. package/dist/task/backend/types.d.ts +33 -53
  167. package/dist/task/backend/types.d.ts.map +1 -1
  168. package/dist/task/backend/types.js +7 -11
  169. package/dist/task/backend/types.js.map +1 -1
  170. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  171. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  172. package/dist/task/backend/unified-tool-provider.js +623 -0
  173. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  174. package/dist/teams/team-loader.d.ts +2 -2
  175. package/dist/teams/team-loader.js +3 -3
  176. package/dist/teams/team-loader.js.map +1 -1
  177. package/dist/teams/team-runtime.d.ts.map +1 -1
  178. package/dist/teams/team-runtime.js +2 -0
  179. package/dist/teams/team-runtime.js.map +1 -1
  180. package/docs/architecture.md +7 -6
  181. package/docs/configuration.md +26 -62
  182. package/docs/implementation-details.md +5 -5
  183. package/docs/implementation-summary.md +17 -17
  184. package/docs/plan-self-driving-support.md +4 -4
  185. package/docs/spec-self-driving-support.md +10 -10
  186. package/docs/team-templates.md +2 -2
  187. package/docs/teams.md +3 -3
  188. package/docs/troubleshooting.md +10 -11
  189. package/package.json +6 -4
  190. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  191. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  192. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  193. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  194. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  195. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  196. package/src/acp/__tests__/integration.test.ts +56 -31
  197. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  198. package/src/acp/macro-agent.ts +170 -36
  199. package/src/acp/types.ts +46 -1
  200. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  201. package/src/agent/agent-manager.ts +714 -261
  202. package/src/agent/types.ts +3 -1
  203. package/src/api/server.ts +41 -7
  204. package/src/auth/__tests__/token.test.ts +100 -0
  205. package/src/auth/index.ts +1 -0
  206. package/src/auth/token.ts +82 -0
  207. package/src/cli/__tests__/acp.test.ts +1 -1
  208. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  209. package/src/cli/acp.ts +130 -72
  210. package/src/cli/index.ts +120 -14
  211. package/src/cli/mcp.ts +311 -207
  212. package/src/cli/parse-args.ts +54 -0
  213. package/src/cli/stable-instance-id.ts +14 -0
  214. package/src/config/project-config.ts +190 -27
  215. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  216. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
  217. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  218. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
  219. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  220. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  221. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  222. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  223. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  224. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  225. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  226. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  227. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  228. package/src/map/adapter/acp-over-map.ts +678 -66
  229. package/src/map/adapter/connection-manager.ts +3 -0
  230. package/src/map/adapter/event-log.ts +208 -0
  231. package/src/map/adapter/event-translator.ts +6 -6
  232. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  233. package/src/map/adapter/extensions/index.ts +60 -0
  234. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  235. package/src/map/adapter/extensions/task.ts +11 -0
  236. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  237. package/src/map/adapter/index.ts +28 -0
  238. package/src/map/adapter/interface.ts +2 -0
  239. package/src/map/adapter/map-adapter.ts +312 -47
  240. package/src/map/adapter/subscription-manager.ts +5 -1
  241. package/src/map/adapter/types.ts +2 -0
  242. package/src/mcp/__tests__/map-client.test.ts +386 -0
  243. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  244. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  245. package/src/mcp/map-client.ts +177 -0
  246. package/src/mcp/mcp-server.ts +191 -100
  247. package/src/mcp/types.ts +6 -1
  248. package/src/metrics/metrics.ts +1 -1
  249. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  250. package/src/roles/__tests__/config-loader.test.ts +7 -7
  251. package/src/roles/capabilities.ts +17 -7
  252. package/src/roles/config-loader.ts +6 -6
  253. package/src/roles/registry.ts +2 -2
  254. package/src/server/__tests__/combined-server.test.ts +94 -21
  255. package/src/server/combined-server.ts +189 -33
  256. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  257. package/src/store/__tests__/event-store.test.ts +196 -1
  258. package/src/store/__tests__/instance.test.ts +3 -3
  259. package/src/store/event-store.ts +80 -21
  260. package/src/store/types/agents.ts +15 -0
  261. package/src/store/types/events.ts +1 -1
  262. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  263. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  264. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  265. package/src/task/backend/index.ts +156 -106
  266. package/src/task/backend/memory.ts +4 -0
  267. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  268. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  269. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  270. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  271. package/src/task/backend/opentasks/backend.ts +1323 -0
  272. package/src/task/backend/opentasks/client.ts +652 -0
  273. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  274. package/src/task/backend/opentasks/index.ts +69 -0
  275. package/src/task/backend/opentasks/mapping.ts +94 -0
  276. package/src/task/backend/types.ts +42 -66
  277. package/src/task/backend/unified-tool-provider.ts +779 -0
  278. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  279. package/src/teams/team-loader.ts +3 -3
  280. package/src/teams/team-runtime.ts +2 -0
  281. package/test_fixtures/README.md +2 -3
  282. package/test_fixtures/fixtures/index.ts +0 -3
  283. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  284. package/test_fixtures/fixtures/repos/index.ts +1 -3
  285. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  286. package/test_fixtures/fixtures/repos/types.ts +0 -11
  287. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  288. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  289. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  290. package/vitest.config.ts +1 -1
  291. package/vitest.e2e.config.ts +1 -1
  292. package/vitest.setup.ts +1 -30
  293. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  294. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  296. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  297. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  298. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  299. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  300. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  301. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  302. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  303. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  304. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  305. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  306. package/.macro-agent/teams/structured/team.yaml +0 -89
  307. package/docs/sudocode-integration.md +0 -383
  308. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  309. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  310. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  311. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  312. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  313. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  314. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  315. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  316. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  317. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  318. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  319. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  320. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  321. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  322. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  323. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  324. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  325. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  326. package/src/task/backend/sudocode/backend.ts +0 -1237
  327. package/src/task/backend/sudocode/client.ts +0 -515
  328. package/src/task/backend/sudocode/index.ts +0 -120
  329. package/src/task/backend/sudocode/mapping.ts +0 -93
  330. package/src/task/backend/sudocode/server-client.ts +0 -522
  331. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  332. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  333. package/src/task/backend/sudocode/tools.ts +0 -896
  334. package/src/task/backend/tool-provider.ts +0 -506
  335. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  336. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  337. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
package/src/cli/mcp.ts CHANGED
@@ -4,25 +4,17 @@
4
4
  *
5
5
  * Runs the MCP server as a subprocess that agents can connect to.
6
6
  * Agent context is passed via environment variables.
7
+ *
8
+ * Two modes:
9
+ * - **Thin-client mode** (MACRO_SERVER_URL set): Tools forward to the main server
10
+ * via ephemeral MAP WebSocket connections. No local services needed.
11
+ * - **Legacy mode** (MACRO_INSTANCE_ID set): Creates a full local service stack
12
+ * with shared SQLite. Used as fallback for backward compatibility.
7
13
  */
8
14
 
9
15
  import * as fs from "fs";
10
16
  import * as path from "path";
11
17
  import * as os from "os";
12
- import { createEventStore } from "../store/event-store.js";
13
- import { createAgentManager } from "../agent/agent-manager.js";
14
- import { createTaskManager } from "../task/task-manager.js";
15
- import { createMessageRouter } from "../router/message-router.js";
16
- import { createMCPServer } from "../mcp/mcp-server.js";
17
- import {
18
- createActivityWatcher,
19
- subscribeAgentToEvents,
20
- MONITOR_DEFAULT_EVENT_TYPES,
21
- } from "../activity/index.js";
22
- import {
23
- createWakeHandler,
24
- createSessionProviderFromAgentManager,
25
- } from "../agent/wake.js";
26
18
 
27
19
  // Debug logging to file (since stderr doesn't show up from MCP subprocess)
28
20
  const debugLogPath = path.join(os.tmpdir(), "macro-agent-mcp-debug.log");
@@ -33,231 +25,343 @@ function debugLog(message: string) {
33
25
  console.error(message); // Also log to stderr in case it's visible
34
26
  }
35
27
 
36
- async function main() {
37
- // Get agent context from environment variables
38
- const agentId = process.env.MACRO_AGENT_ID;
39
- const parentId = process.env.MACRO_PARENT_ID || null;
28
+ // =============================================================================
29
+ // Thin-Client Mode (MACRO_SERVER_URL)
30
+ // =============================================================================
31
+
32
+ async function startThinClient() {
33
+ const agentId = process.env.MACRO_AGENT_ID!;
40
34
  const taskId = process.env.MACRO_TASK_ID;
41
35
  const agentCwd = process.env.MACRO_AGENT_CWD || process.cwd();
42
- const instanceId = process.env.MACRO_INSTANCE_ID;
43
- const baseDir = process.env.MACRO_BASE_DIR; // Optional: custom base directory for testing
36
+ const serverUrl = process.env.MACRO_SERVER_URL!;
37
+ const lineageStr = process.env.MACRO_AGENT_LINEAGE || "[]";
38
+ const sessionId = process.env.MACRO_SESSION_ID || "";
39
+ const serverToken = process.env.MACRO_SERVER_TOKEN || "";
40
+ const agentToken = process.env.MACRO_AGENT_TOKEN || "";
44
41
 
45
- if (!agentId) {
46
- console.error("Error: MACRO_AGENT_ID environment variable is required");
47
- process.exit(1);
42
+ let lineage: string[];
43
+ try {
44
+ lineage = JSON.parse(lineageStr);
45
+ } catch {
46
+ lineage = [];
48
47
  }
49
48
 
50
- if (!instanceId) {
51
- console.error("Error: MACRO_INSTANCE_ID environment variable is required");
52
- process.exit(1);
53
- }
49
+ debugLog(`[MCP] Thin-client mode: agent=${agentId}, server=${serverUrl}`);
50
+
51
+ const { createMCPServerThinClient } = await import("../mcp/mcp-server.js");
52
+ const { mapCall } = await import("../mcp/map-client.js");
53
+
54
+ const context = {
55
+ agent_id: agentId,
56
+ session_id: sessionId,
57
+ task_id: taskId ?? undefined,
58
+ lineage,
59
+ cwd: agentCwd,
60
+ agent_token: agentToken || undefined,
61
+ };
62
+
63
+ // Also pass permission mode for spawn_agent forwarding
64
+ const permissionMode = process.env.MACRO_PERMISSION_MODE;
65
+
66
+ // Build mapCall options with server token for WebSocket auth
67
+ const callOptions = serverToken ? { serverToken } : undefined;
68
+
69
+ const mcpServer = createMCPServerThinClient(
70
+ context,
71
+ async (method, params, options) => {
72
+ // Merge auth options with per-call options
73
+ const mergedOptions = { ...callOptions, ...options };
74
+ // Inject permission_mode into spawn_agent calls
75
+ if (method === "_macro/mcp/spawn_agent" && permissionMode) {
76
+ const p = (params ?? {}) as Record<string, unknown>;
77
+ p.permission_mode = permissionMode;
78
+ return mapCall(serverUrl, method, p, mergedOptions);
79
+ }
80
+ return mapCall(serverUrl, method, params, mergedOptions);
81
+ }
82
+ );
54
83
 
55
- debugLog(`[MCP] Starting MCP server for agent ${agentId} with instanceId ${instanceId}`);
84
+ await mcpServer.start();
85
+
86
+ // Handle graceful shutdown
87
+ const shutdown = async () => {
88
+ await mcpServer.close();
89
+ process.exit(0);
90
+ };
91
+ process.on("SIGINT", shutdown);
92
+ process.on("SIGTERM", shutdown);
93
+ }
94
+
95
+ // =============================================================================
96
+ // Legacy Mode (MACRO_INSTANCE_ID)
97
+ // =============================================================================
98
+
99
+ async function startLegacy() {
100
+ const agentId = process.env.MACRO_AGENT_ID!;
101
+ const taskId = process.env.MACRO_TASK_ID;
102
+ const agentCwd = process.env.MACRO_AGENT_CWD || process.cwd();
103
+ const instanceId = process.env.MACRO_INSTANCE_ID!;
104
+ const baseDir = process.env.MACRO_BASE_DIR;
105
+
106
+ debugLog(`[MCP] Legacy mode: agent=${agentId}, instanceId=${instanceId}`);
56
107
  debugLog(`[MCP] Debug log file: ${debugLogPath}`);
57
108
 
109
+ const { createEventStore } = await import("../store/event-store.js");
110
+ const { createAgentManager } = await import("../agent/agent-manager.js");
111
+ const { createTaskManager } = await import("../task/task-manager.js");
112
+ const { createMessageRouter } = await import("../router/message-router.js");
113
+ const { createMCPServer } = await import("../mcp/mcp-server.js");
114
+ const { createTaskBackend, loadTaskConfigFromEnv } = await import("../task/backend/index.js");
115
+ const { UnifiedTaskToolProvider } = await import("../task/backend/unified-tool-provider.js");
116
+ const {
117
+ createActivityWatcher,
118
+ subscribeAgentToEvents,
119
+ MONITOR_DEFAULT_EVENT_TYPES,
120
+ } = await import("../activity/index.js");
121
+ const {
122
+ createWakeHandler,
123
+ createSessionProviderFromAgentManager,
124
+ } = await import("../agent/wake.js");
125
+
126
+ // Initialize services with shared file-based storage
127
+ const eventStore = await createEventStore({ inMemory: false, instanceId, baseDir });
128
+ debugLog(`[MCP] EventStore created, path: ${eventStore.instancePath}`);
129
+ const messageRouter = createMessageRouter(eventStore);
130
+ const agentManager = createAgentManager(eventStore, messageRouter);
131
+ const taskManager = createTaskManager(eventStore);
132
+
133
+ // Create task backend from env config
134
+ const taskConfig = loadTaskConfigFromEnv();
135
+ let taskBackend: import("../task/backend/types.js").TaskBackend | undefined;
136
+ let taskToolProvider: InstanceType<typeof UnifiedTaskToolProvider> | undefined;
137
+ let openTasksClient: import("../task/backend/opentasks/client.js").OpenTasksClient | undefined;
138
+
58
139
  try {
59
- // Initialize services with shared file-based storage using the same instanceId as the main process
60
- // If MACRO_BASE_DIR is provided (e.g., for testing), use it to resolve to the correct database location
61
- const eventStore = await createEventStore({ inMemory: false, instanceId, baseDir });
62
- debugLog(`[MCP] EventStore created, path: ${eventStore.instancePath}`);
63
- const messageRouter = createMessageRouter(eventStore);
64
- const agentManager = createAgentManager(eventStore, messageRouter);
65
- const taskManager = createTaskManager(eventStore);
66
-
67
- // Get agent lineage for authorization checks
68
- // Note: The agent may not be in the store yet if the MCP server starts before
69
- // the spawn event is persisted. This is a race condition - we retry a few times.
70
- let agent = eventStore.getAgent(agentId);
71
- const allAgentsInitial = eventStore.listAgents();
72
- debugLog(`[MCP] Initial check: agent found = ${!!agent}, total agents in store = ${allAgentsInitial.length}`);
73
- if (allAgentsInitial.length > 0) {
74
- debugLog(`[MCP] Agents in store: ${allAgentsInitial.map(a => a.id).join(', ')}`);
75
- }
140
+ const result = await createTaskBackend(taskConfig, eventStore);
141
+ taskBackend = result.backend;
142
+ openTasksClient = result.openTasksClient;
143
+
144
+ taskToolProvider = new UnifiedTaskToolProvider(
145
+ taskBackend,
146
+ () => ({ agent_id: agentId! }),
147
+ openTasksClient
148
+ );
149
+ debugLog(`[MCP] Task backend created: ${taskConfig.backend.type}`);
150
+ } catch (err) {
151
+ debugLog(`[MCP] Failed to create task backend: ${err}. Falling back to legacy TaskManager only.`);
152
+ }
76
153
 
77
- if (!agent) {
78
- // Retry a few times with small delays to handle race condition
79
- // where MCP server starts before spawn event is persisted
80
- for (let i = 0; i < 10; i++) {
81
- await new Promise(resolve => setTimeout(resolve, 100));
82
- // Reload from SQLite to get fresh data
83
- await eventStore.reload();
84
- agent = eventStore.getAgent(agentId);
85
- const allAgentsRetry = eventStore.listAgents();
86
- debugLog(`[MCP] Retry ${i + 1}: agent found = ${!!agent}, total agents = ${allAgentsRetry.length}`);
87
- if (agent) {
88
- debugLog(`[MCP] Found agent ${agentId} after ${i + 1} retries`);
89
- break;
90
- }
154
+ // Get agent lineage for authorization checks
155
+ let agent = eventStore.getAgent(agentId);
156
+ const allAgentsInitial = eventStore.listAgents();
157
+ debugLog(`[MCP] Initial check: agent found = ${!!agent}, total agents in store = ${allAgentsInitial.length}`);
158
+ if (allAgentsInitial.length > 0) {
159
+ debugLog(`[MCP] Agents in store: ${allAgentsInitial.map(a => a.id).join(', ')}`);
160
+ }
161
+
162
+ if (!agent) {
163
+ for (let i = 0; i < 10; i++) {
164
+ await new Promise(resolve => setTimeout(resolve, 100));
165
+ await eventStore.reload();
166
+ agent = eventStore.getAgent(agentId);
167
+ const allAgentsRetry = eventStore.listAgents();
168
+ debugLog(`[MCP] Retry ${i + 1}: agent found = ${!!agent}, total agents = ${allAgentsRetry.length}`);
169
+ if (agent) {
170
+ debugLog(`[MCP] Found agent ${agentId} after ${i + 1} retries`);
171
+ break;
91
172
  }
92
- } else {
93
- debugLog(`[MCP] Agent ${agentId} found immediately (no retry needed)`);
94
173
  }
174
+ } else {
175
+ debugLog(`[MCP] Agent ${agentId} found immediately (no retry needed)`);
176
+ }
95
177
 
96
- if (!agent) {
97
- debugLog(`[MCP] Warning: Agent ${agentId} not found in store after retries. ` +
98
- `Continuing with limited context. This may affect authorization checks.`);
99
- // List all events to help debug
100
- const events = eventStore.query({ limit: 50 });
101
- debugLog(`[MCP] Events in store (${events.length}): ${events.map(e => `${e.type}:${e.payload?.agent_id || e.source?.agent_id}`).join(', ')}`);
102
- }
178
+ if (!agent) {
179
+ debugLog(`[MCP] Warning: Agent ${agentId} not found in store after retries. ` +
180
+ `Continuing with limited context. This may affect authorization checks.`);
181
+ const events = eventStore.query({ limit: 50 });
182
+ debugLog(`[MCP] Events in store (${events.length}): ${events.map(e => `${e.type}:${e.payload?.agent_id || e.source?.agent_id}`).join(', ')}`);
183
+ }
103
184
 
104
- const lineage = agent?.lineage ?? [];
105
-
106
- // Create ActivityWatcher for wait_for_activity MCP tool
107
- const sessionProvider = createSessionProviderFromAgentManager(agentManager);
108
- const wakeHandler = createWakeHandler(sessionProvider, agentManager);
109
- const activityWatcher = createActivityWatcher(
110
- {
111
- listAgents: () => agentManager.list(),
112
- getAgent: (id) => agentManager.get(id),
113
- },
114
- wakeHandler
115
- );
185
+ const lineage = agent?.lineage ?? [];
116
186
 
117
- // Wire EventStore events to ActivityWatcher
118
- eventStore.onAgentChange((changedAgentId, changedAgent) => {
119
- if (!activityWatcher.isRunning()) return;
120
- if (!changedAgent) return; // Agent was deleted
121
-
122
- // Infer event type from agent state
123
- const eventType = changedAgent.state === "spawning" ? "agent_spawned"
124
- : changedAgent.state === "running" ? "agent_started"
125
- : changedAgent.state === "stopped" ? "agent_terminated"
126
- : "agent_updated";
127
-
128
- activityWatcher.processActivity({
129
- id: `evt-${Date.now()}-${Math.random().toString(36).slice(2)}`,
130
- type: eventType,
131
- source: { agent_id: changedAgentId, role: changedAgent.role },
132
- timestamp: Date.now(),
133
- details: { state: changedAgent.state },
134
- });
135
- });
187
+ // Create ActivityWatcher for wait_for_activity MCP tool
188
+ const sessionProvider = createSessionProviderFromAgentManager(agentManager);
189
+ const wakeHandler = createWakeHandler(sessionProvider, agentManager);
190
+ const activityWatcher = createActivityWatcher(
191
+ {
192
+ listAgents: () => agentManager.list(),
193
+ getAgent: (id) => agentManager.get(id),
194
+ },
195
+ wakeHandler
196
+ );
197
+
198
+ // Wire EventStore events to ActivityWatcher
199
+ eventStore.onAgentChange((changedAgentId, changedAgent) => {
200
+ if (!activityWatcher.isRunning()) return;
201
+ if (!changedAgent) return;
136
202
 
137
- eventStore.onTaskChange((changedTaskId, task) => {
138
- if (!activityWatcher.isRunning()) return;
139
- if (!task) return; // Task was deleted
140
-
141
- // Infer event type from task status
142
- const eventType = task.status === "pending" ? "task_created"
143
- : task.status === "assigned" ? "task_assigned"
144
- : task.status === "in_progress" ? "task_started"
145
- : task.status === "completed" ? "task_completed"
146
- : task.status === "failed" ? "task_failed"
147
- : "task_updated";
148
-
149
- activityWatcher.processActivity({
150
- id: `evt-${Date.now()}-${Math.random().toString(36).slice(2)}`,
151
- type: eventType,
152
- source: { agent_id: task.assigned_agent ?? undefined, task_id: changedTaskId },
153
- timestamp: Date.now(),
154
- details: { status: task.status },
155
- });
203
+ const eventType = changedAgent.state === "spawning" ? "agent_spawned"
204
+ : changedAgent.state === "running" ? "agent_started"
205
+ : changedAgent.state === "stopped" ? "agent_terminated"
206
+ : "agent_updated";
207
+
208
+ activityWatcher.processActivity({
209
+ id: `evt-${Date.now()}-${Math.random().toString(36).slice(2)}`,
210
+ type: eventType,
211
+ source: { agent_id: changedAgentId, role: changedAgent.role },
212
+ timestamp: Date.now(),
213
+ details: { state: changedAgent.state },
156
214
  });
215
+ });
157
216
 
158
- // Start the ActivityWatcher
159
- activityWatcher.start();
160
-
161
- // Auto-subscribe Monitor agents to health events when they spawn
162
- agentManager.onLifecycleEvent((event) => {
163
- if (event.type === "spawned") {
164
- const spawnedAgent = event.agent;
165
- // Check if this is a Monitor agent
166
- if (spawnedAgent.role === "monitor" || spawnedAgent.role?.startsWith("monitor.")) {
167
- subscribeAgentToEvents(
168
- activityWatcher,
169
- spawnedAgent.id,
170
- MONITOR_DEFAULT_EVENT_TYPES,
171
- undefined, // No scope filter - monitor sees all
172
- "high" // High priority for health events
173
- );
174
- debugLog(`[MCP] Auto-subscribed Monitor ${spawnedAgent.id} to health events`);
175
- }
176
- }
217
+ eventStore.onTaskChange((changedTaskId, task) => {
218
+ if (!activityWatcher.isRunning()) return;
219
+ if (!task) return;
220
+
221
+ const eventType = task.status === "pending" ? "task_created"
222
+ : task.status === "assigned" ? "task_assigned"
223
+ : task.status === "in_progress" ? "task_started"
224
+ : task.status === "completed" ? "task_completed"
225
+ : task.status === "failed" ? "task_failed"
226
+ : "task_updated";
227
+
228
+ activityWatcher.processActivity({
229
+ id: `evt-${Date.now()}-${Math.random().toString(36).slice(2)}`,
230
+ type: eventType,
231
+ source: { agent_id: task.assigned_agent ?? undefined, task_id: changedTaskId },
232
+ timestamp: Date.now(),
233
+ details: { status: task.status },
177
234
  });
235
+ });
178
236
 
179
- // Read team config from EventStore (stored by TeamRuntime.initialize)
180
- let teamTaskMode: string | undefined;
181
- const teamEvents = eventStore.query({ type: "status", limit: 50 });
182
- const teamConfigEvent = teamEvents.find(
183
- (e) => e.payload?.team_config != null
184
- );
185
- if (teamConfigEvent?.payload?.team_config) {
186
- const tc = teamConfigEvent.payload.team_config as Record<string, unknown>;
187
- teamTaskMode = tc.taskMode as string | undefined;
188
- debugLog(`[MCP] Found team config: team=${tc.teamName}, strategy=${tc.strategy}, taskMode=${tc.taskMode}`);
237
+ activityWatcher.start();
238
+
239
+ // Auto-subscribe Monitor agents to health events when they spawn
240
+ agentManager.onLifecycleEvent((event) => {
241
+ if (event.type === "spawned") {
242
+ const spawnedAgent = event.agent;
243
+ if (spawnedAgent.role === "monitor" || spawnedAgent.role?.startsWith("monitor.")) {
244
+ subscribeAgentToEvents(
245
+ activityWatcher,
246
+ spawnedAgent.id,
247
+ MONITOR_DEFAULT_EVENT_TYPES,
248
+ undefined,
249
+ "high"
250
+ );
251
+ debugLog(`[MCP] Auto-subscribed Monitor ${spawnedAgent.id} to health events`);
252
+ }
189
253
  }
254
+ });
190
255
 
191
- // Register team roles in local RoleRegistry for capability checks
192
- const roleRegistry = agentManager.getRoleRegistry();
193
- let integrationStrategy: import("../workspace/strategies/types.js").IntegrationStrategy | undefined;
256
+ // Read team config from EventStore
257
+ let teamTaskMode: string | undefined;
258
+ const teamEvents = eventStore.query({ type: "status", limit: 50 });
259
+ const teamConfigEvent = teamEvents.find(
260
+ (e) => e.payload?.team_config != null
261
+ );
262
+ if (teamConfigEvent?.payload?.team_config) {
263
+ const tc = teamConfigEvent.payload.team_config as Record<string, unknown>;
264
+ teamTaskMode = tc.taskMode as string | undefined;
265
+ debugLog(`[MCP] Found team config: team=${tc.teamName}, strategy=${tc.strategy}, taskMode=${tc.taskMode}`);
266
+ }
194
267
 
195
- if (teamConfigEvent?.payload?.team_config) {
196
- const tc = teamConfigEvent.payload.team_config as Record<string, unknown>;
268
+ // Register team roles in local RoleRegistry
269
+ const roleRegistry = agentManager.getRoleRegistry();
270
+ let integrationStrategy: import("../workspace/strategies/types.js").IntegrationStrategy | undefined;
197
271
 
198
- // Register serialized team roles (stored by TeamRuntime.initialize)
199
- const roles = tc.roles as Record<string, { name: string; capabilities: string[] }> | undefined;
200
- if (roles) {
201
- for (const roleDef of Object.values(roles)) {
202
- roleRegistry.registerRole(roleDef as import("../roles/types.js").RoleDefinition);
203
- }
204
- debugLog(`[MCP] Registered ${Object.keys(roles).length} team roles in RoleRegistry`);
205
- }
272
+ if (teamConfigEvent?.payload?.team_config) {
273
+ const tc = teamConfigEvent.payload.team_config as Record<string, unknown>;
206
274
 
207
- // Instantiate integration strategy from team config
208
- const strategyName = tc.strategy as string | undefined;
209
- if (strategyName) {
210
- try {
211
- const { defaultStrategyRegistry } = await import("../workspace/strategies/registry.js");
212
- integrationStrategy = defaultStrategyRegistry.get(
213
- strategyName,
214
- tc.strategyConfig as Record<string, unknown> | undefined
215
- );
216
- debugLog(`[MCP] Instantiated '${strategyName}' integration strategy`);
217
- } catch (err) {
218
- debugLog(`[MCP] Failed to instantiate strategy '${strategyName}': ${err}`);
219
- }
275
+ const roles = tc.roles as Record<string, { name: string; capabilities: string[] }> | undefined;
276
+ if (roles) {
277
+ for (const roleDef of Object.values(roles)) {
278
+ roleRegistry.registerRole(roleDef as import("../roles/types.js").RoleDefinition);
220
279
  }
280
+ debugLog(`[MCP] Registered ${Object.keys(roles).length} team roles in RoleRegistry`);
221
281
  }
222
282
 
223
- // Create MCP server with agent context
224
- const mcpServer = createMCPServer(
225
- {
226
- agent_id: agentId,
227
- session_id: agent?.session_id ?? "",
228
- task_id: taskId ?? undefined,
229
- lineage,
230
- cwd: agentCwd,
231
- },
232
- {
233
- eventStore,
234
- agentManager,
235
- taskManager,
236
- messageRouter,
237
- activityWatcher,
238
- taskMode: teamTaskMode as "push" | "pull" | undefined,
239
- roleRegistry,
240
- integrationStrategy,
283
+ const strategyName = tc.strategy as string | undefined;
284
+ if (strategyName) {
285
+ try {
286
+ const { defaultStrategyRegistry } = await import("../workspace/strategies/registry.js");
287
+ integrationStrategy = defaultStrategyRegistry.get(
288
+ strategyName,
289
+ tc.strategyConfig as Record<string, unknown> | undefined
290
+ );
291
+ debugLog(`[MCP] Instantiated '${strategyName}' integration strategy`);
292
+ } catch (err) {
293
+ debugLog(`[MCP] Failed to instantiate strategy '${strategyName}': ${err}`);
241
294
  }
242
- );
295
+ }
296
+ }
297
+
298
+ const mcpServer = createMCPServer(
299
+ {
300
+ agent_id: agentId,
301
+ session_id: agent?.session_id ?? "",
302
+ task_id: taskId ?? undefined,
303
+ lineage,
304
+ cwd: agentCwd,
305
+ },
306
+ {
307
+ eventStore,
308
+ agentManager,
309
+ taskManager,
310
+ messageRouter,
311
+ activityWatcher,
312
+ taskMode: teamTaskMode as "push" | "pull" | undefined,
313
+ roleRegistry,
314
+ integrationStrategy,
315
+ taskBackend,
316
+ taskToolProvider,
317
+ }
318
+ );
243
319
 
244
- // Start the MCP server (uses stdio transport)
245
- await mcpServer.start();
320
+ await mcpServer.start();
246
321
 
247
- // Handle graceful shutdown
248
- process.on("SIGINT", async () => {
249
- activityWatcher.stop();
250
- await mcpServer.close();
251
- await eventStore.close();
252
- process.exit(0);
253
- });
322
+ // Handle graceful shutdown
323
+ process.on("SIGINT", async () => {
324
+ activityWatcher.stop();
325
+ try { openTasksClient?.disconnect(); } catch { /* ignore */ }
326
+ await mcpServer.close();
327
+ await eventStore.close();
328
+ process.exit(0);
329
+ });
254
330
 
255
- process.on("SIGTERM", async () => {
256
- activityWatcher.stop();
257
- await mcpServer.close();
258
- await eventStore.close();
259
- process.exit(0);
260
- });
331
+ process.on("SIGTERM", async () => {
332
+ activityWatcher.stop();
333
+ try { openTasksClient?.disconnect(); } catch { /* ignore */ }
334
+ await mcpServer.close();
335
+ await eventStore.close();
336
+ process.exit(0);
337
+ });
338
+ }
339
+
340
+ // =============================================================================
341
+ // Main
342
+ // =============================================================================
343
+
344
+ async function main() {
345
+ const agentId = process.env.MACRO_AGENT_ID;
346
+ const serverUrl = process.env.MACRO_SERVER_URL;
347
+ const instanceId = process.env.MACRO_INSTANCE_ID;
348
+
349
+ if (!agentId) {
350
+ console.error("Error: MACRO_AGENT_ID environment variable is required");
351
+ process.exit(1);
352
+ }
353
+
354
+ try {
355
+ if (serverUrl) {
356
+ // Thin-client mode: forward tool calls to main server via MAP WebSocket
357
+ await startThinClient();
358
+ } else if (instanceId) {
359
+ // Legacy mode: create full local service stack with shared SQLite
360
+ await startLegacy();
361
+ } else {
362
+ console.error("Error: Either MACRO_SERVER_URL or MACRO_INSTANCE_ID environment variable is required");
363
+ process.exit(1);
364
+ }
261
365
  } catch (error) {
262
366
  console.error(`Failed to start MCP server: ${error}`);
263
367
  process.exit(1);
@@ -0,0 +1,54 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ export interface ACPServerOptions {
6
+ /** Working directory for agents */
7
+ cwd?: string;
8
+ /** Stdio ACP-only mode (for embedded use with acp-factory) */
9
+ acp?: boolean;
10
+ /** Port for server (default: 3001) */
11
+ port?: number;
12
+ /** Host for server (default: localhost) */
13
+ host?: string;
14
+ /** Instance ID to reuse an existing event store (omit for new instance) */
15
+ instanceId?: string;
16
+ /** Disable authentication (for local development/testing) */
17
+ noAuth?: boolean;
18
+ }
19
+
20
+ /**
21
+ * Parse command line arguments.
22
+ * @param argv Optional array of arguments (defaults to process.argv.slice(2))
23
+ */
24
+ export function parseArgs(argv?: string[]): ACPServerOptions {
25
+ const args = argv ?? process.argv.slice(2);
26
+ const options: ACPServerOptions = {};
27
+
28
+ for (let i = 0; i < args.length; i++) {
29
+ if (args[i] === "--version" || args[i] === "-v") {
30
+ const __dirname = dirname(fileURLToPath(import.meta.url));
31
+ const pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
32
+ console.log(pkg.version);
33
+ process.exit(0);
34
+ } else if (args[i] === "--cwd" && args[i + 1]) {
35
+ options.cwd = args[i + 1];
36
+ i++;
37
+ } else if (args[i] === "--acp") {
38
+ options.acp = true;
39
+ } else if (args[i] === "--port" && args[i + 1]) {
40
+ options.port = parseInt(args[i + 1], 10);
41
+ i++;
42
+ } else if (args[i] === "--host" && args[i + 1]) {
43
+ options.host = args[i + 1];
44
+ i++;
45
+ } else if (args[i] === "--instance-id" && args[i + 1]) {
46
+ options.instanceId = args[i + 1];
47
+ i++;
48
+ } else if (args[i] === "--no-auth") {
49
+ options.noAuth = true;
50
+ }
51
+ }
52
+
53
+ return options;
54
+ }
@@ -0,0 +1,14 @@
1
+ import { createHash } from "node:crypto";
2
+ import { resolve } from "node:path";
3
+
4
+ /**
5
+ * Generate a stable, deterministic instance ID from a directory path.
6
+ *
7
+ * This ensures the same project always uses the same EventStore,
8
+ * so agents and sessions persist across server restarts.
9
+ */
10
+ export function getStableInstanceId(cwd: string): string {
11
+ const normalizedPath = resolve(cwd);
12
+ const hash = createHash("sha256").update(normalizedPath).digest("hex").slice(0, 12);
13
+ return `inst_${hash}`;
14
+ }