macro-agent 0.0.10 → 0.0.12

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 (518) hide show
  1. package/.macro-agent/teams/self-driving/prompts/grinder.md +27 -0
  2. package/.macro-agent/teams/self-driving/prompts/judge.md +27 -0
  3. package/.macro-agent/teams/self-driving/prompts/planner.md +33 -0
  4. package/.macro-agent/teams/self-driving/roles/grinder.yaml +17 -0
  5. package/.macro-agent/teams/self-driving/roles/judge.yaml +24 -0
  6. package/.macro-agent/teams/self-driving/roles/planner.yaml +18 -0
  7. package/.macro-agent/teams/self-driving/team.yaml +103 -0
  8. package/.macro-agent/teams/structured/prompts/developer.md +26 -0
  9. package/.macro-agent/teams/structured/prompts/lead.md +25 -0
  10. package/.macro-agent/teams/structured/prompts/reviewer.md +24 -0
  11. package/.macro-agent/teams/structured/roles/developer.yaml +12 -0
  12. package/.macro-agent/teams/structured/roles/lead.yaml +11 -0
  13. package/.macro-agent/teams/structured/roles/reviewer.yaml +19 -0
  14. package/.macro-agent/teams/structured/team.yaml +89 -0
  15. package/.sudocode/issues.jsonl +56 -51
  16. package/.sudocode/specs.jsonl +8 -1
  17. package/CLAUDE.md +121 -30
  18. package/README.md +60 -3
  19. package/dist/acp/macro-agent.d.ts +4 -0
  20. package/dist/acp/macro-agent.d.ts.map +1 -1
  21. package/dist/acp/macro-agent.js +50 -4
  22. package/dist/acp/macro-agent.js.map +1 -1
  23. package/dist/acp/session-mapper.d.ts +20 -1
  24. package/dist/acp/session-mapper.d.ts.map +1 -1
  25. package/dist/acp/session-mapper.js +90 -1
  26. package/dist/acp/session-mapper.js.map +1 -1
  27. package/dist/acp/types.d.ts +24 -1
  28. package/dist/acp/types.d.ts.map +1 -1
  29. package/dist/acp/types.js.map +1 -1
  30. package/dist/agent/agent-manager.d.ts +40 -1
  31. package/dist/agent/agent-manager.d.ts.map +1 -1
  32. package/dist/agent/agent-manager.js +172 -8
  33. package/dist/agent/agent-manager.js.map +1 -1
  34. package/dist/agent/types.d.ts +22 -0
  35. package/dist/agent/types.d.ts.map +1 -1
  36. package/dist/agent/types.js.map +1 -1
  37. package/dist/agent/wake.d.ts +15 -0
  38. package/dist/agent/wake.d.ts.map +1 -1
  39. package/dist/agent/wake.js +15 -0
  40. package/dist/agent/wake.js.map +1 -1
  41. package/dist/agent-detection/command-builder.d.ts +30 -0
  42. package/dist/agent-detection/command-builder.d.ts.map +1 -0
  43. package/dist/agent-detection/command-builder.js +71 -0
  44. package/dist/agent-detection/command-builder.js.map +1 -0
  45. package/dist/agent-detection/detector.d.ts +84 -0
  46. package/dist/agent-detection/detector.d.ts.map +1 -0
  47. package/dist/agent-detection/detector.js +240 -0
  48. package/dist/agent-detection/detector.js.map +1 -0
  49. package/dist/agent-detection/index.d.ts +12 -0
  50. package/dist/agent-detection/index.d.ts.map +1 -0
  51. package/dist/agent-detection/index.js +14 -0
  52. package/dist/agent-detection/index.js.map +1 -0
  53. package/dist/agent-detection/registry.d.ts +53 -0
  54. package/dist/agent-detection/registry.d.ts.map +1 -0
  55. package/dist/agent-detection/registry.js +177 -0
  56. package/dist/agent-detection/registry.js.map +1 -0
  57. package/dist/agent-detection/types.d.ts +121 -0
  58. package/dist/agent-detection/types.d.ts.map +1 -0
  59. package/dist/agent-detection/types.js +20 -0
  60. package/dist/agent-detection/types.js.map +1 -0
  61. package/dist/api/server.d.ts +5 -1
  62. package/dist/api/server.d.ts.map +1 -1
  63. package/dist/api/server.js +362 -0
  64. package/dist/api/server.js.map +1 -1
  65. package/dist/api/types.d.ts +50 -1
  66. package/dist/api/types.d.ts.map +1 -1
  67. package/dist/cli/acp.d.ts +2 -0
  68. package/dist/cli/acp.d.ts.map +1 -1
  69. package/dist/cli/acp.js +8 -1
  70. package/dist/cli/acp.js.map +1 -1
  71. package/dist/cli/index.js +29 -0
  72. package/dist/cli/index.js.map +1 -1
  73. package/dist/cli/mcp.js +38 -0
  74. package/dist/cli/mcp.js.map +1 -1
  75. package/dist/config/index.d.ts +2 -0
  76. package/dist/config/index.d.ts.map +1 -0
  77. package/dist/config/index.js +2 -0
  78. package/dist/config/index.js.map +1 -0
  79. package/dist/config/project-config.d.ts +46 -0
  80. package/dist/config/project-config.d.ts.map +1 -0
  81. package/dist/config/project-config.js +68 -0
  82. package/dist/config/project-config.js.map +1 -0
  83. package/dist/lifecycle/cascade.d.ts +1 -1
  84. package/dist/lifecycle/cascade.d.ts.map +1 -1
  85. package/dist/lifecycle/handlers/index.d.ts +4 -0
  86. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  87. package/dist/lifecycle/handlers/index.js +2 -0
  88. package/dist/lifecycle/handlers/index.js.map +1 -1
  89. package/dist/lifecycle/handlers/worker.d.ts +4 -0
  90. package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
  91. package/dist/lifecycle/handlers/worker.js +35 -3
  92. package/dist/lifecycle/handlers/worker.js.map +1 -1
  93. package/dist/mail/conversation-map.d.ts +33 -0
  94. package/dist/mail/conversation-map.d.ts.map +1 -0
  95. package/dist/mail/conversation-map.js +61 -0
  96. package/dist/mail/conversation-map.js.map +1 -0
  97. package/dist/mail/index.d.ts +11 -0
  98. package/dist/mail/index.d.ts.map +1 -0
  99. package/dist/mail/index.js +11 -0
  100. package/dist/mail/index.js.map +1 -0
  101. package/dist/mail/mail-service.d.ts +85 -0
  102. package/dist/mail/mail-service.d.ts.map +1 -0
  103. package/dist/mail/mail-service.js +121 -0
  104. package/dist/mail/mail-service.js.map +1 -0
  105. package/dist/mail/stores/eventstore-conversation-store.d.ts +40 -0
  106. package/dist/mail/stores/eventstore-conversation-store.d.ts.map +1 -0
  107. package/dist/mail/stores/eventstore-conversation-store.js +131 -0
  108. package/dist/mail/stores/eventstore-conversation-store.js.map +1 -0
  109. package/dist/mail/stores/eventstore-participant-store.d.ts +43 -0
  110. package/dist/mail/stores/eventstore-participant-store.d.ts.map +1 -0
  111. package/dist/mail/stores/eventstore-participant-store.js +145 -0
  112. package/dist/mail/stores/eventstore-participant-store.js.map +1 -0
  113. package/dist/mail/stores/eventstore-thread-store.d.ts +46 -0
  114. package/dist/mail/stores/eventstore-thread-store.d.ts.map +1 -0
  115. package/dist/mail/stores/eventstore-thread-store.js +118 -0
  116. package/dist/mail/stores/eventstore-thread-store.js.map +1 -0
  117. package/dist/mail/stores/eventstore-turn-store.d.ts +47 -0
  118. package/dist/mail/stores/eventstore-turn-store.d.ts.map +1 -0
  119. package/dist/mail/stores/eventstore-turn-store.js +153 -0
  120. package/dist/mail/stores/eventstore-turn-store.js.map +1 -0
  121. package/dist/mail/stores/index.d.ts +12 -0
  122. package/dist/mail/stores/index.d.ts.map +1 -0
  123. package/dist/mail/stores/index.js +12 -0
  124. package/dist/mail/stores/index.js.map +1 -0
  125. package/dist/mail/stores/types.d.ts +146 -0
  126. package/dist/mail/stores/types.d.ts.map +1 -0
  127. package/dist/mail/stores/types.js +13 -0
  128. package/dist/mail/stores/types.js.map +1 -0
  129. package/dist/mail/turn-recorder.d.ts +30 -0
  130. package/dist/mail/turn-recorder.d.ts.map +1 -0
  131. package/dist/mail/turn-recorder.js +98 -0
  132. package/dist/mail/turn-recorder.js.map +1 -0
  133. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  134. package/dist/map/adapter/acp-over-map.js +32 -2
  135. package/dist/map/adapter/acp-over-map.js.map +1 -1
  136. package/dist/map/adapter/event-translator.d.ts.map +1 -1
  137. package/dist/map/adapter/event-translator.js +4 -0
  138. package/dist/map/adapter/event-translator.js.map +1 -1
  139. package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
  140. package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
  141. package/dist/map/adapter/extensions/agent-detection.js +91 -0
  142. package/dist/map/adapter/extensions/agent-detection.js.map +1 -0
  143. package/dist/map/adapter/extensions/index.d.ts +10 -1
  144. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  145. package/dist/map/adapter/extensions/index.js +39 -0
  146. package/dist/map/adapter/extensions/index.js.map +1 -1
  147. package/dist/map/adapter/extensions/resume.d.ts +47 -0
  148. package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
  149. package/dist/map/adapter/extensions/resume.js +59 -0
  150. package/dist/map/adapter/extensions/resume.js.map +1 -0
  151. package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
  152. package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
  153. package/dist/map/adapter/extensions/workspace-files.js +338 -0
  154. package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
  155. package/dist/map/adapter/mail-handler-adapter.d.ts +27 -0
  156. package/dist/map/adapter/mail-handler-adapter.d.ts.map +1 -0
  157. package/dist/map/adapter/mail-handler-adapter.js +292 -0
  158. package/dist/map/adapter/mail-handler-adapter.js.map +1 -0
  159. package/dist/map/adapter/map-adapter.d.ts +34 -10
  160. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  161. package/dist/map/adapter/map-adapter.js +110 -14
  162. package/dist/map/adapter/map-adapter.js.map +1 -1
  163. package/dist/map/adapter/rpc-handler.d.ts +4 -1
  164. package/dist/map/adapter/rpc-handler.d.ts.map +1 -1
  165. package/dist/map/adapter/rpc-handler.js +6 -0
  166. package/dist/map/adapter/rpc-handler.js.map +1 -1
  167. package/dist/map/index.d.ts +1 -0
  168. package/dist/map/index.d.ts.map +1 -1
  169. package/dist/map/index.js +2 -0
  170. package/dist/map/index.js.map +1 -1
  171. package/dist/map/types.d.ts +3 -1
  172. package/dist/map/types.d.ts.map +1 -1
  173. package/dist/map/types.js.map +1 -1
  174. package/dist/mcp/mcp-server.d.ts +6 -0
  175. package/dist/mcp/mcp-server.d.ts.map +1 -1
  176. package/dist/mcp/mcp-server.js +45 -0
  177. package/dist/mcp/mcp-server.js.map +1 -1
  178. package/dist/mcp/tools/claim_task.d.ts +35 -0
  179. package/dist/mcp/tools/claim_task.d.ts.map +1 -0
  180. package/dist/mcp/tools/claim_task.js +58 -0
  181. package/dist/mcp/tools/claim_task.js.map +1 -0
  182. package/dist/mcp/tools/done.d.ts +15 -2
  183. package/dist/mcp/tools/done.d.ts.map +1 -1
  184. package/dist/mcp/tools/done.js +45 -10
  185. package/dist/mcp/tools/done.js.map +1 -1
  186. package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
  187. package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
  188. package/dist/mcp/tools/list_claimable_tasks.js +63 -0
  189. package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
  190. package/dist/mcp/tools/unclaim_task.d.ts +31 -0
  191. package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
  192. package/dist/mcp/tools/unclaim_task.js +47 -0
  193. package/dist/mcp/tools/unclaim_task.js.map +1 -0
  194. package/dist/metrics/index.d.ts +2 -0
  195. package/dist/metrics/index.d.ts.map +1 -0
  196. package/dist/metrics/index.js +2 -0
  197. package/dist/metrics/index.js.map +1 -0
  198. package/dist/metrics/metrics.d.ts +79 -0
  199. package/dist/metrics/metrics.d.ts.map +1 -0
  200. package/dist/metrics/metrics.js +166 -0
  201. package/dist/metrics/metrics.js.map +1 -0
  202. package/dist/roles/capabilities.d.ts +1 -0
  203. package/dist/roles/capabilities.d.ts.map +1 -1
  204. package/dist/roles/capabilities.js +3 -0
  205. package/dist/roles/capabilities.js.map +1 -1
  206. package/dist/roles/types.d.ts +1 -1
  207. package/dist/roles/types.d.ts.map +1 -1
  208. package/dist/router/channels.d.ts +2 -4
  209. package/dist/router/channels.d.ts.map +1 -1
  210. package/dist/router/channels.js.map +1 -1
  211. package/dist/router/message-router.d.ts +85 -9
  212. package/dist/router/message-router.d.ts.map +1 -1
  213. package/dist/router/message-router.js +203 -14
  214. package/dist/router/message-router.js.map +1 -1
  215. package/dist/router/role-resolver.d.ts +10 -1
  216. package/dist/router/role-resolver.d.ts.map +1 -1
  217. package/dist/router/role-resolver.js +15 -1
  218. package/dist/router/role-resolver.js.map +1 -1
  219. package/dist/router/types.d.ts +30 -1
  220. package/dist/router/types.d.ts.map +1 -1
  221. package/dist/router/types.js.map +1 -1
  222. package/dist/server/combined-server.d.ts +6 -0
  223. package/dist/server/combined-server.d.ts.map +1 -1
  224. package/dist/server/combined-server.js +24 -2
  225. package/dist/server/combined-server.js.map +1 -1
  226. package/dist/store/event-store.d.ts +14 -1
  227. package/dist/store/event-store.d.ts.map +1 -1
  228. package/dist/store/event-store.js +456 -4
  229. package/dist/store/event-store.js.map +1 -1
  230. package/dist/store/types/agents.d.ts +1 -1
  231. package/dist/store/types/agents.d.ts.map +1 -1
  232. package/dist/store/types/conversations.d.ts +91 -0
  233. package/dist/store/types/conversations.d.ts.map +1 -0
  234. package/dist/store/types/conversations.js +8 -0
  235. package/dist/store/types/conversations.js.map +1 -0
  236. package/dist/store/types/events.d.ts +1 -1
  237. package/dist/store/types/events.d.ts.map +1 -1
  238. package/dist/store/types/events.js.map +1 -1
  239. package/dist/store/types/index.d.ts +2 -0
  240. package/dist/store/types/index.d.ts.map +1 -1
  241. package/dist/store/types/index.js +2 -0
  242. package/dist/store/types/index.js.map +1 -1
  243. package/dist/store/types/sessions.d.ts +44 -0
  244. package/dist/store/types/sessions.d.ts.map +1 -0
  245. package/dist/store/types/sessions.js +9 -0
  246. package/dist/store/types/sessions.js.map +1 -0
  247. package/dist/store/types/tasks.d.ts +2 -0
  248. package/dist/store/types/tasks.d.ts.map +1 -1
  249. package/dist/task/backend/memory.d.ts +4 -1
  250. package/dist/task/backend/memory.d.ts.map +1 -1
  251. package/dist/task/backend/memory.js +81 -0
  252. package/dist/task/backend/memory.js.map +1 -1
  253. package/dist/task/backend/types.d.ts +30 -0
  254. package/dist/task/backend/types.d.ts.map +1 -1
  255. package/dist/task/backend/types.js.map +1 -1
  256. package/dist/teams/index.d.ts +4 -0
  257. package/dist/teams/index.d.ts.map +1 -0
  258. package/dist/teams/index.js +4 -0
  259. package/dist/teams/index.js.map +1 -0
  260. package/dist/teams/team-loader.d.ts +20 -0
  261. package/dist/teams/team-loader.d.ts.map +1 -0
  262. package/dist/teams/team-loader.js +293 -0
  263. package/dist/teams/team-loader.js.map +1 -0
  264. package/dist/teams/team-runtime.d.ts +139 -0
  265. package/dist/teams/team-runtime.d.ts.map +1 -0
  266. package/dist/teams/team-runtime.js +613 -0
  267. package/dist/teams/team-runtime.js.map +1 -0
  268. package/dist/teams/types.d.ts +266 -0
  269. package/dist/teams/types.d.ts.map +1 -0
  270. package/dist/teams/types.js +20 -0
  271. package/dist/teams/types.js.map +1 -0
  272. package/dist/trigger/router/trigger-router.d.ts +30 -3
  273. package/dist/trigger/router/trigger-router.d.ts.map +1 -1
  274. package/dist/trigger/router/trigger-router.js +30 -3
  275. package/dist/trigger/router/trigger-router.js.map +1 -1
  276. package/dist/trigger/wake/types.d.ts +31 -5
  277. package/dist/trigger/wake/types.d.ts.map +1 -1
  278. package/dist/trigger/wake/types.js +19 -0
  279. package/dist/trigger/wake/types.js.map +1 -1
  280. package/dist/workspace/dataplane-adapter.d.ts +1 -1
  281. package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
  282. package/dist/workspace/dataplane-adapter.js +1 -1
  283. package/dist/workspace/dataplane-adapter.js.map +1 -1
  284. package/dist/workspace/index.d.ts +1 -1
  285. package/dist/workspace/index.d.ts.map +1 -1
  286. package/dist/workspace/strategies/index.d.ts +6 -0
  287. package/dist/workspace/strategies/index.d.ts.map +1 -0
  288. package/dist/workspace/strategies/index.js +5 -0
  289. package/dist/workspace/strategies/index.js.map +1 -0
  290. package/dist/workspace/strategies/optimistic.d.ts +26 -0
  291. package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
  292. package/dist/workspace/strategies/optimistic.js +121 -0
  293. package/dist/workspace/strategies/optimistic.js.map +1 -0
  294. package/dist/workspace/strategies/queue.d.ts +26 -0
  295. package/dist/workspace/strategies/queue.d.ts.map +1 -0
  296. package/dist/workspace/strategies/queue.js +67 -0
  297. package/dist/workspace/strategies/queue.js.map +1 -0
  298. package/dist/workspace/strategies/registry.d.ts +37 -0
  299. package/dist/workspace/strategies/registry.d.ts.map +1 -0
  300. package/dist/workspace/strategies/registry.js +63 -0
  301. package/dist/workspace/strategies/registry.js.map +1 -0
  302. package/dist/workspace/strategies/trunk.d.ts +20 -0
  303. package/dist/workspace/strategies/trunk.d.ts.map +1 -0
  304. package/dist/workspace/strategies/trunk.js +108 -0
  305. package/dist/workspace/strategies/trunk.js.map +1 -0
  306. package/dist/workspace/strategies/types.d.ts +104 -0
  307. package/dist/workspace/strategies/types.d.ts.map +1 -0
  308. package/dist/workspace/strategies/types.js +11 -0
  309. package/dist/workspace/strategies/types.js.map +1 -0
  310. package/dist/workspace/types.d.ts +1 -1
  311. package/dist/workspace/types.d.ts.map +1 -1
  312. package/dist/workspace/workspace-manager.d.ts +1 -1
  313. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  314. package/docs/implementation-details.md +1127 -0
  315. package/docs/implementation-summary.md +448 -0
  316. package/docs/mail-integration.md +608 -0
  317. package/docs/plan-self-driving-support.md +433 -0
  318. package/docs/spec-self-driving-support.md +462 -0
  319. package/docs/team-templates.md +860 -0
  320. package/docs/teams.md +233 -0
  321. package/package.json +5 -3
  322. package/src/acp/__tests__/integration.test.ts +161 -1
  323. package/src/acp/__tests__/macro-agent.test.ts +95 -0
  324. package/src/acp/__tests__/session-persistence.test.ts +276 -0
  325. package/src/acp/macro-agent.ts +79 -7
  326. package/src/acp/session-mapper.ts +108 -1
  327. package/src/acp/types.ts +33 -1
  328. package/src/agent/agent-manager.ts +278 -6
  329. package/src/agent/types.ts +27 -0
  330. package/src/agent/wake.ts +15 -0
  331. package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
  332. package/src/agent-detection/__tests__/detector.test.ts +768 -0
  333. package/src/agent-detection/__tests__/registry.test.ts +254 -0
  334. package/src/agent-detection/command-builder.ts +90 -0
  335. package/src/agent-detection/detector.ts +307 -0
  336. package/src/agent-detection/index.ts +36 -0
  337. package/src/agent-detection/registry.ts +200 -0
  338. package/src/agent-detection/types.ts +184 -0
  339. package/src/api/__tests__/conversation-api.test.ts +468 -0
  340. package/src/api/server.ts +425 -1
  341. package/src/api/types.ts +64 -1
  342. package/src/cli/acp.ts +9 -1
  343. package/src/cli/index.ts +44 -0
  344. package/src/cli/mcp.ts +47 -0
  345. package/src/config/index.ts +9 -0
  346. package/src/config/project-config.ts +107 -0
  347. package/src/lifecycle/cascade.ts +1 -1
  348. package/src/lifecycle/handlers/index.ts +8 -0
  349. package/src/lifecycle/handlers/worker.ts +48 -3
  350. package/src/mail/__tests__/conversation-lifecycle.test.ts +409 -0
  351. package/src/mail/__tests__/eventstore-stores.test.ts +1073 -0
  352. package/src/mail/__tests__/mail-full-agent.e2e.test.ts +575 -0
  353. package/src/mail/__tests__/mail-integration.test.ts +759 -0
  354. package/src/mail/__tests__/mail-map-protocol.e2e.test.ts +1068 -0
  355. package/src/mail/__tests__/mail-service.test.ts +506 -0
  356. package/src/mail/__tests__/turn-recorder.test.ts +328 -0
  357. package/src/mail/conversation-map.ts +107 -0
  358. package/src/mail/index.ts +25 -0
  359. package/src/mail/mail-service.ts +257 -0
  360. package/src/mail/stores/eventstore-conversation-store.ts +146 -0
  361. package/src/mail/stores/eventstore-participant-store.ts +172 -0
  362. package/src/mail/stores/eventstore-thread-store.ts +129 -0
  363. package/src/mail/stores/eventstore-turn-store.ts +173 -0
  364. package/src/mail/stores/index.ts +12 -0
  365. package/src/mail/stores/types.ts +160 -0
  366. package/src/mail/turn-recorder.ts +124 -0
  367. package/src/map/README.md +79 -0
  368. package/src/map/adapter/__tests__/extensions.test.ts +359 -0
  369. package/src/map/adapter/__tests__/map-adapter.test.ts +90 -0
  370. package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
  371. package/src/map/adapter/acp-over-map.ts +45 -2
  372. package/src/map/adapter/event-translator.ts +4 -0
  373. package/src/map/adapter/extensions/agent-detection.ts +201 -0
  374. package/src/map/adapter/extensions/index.ts +63 -0
  375. package/src/map/adapter/extensions/resume.ts +114 -0
  376. package/src/map/adapter/extensions/workspace-files.ts +449 -0
  377. package/src/map/adapter/mail-handler-adapter.ts +429 -0
  378. package/src/map/adapter/map-adapter.ts +173 -27
  379. package/src/map/adapter/rpc-handler.ts +8 -1
  380. package/src/map/index.ts +3 -0
  381. package/src/map/types.ts +3 -1
  382. package/src/mcp/mcp-server.ts +67 -0
  383. package/src/mcp/tools/claim_task.ts +86 -0
  384. package/src/mcp/tools/done.ts +59 -10
  385. package/src/mcp/tools/list_claimable_tasks.ts +93 -0
  386. package/src/mcp/tools/unclaim_task.ts +71 -0
  387. package/src/metrics/index.ts +9 -0
  388. package/src/metrics/metrics.ts +280 -0
  389. package/src/roles/capabilities.ts +3 -0
  390. package/src/roles/types.ts +2 -1
  391. package/src/router/README.md +120 -0
  392. package/src/router/__tests__/message-router.test.ts +561 -0
  393. package/src/router/channels.ts +3 -4
  394. package/src/router/message-router.ts +308 -22
  395. package/src/router/role-resolver.ts +22 -1
  396. package/src/router/types.ts +36 -1
  397. package/src/server/combined-server.ts +36 -2
  398. package/src/store/README.md +134 -0
  399. package/src/store/event-store.ts +546 -3
  400. package/src/store/types/agents.ts +1 -1
  401. package/src/store/types/conversations.ts +129 -0
  402. package/src/store/types/events.ts +5 -1
  403. package/src/store/types/index.ts +2 -0
  404. package/src/store/types/sessions.ts +53 -0
  405. package/src/store/types/tasks.ts +3 -0
  406. package/src/task/backend/memory.ts +116 -0
  407. package/src/task/backend/types.ts +43 -0
  408. package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
  409. package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
  410. package/src/teams/__tests__/team-system.test.ts +1280 -0
  411. package/src/teams/index.ts +13 -0
  412. package/src/teams/team-loader.ts +434 -0
  413. package/src/teams/team-runtime.ts +727 -0
  414. package/src/teams/types.ts +377 -0
  415. package/src/trigger/router/trigger-router.ts +30 -3
  416. package/src/trigger/wake/types.ts +32 -5
  417. package/src/trigger/wake/wake-manager.ts +2 -2
  418. package/src/workspace/dataplane-adapter.ts +1 -1
  419. package/src/workspace/index.ts +1 -1
  420. package/src/workspace/strategies/index.ts +18 -0
  421. package/src/workspace/strategies/optimistic.ts +136 -0
  422. package/src/workspace/strategies/queue.ts +81 -0
  423. package/src/workspace/strategies/registry.ts +89 -0
  424. package/src/workspace/strategies/trunk.ts +123 -0
  425. package/src/workspace/strategies/types.ts +145 -0
  426. package/src/workspace/types.ts +1 -1
  427. package/src/workspace/workspace-manager.ts +1 -1
  428. package/.claude/settings.local.json +0 -59
  429. package/dist/map/utils/address-translation.d.ts +0 -99
  430. package/dist/map/utils/address-translation.d.ts.map +0 -1
  431. package/dist/map/utils/address-translation.js +0 -285
  432. package/dist/map/utils/address-translation.js.map +0 -1
  433. package/dist/map/utils/index.d.ts +0 -7
  434. package/dist/map/utils/index.d.ts.map +0 -1
  435. package/dist/map/utils/index.js +0 -7
  436. package/dist/map/utils/index.js.map +0 -1
  437. package/openspec/AGENTS.md +0 -456
  438. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/design.md +0 -128
  439. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/proposal.md +0 -49
  440. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/agent-manager/spec.md +0 -150
  441. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/cli-api/spec.md +0 -258
  442. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/event-store/spec.md +0 -160
  443. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/mcp-tools/spec.md +0 -224
  444. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/message-router/spec.md +0 -153
  445. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/task-manager/spec.md +0 -136
  446. package/openspec/changes/archive/2025-12-21-add-mvp-foundation/tasks.md +0 -147
  447. package/openspec/project.md +0 -31
  448. package/openspec/specs/agent-manager/spec.md +0 -154
  449. package/openspec/specs/cli-api/spec.md +0 -262
  450. package/openspec/specs/event-store/spec.md +0 -164
  451. package/openspec/specs/mcp-tools/spec.md +0 -228
  452. package/openspec/specs/message-router/spec.md +0 -157
  453. package/openspec/specs/task-manager/spec.md +0 -140
  454. package/references/acp-factory-ref/CHANGELOG.md +0 -33
  455. package/references/acp-factory-ref/LICENSE +0 -21
  456. package/references/acp-factory-ref/README.md +0 -341
  457. package/references/acp-factory-ref/package-lock.json +0 -3102
  458. package/references/acp-factory-ref/package.json +0 -96
  459. package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
  460. package/references/acp-factory-ref/python/LICENSE +0 -21
  461. package/references/acp-factory-ref/python/Makefile +0 -57
  462. package/references/acp-factory-ref/python/README.md +0 -253
  463. package/references/acp-factory-ref/python/pyproject.toml +0 -73
  464. package/references/acp-factory-ref/python/tests/__init__.py +0 -0
  465. package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
  466. package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
  467. package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
  468. package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
  469. package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
  470. package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
  471. package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
  472. package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
  473. package/references/claude-code-acp/.prettierrc.json +0 -4
  474. package/references/claude-code-acp/CHANGELOG.md +0 -249
  475. package/references/claude-code-acp/LICENSE +0 -222
  476. package/references/claude-code-acp/README.md +0 -53
  477. package/references/claude-code-acp/docs/RELEASES.md +0 -24
  478. package/references/claude-code-acp/eslint.config.js +0 -48
  479. package/references/claude-code-acp/package-lock.json +0 -4570
  480. package/references/claude-code-acp/package.json +0 -88
  481. package/references/claude-code-acp/scripts/release.sh +0 -119
  482. package/references/claude-code-acp/src/acp-agent.ts +0 -2065
  483. package/references/claude-code-acp/src/index.ts +0 -26
  484. package/references/claude-code-acp/src/lib.ts +0 -38
  485. package/references/claude-code-acp/src/mcp-server.ts +0 -911
  486. package/references/claude-code-acp/src/settings.ts +0 -522
  487. package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
  488. package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
  489. package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
  490. package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
  491. package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
  492. package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
  493. package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
  494. package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
  495. package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
  496. package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
  497. package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
  498. package/references/claude-code-acp/src/tools.ts +0 -819
  499. package/references/claude-code-acp/src/utils.ts +0 -171
  500. package/references/claude-code-acp/tsconfig.json +0 -18
  501. package/references/claude-code-acp/vitest.config.ts +0 -19
  502. package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -82
  503. package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -9
  504. package/references/multi-agent-protocol/LICENSE +0 -21
  505. package/references/multi-agent-protocol/README.md +0 -113
  506. package/references/multi-agent-protocol/docs/00-design-specification.md +0 -460
  507. package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
  508. package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
  509. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
  510. package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
  511. package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
  512. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
  513. package/references/multi-agent-protocol/docs/07-federation.md +0 -259
  514. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
  515. package/references/multi-agent-protocol/package-lock.json +0 -3239
  516. package/references/multi-agent-protocol/package.json +0 -56
  517. package/references/multi-agent-protocol/schema/meta.json +0 -337
  518. package/references/multi-agent-protocol/schema/schema.json +0 -1828
@@ -1,911 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import {
3
- BashInput,
4
- FileEditInput,
5
- FileReadInput,
6
- FileWriteInput,
7
- TaskOutputInput,
8
- } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
9
- import { z } from "zod";
10
- import { CLAUDE_CONFIG_DIR, ClaudeAcpAgent } from "./acp-agent.js";
11
- import {
12
- ClientCapabilities,
13
- ReadTextFileResponse,
14
- TerminalOutputResponse,
15
- } from "@agentclientprotocol/sdk";
16
- import * as diff from "diff";
17
- import * as path from "node:path";
18
- import * as fs from "node:fs/promises";
19
-
20
- import { sleep, unreachable, extractLinesWithByteLimit } from "./utils.js";
21
- import { acpToolNames } from "./tools.js";
22
-
23
- export const SYSTEM_REMINDER = `
24
-
25
- <system-reminder>
26
- Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.
27
- </system-reminder>`;
28
-
29
- const defaults = { maxFileSize: 50000, linesToRead: 2000 };
30
-
31
- function formatErrorMessage(error: unknown): string {
32
- if (error instanceof Error) {
33
- return error.message;
34
- }
35
- if (typeof error === "string") {
36
- return error;
37
- }
38
- try {
39
- return JSON.stringify(error);
40
- } catch {
41
- return String(error);
42
- }
43
- }
44
-
45
- const unqualifiedToolNames = {
46
- read: "Read",
47
- edit: "Edit",
48
- write: "Write",
49
- bash: "Bash",
50
- killShell: "KillShell",
51
- bashOutput: "BashOutput",
52
- };
53
-
54
- export function createMcpServer(
55
- agent: ClaudeAcpAgent,
56
- sessionId: string,
57
- clientCapabilities: ClientCapabilities | undefined,
58
- ): McpServer {
59
- /**
60
- * This checks if a given path is related to internal agent persistence and if the agent should be allowed to read/write from here.
61
- * We let the agent do normal fs operations on these paths so that it can persist its state.
62
- * However, we block access to settings files for security reasons.
63
- */
64
- function internalPath(file_path: string) {
65
- return (
66
- file_path.startsWith(CLAUDE_CONFIG_DIR) &&
67
- !file_path.startsWith(path.join(CLAUDE_CONFIG_DIR, "settings.json")) &&
68
- !file_path.startsWith(path.join(CLAUDE_CONFIG_DIR, "session-env"))
69
- );
70
- }
71
-
72
- async function readTextFile(input: FileReadInput): Promise<ReadTextFileResponse> {
73
- if (internalPath(input.file_path)) {
74
- const content = await fs.readFile(input.file_path, "utf8");
75
-
76
- // eslint-disable-next-line eqeqeq
77
- if (input.offset != null || input.limit != null) {
78
- const lines = content.split("\n");
79
-
80
- // Apply offset and limit if provided
81
- const offset = input.offset ?? 1;
82
- const limit = input.limit ?? lines.length;
83
-
84
- // Extract the requested lines (offset is 1-based)
85
- const startIndex = Math.max(0, offset - 1);
86
- const endIndex = Math.min(lines.length, startIndex + limit);
87
- const selectedLines = lines.slice(startIndex, endIndex);
88
-
89
- return { content: selectedLines.join("\n") };
90
- } else {
91
- return { content };
92
- }
93
- }
94
-
95
- return agent.readTextFile({
96
- sessionId,
97
- path: input.file_path,
98
- line: input.offset,
99
- limit: input.limit,
100
- });
101
- }
102
-
103
- async function writeTextFile(input: FileWriteInput): Promise<void> {
104
- if (internalPath(input.file_path)) {
105
- await fs.writeFile(input.file_path, input.content, "utf8");
106
- } else {
107
- await agent.writeTextFile({
108
- sessionId,
109
- path: input.file_path,
110
- content: input.content,
111
- });
112
- }
113
- }
114
-
115
- // Create MCP server
116
- const server = new McpServer({ name: "acp", version: "1.0.0" }, { capabilities: { tools: {} } });
117
-
118
- if (clientCapabilities?.fs?.readTextFile) {
119
- server.registerTool(
120
- unqualifiedToolNames.read,
121
- {
122
- title: unqualifiedToolNames.read,
123
- description: `Reads the content of the given file in the project.
124
-
125
- In sessions with ${acpToolNames.read} always use it instead of Read as it contains the most up-to-date contents.
126
-
127
- Reads a file from the local filesystem. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
128
-
129
- Usage:
130
- - The file_path parameter must be an absolute path, not a relative path
131
- - By default, it reads up to ${defaults.linesToRead} lines starting from the beginning of the file
132
- - You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters
133
- - Any files larger than ${defaults.maxFileSize} bytes will be truncated
134
- - This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.
135
- - This tool can only read files, not directories. To read a directory, use an ls command via the ${acpToolNames.bash} tool.
136
- - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.`,
137
- inputSchema: {
138
- file_path: z.string().describe("The absolute path to the file to read"),
139
- offset: z
140
- .number()
141
- .optional()
142
- .default(1)
143
- .describe(
144
- "The line number to start reading from. Only provide if the file is too large to read at once",
145
- ),
146
- limit: z
147
- .number()
148
- .optional()
149
- .default(defaults.linesToRead)
150
- .describe(
151
- `The number of lines to read. Only provide if the file is too large to read at once.`,
152
- ),
153
- },
154
- annotations: {
155
- title: "Read file",
156
- readOnlyHint: true,
157
- destructiveHint: false,
158
- openWorldHint: false,
159
- idempotentHint: false,
160
- },
161
- },
162
- async (input: FileReadInput) => {
163
- try {
164
- const session = agent.sessions[sessionId];
165
- if (!session) {
166
- return {
167
- content: [
168
- {
169
- type: "text",
170
- text: "The user has left the building",
171
- },
172
- ],
173
- };
174
- }
175
-
176
- const readResponse = await readTextFile(input);
177
-
178
- if (typeof readResponse?.content !== "string") {
179
- throw new Error(`No file contents for ${input.file_path}.`);
180
- }
181
-
182
- // Extract lines with byte limit enforcement
183
- const result = extractLinesWithByteLimit(readResponse.content, defaults.maxFileSize);
184
-
185
- // Construct informative message about what was read
186
- let readInfo = "";
187
- if ((input.offset && input.offset > 1) || result.wasLimited) {
188
- readInfo = "\n\n<file-read-info>";
189
-
190
- if (result.wasLimited) {
191
- readInfo += `Read ${result.linesRead} lines (hit 50KB limit). `;
192
- } else if (input.offset && input.offset > 1) {
193
- readInfo += `Read lines ${input.offset}-${input.offset + result.linesRead}.`;
194
- }
195
-
196
- if (result.wasLimited) {
197
- readInfo += `Continue with offset=${result.linesRead}.`;
198
- }
199
-
200
- readInfo += "</file-read-info>";
201
- }
202
-
203
- return {
204
- content: [
205
- {
206
- type: "text",
207
- text: result.content + readInfo + SYSTEM_REMINDER,
208
- },
209
- ],
210
- };
211
- } catch (error) {
212
- return {
213
- isError: true,
214
- content: [
215
- {
216
- type: "text",
217
- text: "Reading file failed: " + formatErrorMessage(error),
218
- },
219
- ],
220
- };
221
- }
222
- },
223
- );
224
- }
225
-
226
- if (clientCapabilities?.fs?.writeTextFile) {
227
- server.registerTool(
228
- unqualifiedToolNames.write,
229
- {
230
- title: unqualifiedToolNames.write,
231
- description: `Writes a file to the local filesystem..
232
-
233
- In sessions with ${acpToolNames.write} always use it instead of Write as it will
234
- allow the user to conveniently review changes.
235
-
236
- Usage:
237
- - This tool will overwrite the existing file if there is one at the provided path.
238
- - If this is an existing file, you MUST use the ${acpToolNames.read} tool first to read the file's contents. This tool will fail if you did not read the file first.
239
- - ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
240
- - NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
241
- - Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`,
242
- inputSchema: {
243
- file_path: z
244
- .string()
245
- .describe("The absolute path to the file to write (must be absolute, not relative)"),
246
- content: z.string().describe("The content to write to the file"),
247
- },
248
- annotations: {
249
- title: "Write file",
250
- readOnlyHint: false,
251
- destructiveHint: false,
252
- openWorldHint: false,
253
- idempotentHint: false,
254
- },
255
- },
256
- async (input: FileWriteInput) => {
257
- try {
258
- const session = agent.sessions[sessionId];
259
- if (!session) {
260
- return {
261
- content: [
262
- {
263
- type: "text",
264
- text: "The user has left the building",
265
- },
266
- ],
267
- };
268
- }
269
- await writeTextFile(input);
270
-
271
- return {
272
- content: [
273
- {
274
- type: "text",
275
- text: `The file ${input.file_path} has been updated successfully.`,
276
- },
277
- ],
278
- };
279
- } catch (error) {
280
- return {
281
- isError: true,
282
- content: [
283
- {
284
- type: "text",
285
- text: "Writing file failed: " + formatErrorMessage(error),
286
- },
287
- ],
288
- };
289
- }
290
- },
291
- );
292
-
293
- server.registerTool(
294
- unqualifiedToolNames.edit,
295
- {
296
- title: unqualifiedToolNames.edit,
297
- description: `Performs exact string replacements in files.
298
-
299
- In sessions with ${acpToolNames.edit} always use it instead of Edit as it will
300
- allow the user to conveniently review changes.
301
-
302
- Usage:
303
- - You must use your \`${acpToolNames.read}\` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
304
- - When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears.
305
- - ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
306
- - Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
307
- - The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`.
308
- - Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`,
309
- inputSchema: {
310
- file_path: z.string().describe("The absolute path to the file to modify"),
311
- old_string: z.string().describe("The text to replace"),
312
- new_string: z
313
- .string()
314
- .describe("The text to replace it with (must be different from old_string)"),
315
- replace_all: z
316
- .boolean()
317
- .default(false)
318
- .optional()
319
- .describe("Replace all occurrences of old_string (default false)"),
320
- },
321
- annotations: {
322
- title: "Edit file",
323
- readOnlyHint: false,
324
- destructiveHint: false,
325
- openWorldHint: false,
326
- idempotentHint: false,
327
- },
328
- },
329
- async (input: FileEditInput) => {
330
- try {
331
- const session = agent.sessions[sessionId];
332
- if (!session) {
333
- return {
334
- content: [
335
- {
336
- type: "text",
337
- text: "The user has left the building",
338
- },
339
- ],
340
- };
341
- }
342
-
343
- const readResponse = await readTextFile({
344
- file_path: input.file_path,
345
- });
346
-
347
- if (typeof readResponse?.content !== "string") {
348
- throw new Error(`No file contents for ${input.file_path}.`);
349
- }
350
-
351
- const { newContent } = replaceAndCalculateLocation(readResponse.content, [
352
- {
353
- oldText: input.old_string,
354
- newText: input.new_string,
355
- replaceAll: input.replace_all,
356
- },
357
- ]);
358
-
359
- const patch = diff.createPatch(input.file_path, readResponse.content, newContent);
360
-
361
- await writeTextFile({ file_path: input.file_path, content: newContent });
362
-
363
- return {
364
- content: [
365
- {
366
- type: "text",
367
- text: patch,
368
- },
369
- ],
370
- };
371
- } catch (error) {
372
- return {
373
- isError: true,
374
- content: [
375
- {
376
- type: "text",
377
- text: "Editing file failed: " + formatErrorMessage(error),
378
- },
379
- ],
380
- };
381
- }
382
- },
383
- );
384
- }
385
-
386
- if (agent.clientCapabilities?.terminal) {
387
- server.registerTool(
388
- unqualifiedToolNames.bash,
389
- {
390
- title: unqualifiedToolNames.bash,
391
- description: `Executes a bash command
392
-
393
- In sessions with ${acpToolNames.bash} always use it instead of Bash`,
394
- inputSchema: {
395
- command: z.string().describe("The command to execute"),
396
- timeout: z.number().describe(`Optional timeout in milliseconds (max ${2 * 60 * 1000})`),
397
- description: z.string().optional()
398
- .describe(`Clear, concise description of what this command does in 5-10 words, in active voice. Examples:
399
- Input: ls
400
- Output: List files in current directory
401
-
402
- Input: git status
403
- Output: Show working tree status
404
-
405
- Input: npm install
406
- Output: Install package dependencies
407
-
408
- Input: mkdir foo
409
- Output: Create directory 'foo'`),
410
- run_in_background: z
411
- .boolean()
412
- .default(false)
413
- .describe(
414
- `Set to true to run this command in the background. The tool returns an \`id\` that can be used with the \`${acpToolNames.bashOutput}\` tool to retrieve the current output, or the \`${acpToolNames.killShell}\` tool to stop it early.`,
415
- ),
416
- },
417
- },
418
- async (input: BashInput, extra) => {
419
- try {
420
- const session = agent.sessions[sessionId];
421
- if (!session) {
422
- return {
423
- content: [
424
- {
425
- type: "text",
426
- text: "The user has left the building",
427
- },
428
- ],
429
- };
430
- }
431
-
432
- const toolCallId = extra._meta?.["claudecode/toolUseId"];
433
-
434
- if (typeof toolCallId !== "string") {
435
- throw new Error("No tool call ID found");
436
- }
437
-
438
- if (!agent.clientCapabilities?.terminal || !agent.client.createTerminal) {
439
- throw new Error("unreachable");
440
- }
441
-
442
- const handle = await agent.client.createTerminal({
443
- command: input.command,
444
- env: [{ name: "CLAUDECODE", value: "1" }],
445
- sessionId,
446
- outputByteLimit: 32_000,
447
- });
448
-
449
- await agent.client.sessionUpdate({
450
- sessionId,
451
- update: {
452
- sessionUpdate: "tool_call_update",
453
- toolCallId,
454
- status: "in_progress",
455
- title: input.description,
456
- content: [{ type: "terminal", terminalId: handle.id }],
457
- },
458
- });
459
-
460
- const abortPromise = new Promise((resolve) => {
461
- if (extra.signal.aborted) {
462
- resolve(null);
463
- } else {
464
- extra.signal.addEventListener("abort", () => {
465
- resolve(null);
466
- });
467
- }
468
- });
469
-
470
- const statusPromise = Promise.race([
471
- handle.waitForExit().then((exitStatus) => ({ status: "exited" as const, exitStatus })),
472
- abortPromise.then(() => ({ status: "aborted" as const, exitStatus: null })),
473
- sleep(input.timeout ?? 2 * 60 * 1000).then(async () => {
474
- if (agent.backgroundTerminals[handle.id]?.status === "started") {
475
- await handle.kill();
476
- }
477
- return { status: "timedOut" as const, exitStatus: null };
478
- }),
479
- ]);
480
-
481
- if (input.run_in_background) {
482
- agent.backgroundTerminals[handle.id] = {
483
- handle,
484
- lastOutput: null,
485
- status: "started",
486
- };
487
-
488
- statusPromise.then(async ({ status, exitStatus }) => {
489
- const bgTerm = agent.backgroundTerminals[handle.id];
490
-
491
- if (bgTerm.status !== "started") {
492
- return;
493
- }
494
-
495
- const currentOutput = await handle.currentOutput();
496
-
497
- agent.backgroundTerminals[handle.id] = {
498
- status,
499
- pendingOutput: {
500
- ...currentOutput,
501
- output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
502
- exitStatus: exitStatus ?? currentOutput.exitStatus,
503
- },
504
- };
505
-
506
- return handle.release();
507
- });
508
-
509
- return {
510
- content: [
511
- {
512
- type: "text",
513
- text: `Command started in background with id: ${handle.id}`,
514
- },
515
- ],
516
- };
517
- }
518
-
519
- await using terminal = handle;
520
-
521
- const { status } = await statusPromise;
522
-
523
- if (status === "aborted") {
524
- return {
525
- content: [{ type: "text", text: "Tool cancelled by user" }],
526
- };
527
- }
528
-
529
- const output = await terminal.currentOutput();
530
-
531
- return {
532
- content: [{ type: "text", text: toolCommandOutput(status, output) }],
533
- };
534
- } catch (error) {
535
- return {
536
- isError: true,
537
- content: [
538
- {
539
- type: "text",
540
- text: "Running bash command failed: " + formatErrorMessage(error),
541
- },
542
- ],
543
- };
544
- }
545
- },
546
- );
547
-
548
- server.registerTool(
549
- unqualifiedToolNames.bashOutput,
550
- {
551
- title: unqualifiedToolNames.bashOutput,
552
- description: `- Retrieves output from a running or completed background bash shell
553
- - Takes a bash_id parameter identifying the shell
554
- - Always returns only new output since the last check
555
- - Returns stdout and stderr output along with shell status
556
- - Use this tool when you need to monitor or check the output of a long-running shell
557
-
558
- In sessions with ${acpToolNames.bashOutput} always use it for output from Bash commands instead of TaskOutput.`,
559
- inputSchema: {
560
- task_id: z
561
- .string()
562
- .describe(
563
- `The id of the background bash command as returned by \`${acpToolNames.bash}\``,
564
- ),
565
- block: z.boolean().describe("Whether to wait for completion"),
566
- timeout: z.number().describe("Max wait time in ms"),
567
- },
568
- },
569
- async (input: TaskOutputInput) => {
570
- try {
571
- const bgTerm = agent.backgroundTerminals[input.task_id];
572
-
573
- if (!bgTerm) {
574
- throw new Error(`Unknown shell ${input.task_id}`);
575
- }
576
-
577
- if (input.block && bgTerm.status === "started") {
578
- const statusPromise = Promise.race([
579
- bgTerm.handle
580
- .waitForExit()
581
- .then((exitStatus) => ({ status: "exited" as const, exitStatus })),
582
- sleep(input.timeout ?? 2 * 60 * 1000).then(async () => {
583
- if (bgTerm.status === "started") {
584
- await bgTerm.handle.kill();
585
- }
586
- return { status: "timedOut" as const, exitStatus: null };
587
- }),
588
- ]);
589
-
590
- const { status, exitStatus } = await statusPromise;
591
- const currentOutput = await bgTerm.handle.currentOutput();
592
- const strippedOutput = stripCommonPrefix(
593
- bgTerm.lastOutput?.output ?? "",
594
- currentOutput.output,
595
- );
596
-
597
- agent.backgroundTerminals[input.task_id] = {
598
- status,
599
- pendingOutput: {
600
- ...currentOutput,
601
- output: strippedOutput,
602
- exitStatus: exitStatus ?? currentOutput.exitStatus,
603
- },
604
- };
605
-
606
- await bgTerm.handle.release();
607
-
608
- return {
609
- content: [
610
- {
611
- type: "text",
612
- text: toolCommandOutput(status, {
613
- ...currentOutput,
614
- output: strippedOutput,
615
- exitStatus: exitStatus ?? currentOutput.exitStatus,
616
- }),
617
- },
618
- ],
619
- };
620
- }
621
-
622
- if (bgTerm.status === "started") {
623
- const newOutput = await bgTerm.handle.currentOutput();
624
- const strippedOutput = stripCommonPrefix(
625
- bgTerm.lastOutput?.output ?? "",
626
- newOutput.output,
627
- );
628
- bgTerm.lastOutput = newOutput;
629
-
630
- return {
631
- content: [
632
- {
633
- type: "text",
634
- text: toolCommandOutput(bgTerm.status, {
635
- ...newOutput,
636
- output: strippedOutput,
637
- }),
638
- },
639
- ],
640
- };
641
- } else {
642
- return {
643
- content: [
644
- {
645
- type: "text",
646
- text: toolCommandOutput(bgTerm.status, bgTerm.pendingOutput),
647
- },
648
- ],
649
- };
650
- }
651
- } catch (error) {
652
- return {
653
- isError: true,
654
- content: [
655
- {
656
- type: "text",
657
- text: "Retrieving bash output failed: " + formatErrorMessage(error),
658
- },
659
- ],
660
- };
661
- }
662
- },
663
- );
664
-
665
- server.registerTool(
666
- unqualifiedToolNames.killShell,
667
- {
668
- title: unqualifiedToolNames.killShell,
669
- description: `- Kills a running background bash shell by its ID
670
- - Takes a shell_id parameter identifying the shell to kill
671
- - Returns a success or failure status
672
- - Use this tool when you need to terminate a long-running shell
673
-
674
- In sessions with ${acpToolNames.killShell} always use it instead of KillShell.`,
675
- inputSchema: {
676
- shell_id: z
677
- .string()
678
- .describe(
679
- `The id of the background bash command as returned by \`${acpToolNames.bash}\``,
680
- ),
681
- },
682
- },
683
- async (input) => {
684
- try {
685
- const bgTerm = agent.backgroundTerminals[input.shell_id];
686
-
687
- if (!bgTerm) {
688
- throw new Error(`Unknown shell ${input.shell_id}`);
689
- }
690
-
691
- switch (bgTerm.status) {
692
- case "started": {
693
- await bgTerm.handle.kill();
694
- const currentOutput = await bgTerm.handle.currentOutput();
695
- agent.backgroundTerminals[bgTerm.handle.id] = {
696
- status: "killed",
697
- pendingOutput: {
698
- ...currentOutput,
699
- output: stripCommonPrefix(bgTerm.lastOutput?.output ?? "", currentOutput.output),
700
- },
701
- };
702
- await bgTerm.handle.release();
703
-
704
- return {
705
- content: [{ type: "text", text: "Command killed successfully." }],
706
- };
707
- }
708
- case "aborted":
709
- return {
710
- content: [{ type: "text", text: "Command aborted by user." }],
711
- };
712
- case "exited":
713
- return {
714
- content: [{ type: "text", text: "Command had already exited." }],
715
- };
716
- case "killed":
717
- return {
718
- content: [{ type: "text", text: "Command was already killed." }],
719
- };
720
- case "timedOut":
721
- return {
722
- content: [{ type: "text", text: "Command killed by timeout." }],
723
- };
724
- default: {
725
- unreachable(bgTerm);
726
- throw new Error("Unexpected background terminal status");
727
- }
728
- }
729
- } catch (error) {
730
- return {
731
- isError: true,
732
- content: [
733
- {
734
- type: "text",
735
- text: "Killing shell failed: " + formatErrorMessage(error),
736
- },
737
- ],
738
- };
739
- }
740
- },
741
- );
742
- }
743
-
744
- return server;
745
- }
746
-
747
- function stripCommonPrefix(a: string, b: string): string {
748
- let i = 0;
749
- while (i < a.length && i < b.length && a[i] === b[i]) {
750
- i++;
751
- }
752
- return b.slice(i);
753
- }
754
-
755
- function toolCommandOutput(
756
- status: "started" | "aborted" | "exited" | "killed" | "timedOut",
757
- output: TerminalOutputResponse,
758
- ): string {
759
- const { exitStatus, output: commandOutput, truncated } = output;
760
-
761
- let toolOutput = "";
762
-
763
- switch (status) {
764
- case "started":
765
- case "exited": {
766
- if (exitStatus && (exitStatus.exitCode ?? null) === null) {
767
- toolOutput += `Interrupted by the user. `;
768
- }
769
- break;
770
- }
771
- case "killed":
772
- toolOutput += `Killed. `;
773
- break;
774
- case "timedOut":
775
- toolOutput += `Timed out. `;
776
- break;
777
- case "aborted":
778
- break;
779
- default: {
780
- const unreachable: never = status;
781
- return unreachable;
782
- }
783
- }
784
-
785
- if (exitStatus) {
786
- if (typeof exitStatus.exitCode === "number") {
787
- toolOutput += `Exited with code ${exitStatus.exitCode}.`;
788
- }
789
-
790
- if (typeof exitStatus.signal === "string") {
791
- toolOutput += `Signal \`${exitStatus.signal}\`. `;
792
- }
793
-
794
- toolOutput += "Final output:\n\n";
795
- } else {
796
- toolOutput += "New output:\n\n";
797
- }
798
-
799
- toolOutput += commandOutput;
800
-
801
- if (truncated) {
802
- toolOutput += `\n\nCommand output was too long, so it was truncated to ${commandOutput.length} bytes.`;
803
- }
804
-
805
- return toolOutput;
806
- }
807
-
808
- /**
809
- * Replace text in a file and calculate the line numbers where the edits occurred.
810
- *
811
- * @param fileContent - The full file content
812
- * @param edits - Array of edit operations to apply sequentially
813
- * @returns the new content and the line numbers where replacements occurred in the final content
814
- */
815
- export function replaceAndCalculateLocation(
816
- fileContent: string,
817
- edits: Array<{
818
- oldText: string;
819
- newText: string;
820
- replaceAll?: boolean;
821
- }>,
822
- ): { newContent: string; lineNumbers: number[] } {
823
- let currentContent = fileContent;
824
-
825
- // Use unique markers to track where replacements happen
826
- const markerPrefix = `__REPLACE_MARKER_${Math.random().toString(36).substr(2, 9)}_`;
827
- let markerCounter = 0;
828
- const markers: string[] = [];
829
-
830
- // Apply edits sequentially, inserting markers at replacement positions
831
- for (const edit of edits) {
832
- // Skip empty oldText
833
- if (edit.oldText === "") {
834
- throw new Error(`The provided \`old_string\` is empty.\n\nNo edits were applied.`);
835
- }
836
-
837
- if (edit.replaceAll) {
838
- // Replace all occurrences with marker + newText
839
- const parts: string[] = [];
840
- let lastIndex = 0;
841
- let searchIndex = 0;
842
-
843
- while (true) {
844
- const index = currentContent.indexOf(edit.oldText, searchIndex);
845
- if (index === -1) {
846
- if (searchIndex === 0) {
847
- throw new Error(
848
- `The provided \`old_string\` does not appear in the file: "${edit.oldText}".\n\nNo edits were applied.`,
849
- );
850
- }
851
- break;
852
- }
853
-
854
- // Add content before the match
855
- parts.push(currentContent.substring(lastIndex, index));
856
-
857
- // Add marker and replacement
858
- const marker = `${markerPrefix}${markerCounter++}__`;
859
- markers.push(marker);
860
- parts.push(marker + edit.newText);
861
-
862
- lastIndex = index + edit.oldText.length;
863
- searchIndex = lastIndex;
864
- }
865
-
866
- // Add remaining content
867
- parts.push(currentContent.substring(lastIndex));
868
- currentContent = parts.join("");
869
- } else {
870
- // Replace first occurrence only
871
- const index = currentContent.indexOf(edit.oldText);
872
- if (index === -1) {
873
- throw new Error(
874
- `The provided \`old_string\` does not appear in the file: "${edit.oldText}".\n\nNo edits were applied.`,
875
- );
876
- } else {
877
- const marker = `${markerPrefix}${markerCounter++}__`;
878
- markers.push(marker);
879
- currentContent =
880
- currentContent.substring(0, index) +
881
- marker +
882
- edit.newText +
883
- currentContent.substring(index + edit.oldText.length);
884
- }
885
- }
886
- }
887
-
888
- // Find line numbers where markers appear in the content
889
- const lineNumbers: number[] = [];
890
- for (const marker of markers) {
891
- const index = currentContent.indexOf(marker);
892
- if (index !== -1) {
893
- const lineNumber = Math.max(
894
- 0,
895
- currentContent.substring(0, index).split(/\r\n|\r|\n/).length - 1,
896
- );
897
- lineNumbers.push(lineNumber);
898
- }
899
- }
900
-
901
- // Remove all markers from the final content
902
- let finalContent = currentContent;
903
- for (const marker of markers) {
904
- finalContent = finalContent.replace(marker, "");
905
- }
906
-
907
- // Dedupe and sort line numbers
908
- const uniqueLineNumbers = [...new Set(lineNumbers)].sort();
909
-
910
- return { newContent: finalContent, lineNumbers: uniqueLineNumbers };
911
- }