macro-agent 0.0.11 → 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 (408) 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 +6 -0
  16. package/.sudocode/specs.jsonl +7 -0
  17. package/CLAUDE.md +110 -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 +25 -1
  31. package/dist/agent/agent-manager.d.ts.map +1 -1
  32. package/dist/agent/agent-manager.js +93 -7
  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-detection/command-builder.d.ts +30 -0
  38. package/dist/agent-detection/command-builder.d.ts.map +1 -0
  39. package/dist/agent-detection/command-builder.js +71 -0
  40. package/dist/agent-detection/command-builder.js.map +1 -0
  41. package/dist/agent-detection/detector.d.ts +84 -0
  42. package/dist/agent-detection/detector.d.ts.map +1 -0
  43. package/dist/agent-detection/detector.js +240 -0
  44. package/dist/agent-detection/detector.js.map +1 -0
  45. package/dist/agent-detection/index.d.ts +12 -0
  46. package/dist/agent-detection/index.d.ts.map +1 -0
  47. package/dist/agent-detection/index.js +14 -0
  48. package/dist/agent-detection/index.js.map +1 -0
  49. package/dist/agent-detection/registry.d.ts +53 -0
  50. package/dist/agent-detection/registry.d.ts.map +1 -0
  51. package/dist/agent-detection/registry.js +177 -0
  52. package/dist/agent-detection/registry.js.map +1 -0
  53. package/dist/agent-detection/types.d.ts +121 -0
  54. package/dist/agent-detection/types.d.ts.map +1 -0
  55. package/dist/agent-detection/types.js +20 -0
  56. package/dist/agent-detection/types.js.map +1 -0
  57. package/dist/api/server.d.ts.map +1 -1
  58. package/dist/api/server.js +95 -0
  59. package/dist/api/server.js.map +1 -1
  60. package/dist/cli/index.js +29 -0
  61. package/dist/cli/index.js.map +1 -1
  62. package/dist/cli/mcp.js +38 -0
  63. package/dist/cli/mcp.js.map +1 -1
  64. package/dist/config/index.d.ts +2 -0
  65. package/dist/config/index.d.ts.map +1 -0
  66. package/dist/config/index.js +2 -0
  67. package/dist/config/index.js.map +1 -0
  68. package/dist/config/project-config.d.ts +46 -0
  69. package/dist/config/project-config.d.ts.map +1 -0
  70. package/dist/config/project-config.js +68 -0
  71. package/dist/config/project-config.js.map +1 -0
  72. package/dist/lifecycle/cascade.d.ts +1 -1
  73. package/dist/lifecycle/cascade.d.ts.map +1 -1
  74. package/dist/lifecycle/handlers/index.d.ts +4 -0
  75. package/dist/lifecycle/handlers/index.d.ts.map +1 -1
  76. package/dist/lifecycle/handlers/index.js +2 -0
  77. package/dist/lifecycle/handlers/index.js.map +1 -1
  78. package/dist/lifecycle/handlers/worker.d.ts +4 -0
  79. package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
  80. package/dist/lifecycle/handlers/worker.js +35 -3
  81. package/dist/lifecycle/handlers/worker.js.map +1 -1
  82. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  83. package/dist/map/adapter/acp-over-map.js +32 -2
  84. package/dist/map/adapter/acp-over-map.js.map +1 -1
  85. package/dist/map/adapter/event-translator.d.ts.map +1 -1
  86. package/dist/map/adapter/event-translator.js +1 -0
  87. package/dist/map/adapter/event-translator.js.map +1 -1
  88. package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
  89. package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
  90. package/dist/map/adapter/extensions/agent-detection.js +91 -0
  91. package/dist/map/adapter/extensions/agent-detection.js.map +1 -0
  92. package/dist/map/adapter/extensions/index.d.ts +10 -1
  93. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  94. package/dist/map/adapter/extensions/index.js +39 -0
  95. package/dist/map/adapter/extensions/index.js.map +1 -1
  96. package/dist/map/adapter/extensions/resume.d.ts +47 -0
  97. package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
  98. package/dist/map/adapter/extensions/resume.js +59 -0
  99. package/dist/map/adapter/extensions/resume.js.map +1 -0
  100. package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
  101. package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
  102. package/dist/map/adapter/extensions/workspace-files.js +338 -0
  103. package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
  104. package/dist/mcp/mcp-server.d.ts +6 -0
  105. package/dist/mcp/mcp-server.d.ts.map +1 -1
  106. package/dist/mcp/mcp-server.js +45 -0
  107. package/dist/mcp/mcp-server.js.map +1 -1
  108. package/dist/mcp/tools/claim_task.d.ts +35 -0
  109. package/dist/mcp/tools/claim_task.d.ts.map +1 -0
  110. package/dist/mcp/tools/claim_task.js +58 -0
  111. package/dist/mcp/tools/claim_task.js.map +1 -0
  112. package/dist/mcp/tools/done.d.ts +11 -2
  113. package/dist/mcp/tools/done.d.ts.map +1 -1
  114. package/dist/mcp/tools/done.js +15 -10
  115. package/dist/mcp/tools/done.js.map +1 -1
  116. package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
  117. package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
  118. package/dist/mcp/tools/list_claimable_tasks.js +63 -0
  119. package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
  120. package/dist/mcp/tools/unclaim_task.d.ts +31 -0
  121. package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
  122. package/dist/mcp/tools/unclaim_task.js +47 -0
  123. package/dist/mcp/tools/unclaim_task.js.map +1 -0
  124. package/dist/metrics/index.d.ts +2 -0
  125. package/dist/metrics/index.d.ts.map +1 -0
  126. package/dist/metrics/index.js +2 -0
  127. package/dist/metrics/index.js.map +1 -0
  128. package/dist/metrics/metrics.d.ts +79 -0
  129. package/dist/metrics/metrics.d.ts.map +1 -0
  130. package/dist/metrics/metrics.js +166 -0
  131. package/dist/metrics/metrics.js.map +1 -0
  132. package/dist/roles/capabilities.d.ts +1 -0
  133. package/dist/roles/capabilities.d.ts.map +1 -1
  134. package/dist/roles/capabilities.js +3 -0
  135. package/dist/roles/capabilities.js.map +1 -1
  136. package/dist/roles/types.d.ts +1 -1
  137. package/dist/roles/types.d.ts.map +1 -1
  138. package/dist/router/message-router.d.ts +41 -0
  139. package/dist/router/message-router.d.ts.map +1 -1
  140. package/dist/router/message-router.js +136 -5
  141. package/dist/router/message-router.js.map +1 -1
  142. package/dist/store/event-store.d.ts +8 -1
  143. package/dist/store/event-store.d.ts.map +1 -1
  144. package/dist/store/event-store.js +120 -4
  145. package/dist/store/event-store.js.map +1 -1
  146. package/dist/store/types/agents.d.ts +1 -1
  147. package/dist/store/types/agents.d.ts.map +1 -1
  148. package/dist/store/types/events.d.ts +1 -1
  149. package/dist/store/types/events.d.ts.map +1 -1
  150. package/dist/store/types/events.js.map +1 -1
  151. package/dist/store/types/index.d.ts +1 -0
  152. package/dist/store/types/index.d.ts.map +1 -1
  153. package/dist/store/types/index.js +1 -0
  154. package/dist/store/types/index.js.map +1 -1
  155. package/dist/store/types/sessions.d.ts +44 -0
  156. package/dist/store/types/sessions.d.ts.map +1 -0
  157. package/dist/store/types/sessions.js +9 -0
  158. package/dist/store/types/sessions.js.map +1 -0
  159. package/dist/store/types/tasks.d.ts +2 -0
  160. package/dist/store/types/tasks.d.ts.map +1 -1
  161. package/dist/task/backend/memory.d.ts +4 -1
  162. package/dist/task/backend/memory.d.ts.map +1 -1
  163. package/dist/task/backend/memory.js +81 -0
  164. package/dist/task/backend/memory.js.map +1 -1
  165. package/dist/task/backend/types.d.ts +30 -0
  166. package/dist/task/backend/types.d.ts.map +1 -1
  167. package/dist/task/backend/types.js.map +1 -1
  168. package/dist/teams/index.d.ts +4 -0
  169. package/dist/teams/index.d.ts.map +1 -0
  170. package/dist/teams/index.js +4 -0
  171. package/dist/teams/index.js.map +1 -0
  172. package/dist/teams/team-loader.d.ts +20 -0
  173. package/dist/teams/team-loader.d.ts.map +1 -0
  174. package/dist/teams/team-loader.js +293 -0
  175. package/dist/teams/team-loader.js.map +1 -0
  176. package/dist/teams/team-runtime.d.ts +139 -0
  177. package/dist/teams/team-runtime.d.ts.map +1 -0
  178. package/dist/teams/team-runtime.js +613 -0
  179. package/dist/teams/team-runtime.js.map +1 -0
  180. package/dist/teams/types.d.ts +266 -0
  181. package/dist/teams/types.d.ts.map +1 -0
  182. package/dist/teams/types.js +20 -0
  183. package/dist/teams/types.js.map +1 -0
  184. package/dist/workspace/dataplane-adapter.d.ts +1 -1
  185. package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
  186. package/dist/workspace/dataplane-adapter.js +1 -1
  187. package/dist/workspace/dataplane-adapter.js.map +1 -1
  188. package/dist/workspace/index.d.ts +1 -1
  189. package/dist/workspace/index.d.ts.map +1 -1
  190. package/dist/workspace/strategies/index.d.ts +6 -0
  191. package/dist/workspace/strategies/index.d.ts.map +1 -0
  192. package/dist/workspace/strategies/index.js +5 -0
  193. package/dist/workspace/strategies/index.js.map +1 -0
  194. package/dist/workspace/strategies/optimistic.d.ts +26 -0
  195. package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
  196. package/dist/workspace/strategies/optimistic.js +121 -0
  197. package/dist/workspace/strategies/optimistic.js.map +1 -0
  198. package/dist/workspace/strategies/queue.d.ts +26 -0
  199. package/dist/workspace/strategies/queue.d.ts.map +1 -0
  200. package/dist/workspace/strategies/queue.js +67 -0
  201. package/dist/workspace/strategies/queue.js.map +1 -0
  202. package/dist/workspace/strategies/registry.d.ts +37 -0
  203. package/dist/workspace/strategies/registry.d.ts.map +1 -0
  204. package/dist/workspace/strategies/registry.js +63 -0
  205. package/dist/workspace/strategies/registry.js.map +1 -0
  206. package/dist/workspace/strategies/trunk.d.ts +20 -0
  207. package/dist/workspace/strategies/trunk.d.ts.map +1 -0
  208. package/dist/workspace/strategies/trunk.js +108 -0
  209. package/dist/workspace/strategies/trunk.js.map +1 -0
  210. package/dist/workspace/strategies/types.d.ts +104 -0
  211. package/dist/workspace/strategies/types.d.ts.map +1 -0
  212. package/dist/workspace/strategies/types.js +11 -0
  213. package/dist/workspace/strategies/types.js.map +1 -0
  214. package/dist/workspace/types.d.ts +1 -1
  215. package/dist/workspace/types.d.ts.map +1 -1
  216. package/dist/workspace/workspace-manager.d.ts +1 -1
  217. package/dist/workspace/workspace-manager.d.ts.map +1 -1
  218. package/docs/implementation-details.md +1127 -0
  219. package/docs/implementation-summary.md +448 -0
  220. package/docs/plan-self-driving-support.md +433 -0
  221. package/docs/spec-self-driving-support.md +462 -0
  222. package/docs/team-templates.md +860 -0
  223. package/docs/teams.md +233 -0
  224. package/package.json +4 -2
  225. package/src/acp/__tests__/integration.test.ts +161 -1
  226. package/src/acp/__tests__/macro-agent.test.ts +95 -0
  227. package/src/acp/__tests__/session-persistence.test.ts +276 -0
  228. package/src/acp/macro-agent.ts +79 -7
  229. package/src/acp/session-mapper.ts +108 -1
  230. package/src/acp/types.ts +33 -1
  231. package/src/agent/agent-manager.ts +158 -6
  232. package/src/agent/types.ts +27 -0
  233. package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
  234. package/src/agent-detection/__tests__/detector.test.ts +768 -0
  235. package/src/agent-detection/__tests__/registry.test.ts +254 -0
  236. package/src/agent-detection/command-builder.ts +90 -0
  237. package/src/agent-detection/detector.ts +307 -0
  238. package/src/agent-detection/index.ts +36 -0
  239. package/src/agent-detection/registry.ts +200 -0
  240. package/src/agent-detection/types.ts +184 -0
  241. package/src/api/server.ts +110 -0
  242. package/src/cli/index.ts +44 -0
  243. package/src/cli/mcp.ts +47 -0
  244. package/src/config/index.ts +9 -0
  245. package/src/config/project-config.ts +107 -0
  246. package/src/lifecycle/cascade.ts +1 -1
  247. package/src/lifecycle/handlers/index.ts +8 -0
  248. package/src/lifecycle/handlers/worker.ts +48 -3
  249. package/src/map/adapter/__tests__/extensions.test.ts +359 -0
  250. package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
  251. package/src/map/adapter/acp-over-map.ts +45 -2
  252. package/src/map/adapter/event-translator.ts +1 -0
  253. package/src/map/adapter/extensions/agent-detection.ts +201 -0
  254. package/src/map/adapter/extensions/index.ts +63 -0
  255. package/src/map/adapter/extensions/resume.ts +114 -0
  256. package/src/map/adapter/extensions/workspace-files.ts +449 -0
  257. package/src/mcp/mcp-server.ts +67 -0
  258. package/src/mcp/tools/claim_task.ts +86 -0
  259. package/src/mcp/tools/done.ts +24 -10
  260. package/src/mcp/tools/list_claimable_tasks.ts +93 -0
  261. package/src/mcp/tools/unclaim_task.ts +71 -0
  262. package/src/metrics/index.ts +9 -0
  263. package/src/metrics/metrics.ts +280 -0
  264. package/src/roles/capabilities.ts +3 -0
  265. package/src/roles/types.ts +2 -1
  266. package/src/router/__tests__/message-router.test.ts +561 -0
  267. package/src/router/message-router.ts +223 -6
  268. package/src/store/event-store.ts +151 -3
  269. package/src/store/types/agents.ts +1 -1
  270. package/src/store/types/events.ts +2 -1
  271. package/src/store/types/index.ts +1 -0
  272. package/src/store/types/sessions.ts +53 -0
  273. package/src/store/types/tasks.ts +3 -0
  274. package/src/task/backend/memory.ts +116 -0
  275. package/src/task/backend/types.ts +43 -0
  276. package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
  277. package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
  278. package/src/teams/__tests__/team-system.test.ts +1280 -0
  279. package/src/teams/index.ts +13 -0
  280. package/src/teams/team-loader.ts +434 -0
  281. package/src/teams/team-runtime.ts +727 -0
  282. package/src/teams/types.ts +377 -0
  283. package/src/workspace/dataplane-adapter.ts +1 -1
  284. package/src/workspace/index.ts +1 -1
  285. package/src/workspace/strategies/index.ts +18 -0
  286. package/src/workspace/strategies/optimistic.ts +136 -0
  287. package/src/workspace/strategies/queue.ts +81 -0
  288. package/src/workspace/strategies/registry.ts +89 -0
  289. package/src/workspace/strategies/trunk.ts +123 -0
  290. package/src/workspace/strategies/types.ts +145 -0
  291. package/src/workspace/types.ts +1 -1
  292. package/src/workspace/workspace-manager.ts +1 -1
  293. package/.claude/settings.local.json +0 -59
  294. package/dist/map/utils/address-translation.d.ts +0 -99
  295. package/dist/map/utils/address-translation.d.ts.map +0 -1
  296. package/dist/map/utils/address-translation.js +0 -285
  297. package/dist/map/utils/address-translation.js.map +0 -1
  298. package/dist/map/utils/index.d.ts +0 -7
  299. package/dist/map/utils/index.d.ts.map +0 -1
  300. package/dist/map/utils/index.js +0 -7
  301. package/dist/map/utils/index.js.map +0 -1
  302. package/references/acp-factory-ref/CHANGELOG.md +0 -33
  303. package/references/acp-factory-ref/LICENSE +0 -21
  304. package/references/acp-factory-ref/README.md +0 -341
  305. package/references/acp-factory-ref/package-lock.json +0 -3102
  306. package/references/acp-factory-ref/package.json +0 -96
  307. package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
  308. package/references/acp-factory-ref/python/LICENSE +0 -21
  309. package/references/acp-factory-ref/python/Makefile +0 -57
  310. package/references/acp-factory-ref/python/README.md +0 -253
  311. package/references/acp-factory-ref/python/pyproject.toml +0 -73
  312. package/references/acp-factory-ref/python/tests/__init__.py +0 -0
  313. package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
  314. package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
  315. package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
  316. package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
  317. package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
  318. package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
  319. package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
  320. package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
  321. package/references/claude-code-acp/.prettierrc.json +0 -4
  322. package/references/claude-code-acp/CHANGELOG.md +0 -249
  323. package/references/claude-code-acp/LICENSE +0 -222
  324. package/references/claude-code-acp/README.md +0 -53
  325. package/references/claude-code-acp/docs/RELEASES.md +0 -24
  326. package/references/claude-code-acp/eslint.config.js +0 -48
  327. package/references/claude-code-acp/package-lock.json +0 -4570
  328. package/references/claude-code-acp/package.json +0 -88
  329. package/references/claude-code-acp/scripts/release.sh +0 -119
  330. package/references/claude-code-acp/src/acp-agent.ts +0 -2065
  331. package/references/claude-code-acp/src/index.ts +0 -26
  332. package/references/claude-code-acp/src/lib.ts +0 -38
  333. package/references/claude-code-acp/src/mcp-server.ts +0 -911
  334. package/references/claude-code-acp/src/settings.ts +0 -522
  335. package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
  336. package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
  337. package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
  338. package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
  339. package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
  340. package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
  341. package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
  342. package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
  343. package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
  344. package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
  345. package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
  346. package/references/claude-code-acp/src/tools.ts +0 -819
  347. package/references/claude-code-acp/src/utils.ts +0 -171
  348. package/references/claude-code-acp/tsconfig.json +0 -18
  349. package/references/claude-code-acp/vitest.config.ts +0 -19
  350. package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -111
  351. package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -13
  352. package/references/multi-agent-protocol/LICENSE +0 -21
  353. package/references/multi-agent-protocol/README.md +0 -113
  354. package/references/multi-agent-protocol/docs/00-design-specification.md +0 -496
  355. package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
  356. package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
  357. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
  358. package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
  359. package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
  360. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
  361. package/references/multi-agent-protocol/docs/07-federation.md +0 -259
  362. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
  363. package/references/multi-agent-protocol/docs/09-authentication.md +0 -680
  364. package/references/multi-agent-protocol/docs/10-mail-protocol.md +0 -553
  365. package/references/multi-agent-protocol/docs/agent-iam-integration.md +0 -877
  366. package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +0 -459
  367. package/references/multi-agent-protocol/docs/git-transport-draft.md +0 -251
  368. package/references/multi-agent-protocol/docs-site/Gemfile +0 -22
  369. package/references/multi-agent-protocol/docs-site/README.md +0 -82
  370. package/references/multi-agent-protocol/docs-site/_config.yml +0 -91
  371. package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +0 -20
  372. package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +0 -42
  373. package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +0 -34
  374. package/references/multi-agent-protocol/docs-site/examples/full-integration.md +0 -510
  375. package/references/multi-agent-protocol/docs-site/examples/index.md +0 -138
  376. package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +0 -282
  377. package/references/multi-agent-protocol/docs-site/examples/task-queue.md +0 -399
  378. package/references/multi-agent-protocol/docs-site/getting-started/index.md +0 -98
  379. package/references/multi-agent-protocol/docs-site/getting-started/installation.md +0 -219
  380. package/references/multi-agent-protocol/docs-site/getting-started/overview.md +0 -172
  381. package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +0 -237
  382. package/references/multi-agent-protocol/docs-site/index.md +0 -136
  383. package/references/multi-agent-protocol/docs-site/protocol/authentication.md +0 -391
  384. package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +0 -376
  385. package/references/multi-agent-protocol/docs-site/protocol/design.md +0 -284
  386. package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +0 -312
  387. package/references/multi-agent-protocol/docs-site/protocol/federation.md +0 -449
  388. package/references/multi-agent-protocol/docs-site/protocol/index.md +0 -129
  389. package/references/multi-agent-protocol/docs-site/protocol/permissions.md +0 -398
  390. package/references/multi-agent-protocol/docs-site/protocol/streaming.md +0 -353
  391. package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +0 -369
  392. package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +0 -357
  393. package/references/multi-agent-protocol/docs-site/sdk/api/client.md +0 -380
  394. package/references/multi-agent-protocol/docs-site/sdk/api/index.md +0 -62
  395. package/references/multi-agent-protocol/docs-site/sdk/api/server.md +0 -453
  396. package/references/multi-agent-protocol/docs-site/sdk/api/types.md +0 -468
  397. package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +0 -375
  398. package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +0 -405
  399. package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +0 -352
  400. package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +0 -89
  401. package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +0 -360
  402. package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +0 -446
  403. package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +0 -363
  404. package/references/multi-agent-protocol/docs-site/sdk/index.md +0 -206
  405. package/references/multi-agent-protocol/package-lock.json +0 -3886
  406. package/references/multi-agent-protocol/package.json +0 -56
  407. package/references/multi-agent-protocol/schema/meta.json +0 -467
  408. package/references/multi-agent-protocol/schema/schema.json +0 -2558
@@ -1,1502 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from "vitest";
2
- import { spawn, spawnSync } from "child_process";
3
- import {
4
- Agent,
5
- AgentSideConnection,
6
- AvailableCommand,
7
- Client,
8
- ClientSideConnection,
9
- ndJsonStream,
10
- NewSessionResponse,
11
- ReadTextFileRequest,
12
- ReadTextFileResponse,
13
- RequestPermissionRequest,
14
- RequestPermissionResponse,
15
- SessionNotification,
16
- WriteTextFileRequest,
17
- WriteTextFileResponse,
18
- } from "@agentclientprotocol/sdk";
19
- import { nodeToWebWritable, nodeToWebReadable } from "../utils.js";
20
- import { markdownEscape, toolInfoFromToolUse, toolUpdateFromToolResult } from "../tools.js";
21
- import { toAcpNotifications, promptToClaude } from "../acp-agent.js";
22
- import { query, SDKAssistantMessage } from "@anthropic-ai/claude-agent-sdk";
23
- import { randomUUID } from "crypto";
24
- import type {
25
- BetaToolResultBlockParam,
26
- BetaToolSearchToolResultBlockParam,
27
- BetaWebSearchToolResultBlockParam,
28
- BetaWebFetchToolResultBlockParam,
29
- BetaCodeExecutionToolResultBlockParam,
30
- } from "@anthropic-ai/sdk/resources/beta.mjs";
31
-
32
- describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration", () => {
33
- let child: ReturnType<typeof spawn>;
34
-
35
- beforeAll(async () => {
36
- const valid = spawnSync("tsc", { stdio: "inherit" });
37
- if (valid.status) {
38
- throw new Error("failed to compile");
39
- }
40
- // Start the subprocess
41
- child = spawn("npm", ["run", "--silent", "dev"], {
42
- stdio: ["pipe", "pipe", "inherit"],
43
- env: process.env,
44
- });
45
- child.on("error", (error) => {
46
- console.error("Error starting subprocess:", error);
47
- });
48
- child.on("exit", (exit) => {
49
- console.error("Exited with", exit);
50
- });
51
- });
52
-
53
- afterAll(() => {
54
- child.kill();
55
- });
56
-
57
- class TestClient implements Client {
58
- agent: Agent;
59
- files: Map<string, string> = new Map();
60
- receivedText: string = "";
61
- resolveAvailableCommands: (commands: AvailableCommand[]) => void;
62
- availableCommandsPromise: Promise<AvailableCommand[]>;
63
-
64
- constructor(agent: Agent) {
65
- this.agent = agent;
66
- this.resolveAvailableCommands = () => {};
67
- this.availableCommandsPromise = new Promise((resolve) => {
68
- this.resolveAvailableCommands = resolve;
69
- });
70
- }
71
-
72
- takeReceivedText() {
73
- const text = this.receivedText;
74
- this.receivedText = "";
75
- return text;
76
- }
77
-
78
- async requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {
79
- const optionId = params.options.find((p) => p.kind === "allow_once")!.optionId;
80
-
81
- return { outcome: { outcome: "selected", optionId } };
82
- }
83
-
84
- async sessionUpdate(params: SessionNotification): Promise<void> {
85
- console.error("RECEIVED", JSON.stringify(params, null, 4));
86
-
87
- switch (params.update.sessionUpdate) {
88
- case "agent_message_chunk": {
89
- if (params.update.content.type === "text") {
90
- this.receivedText += params.update.content.text;
91
- }
92
- break;
93
- }
94
- case "available_commands_update":
95
- this.resolveAvailableCommands(params.update.availableCommands);
96
- break;
97
- default:
98
- break;
99
- }
100
- }
101
-
102
- async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {
103
- this.files.set(params.path, params.content);
104
- return {};
105
- }
106
-
107
- async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {
108
- const content = this.files.get(params.path) ?? "";
109
- return {
110
- content,
111
- };
112
- }
113
- }
114
-
115
- async function setupTestSession(cwd: string): Promise<{
116
- client: TestClient;
117
- connection: ClientSideConnection;
118
- newSessionResponse: NewSessionResponse;
119
- }> {
120
- let client;
121
- const input = nodeToWebWritable(child.stdin!);
122
- const output = nodeToWebReadable(child.stdout!);
123
- const stream = ndJsonStream(input, output);
124
- const connection = new ClientSideConnection((agent) => {
125
- client = new TestClient(agent);
126
- return client;
127
- }, stream);
128
-
129
- await connection.initialize({
130
- protocolVersion: 1,
131
- clientCapabilities: {
132
- fs: {
133
- readTextFile: true,
134
- writeTextFile: true,
135
- },
136
- },
137
- });
138
-
139
- const newSessionResponse = await connection.newSession({
140
- cwd,
141
- mcpServers: [],
142
- });
143
-
144
- return { client: client!, connection, newSessionResponse };
145
- }
146
-
147
- it("should connect to the ACP subprocess", async () => {
148
- const { client, connection, newSessionResponse } = await setupTestSession("./");
149
-
150
- await connection.prompt({
151
- prompt: [
152
- {
153
- type: "text",
154
- text: "Hello",
155
- },
156
- ],
157
- sessionId: newSessionResponse.sessionId,
158
- });
159
-
160
- expect(client.takeReceivedText()).not.toEqual("");
161
- }, 30000);
162
-
163
- it("should include available commands", async () => {
164
- const { client, connection, newSessionResponse } = await setupTestSession(__dirname);
165
-
166
- const commands = await client.availableCommandsPromise;
167
-
168
- expect(commands).toContainEqual({
169
- name: "quick-math",
170
- description: "10 * 3 = 30 (project)",
171
- input: null,
172
- });
173
- expect(commands).toContainEqual({
174
- name: "say-hello",
175
- description: "Say hello (project)",
176
- input: { hint: "name" },
177
- });
178
-
179
- await connection.prompt({
180
- prompt: [
181
- {
182
- type: "text",
183
- text: "/quick-math",
184
- },
185
- ],
186
- sessionId: newSessionResponse.sessionId,
187
- });
188
-
189
- expect(client.takeReceivedText()).toContain("30");
190
-
191
- await connection.prompt({
192
- prompt: [
193
- {
194
- type: "text",
195
- text: "/say-hello GPT-5",
196
- },
197
- ],
198
- sessionId: newSessionResponse.sessionId,
199
- });
200
-
201
- expect(client.takeReceivedText()).toContain("Hello GPT-5");
202
- }, 30000);
203
-
204
- it("/compact works", async () => {
205
- const { client, connection, newSessionResponse } = await setupTestSession(__dirname);
206
-
207
- const commands = await client.availableCommandsPromise;
208
-
209
- expect(commands).toContainEqual({
210
- description:
211
- "Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]",
212
- input: {
213
- hint: "<optional custom summarization instructions>",
214
- },
215
- name: "compact",
216
- });
217
-
218
- // Error case (no previous message)
219
- await connection.prompt({
220
- prompt: [{ type: "text", text: "/compact" }],
221
- sessionId: newSessionResponse.sessionId,
222
- });
223
-
224
- expect(client.takeReceivedText()).toBe("");
225
-
226
- // Send something
227
- await connection.prompt({
228
- prompt: [{ type: "text", text: "Hi" }],
229
- sessionId: newSessionResponse.sessionId,
230
- });
231
- // Clear response
232
- client.takeReceivedText();
233
-
234
- // Test with instruction
235
- await connection.prompt({
236
- prompt: [
237
- {
238
- type: "text",
239
- text: "/compact greeting",
240
- },
241
- ],
242
- sessionId: newSessionResponse.sessionId,
243
- });
244
-
245
- expect(client.takeReceivedText()).toContain("");
246
- }, 120000);
247
- });
248
-
249
- describe("tool conversions", () => {
250
- it("should handle Bash nicely", () => {
251
- const tool_use = {
252
- type: "tool_use",
253
- id: "toolu_01VtsS2mxUFwpBJZYd7BmbC9",
254
- name: "Bash",
255
- input: {
256
- command: "rm README.md.rm",
257
- description: "Delete README.md.rm file",
258
- },
259
- };
260
-
261
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
262
- kind: "execute",
263
- title: "`rm README.md.rm`",
264
- content: [
265
- {
266
- content: {
267
- text: "Delete README.md.rm file",
268
- type: "text",
269
- },
270
- type: "content",
271
- },
272
- ],
273
- });
274
- });
275
-
276
- it("should handle Glob nicely", () => {
277
- const tool_use = {
278
- type: "tool_use",
279
- id: "toolu_01VtsS2mxUFwpBJZYd7BmbC9",
280
- name: "Glob",
281
- input: {
282
- pattern: "*/**.ts",
283
- },
284
- };
285
-
286
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
287
- kind: "search",
288
- title: "Find `*/**.ts`",
289
- content: [],
290
- locations: [],
291
- });
292
- });
293
-
294
- it("should handle Task tool calls", () => {
295
- const tool_use = {
296
- type: "tool_use",
297
- id: "toolu_01ANYHYDsXcDPKgxhg7us9bj",
298
- name: "Task",
299
- input: {
300
- description: "Handle user's work request",
301
- prompt:
302
- 'The user has asked me to "Create a Task to do the work!" but hasn\'t specified what specific work they want done. I need to:\n\n1. First understand what work needs to be done by examining the current state of the repository\n2. Look at the git status to see what files have been modified\n3. Check if there are any obvious tasks that need completion based on the current state\n4. If the work isn\'t clear from the context, ask the user to specify what work they want accomplished\n\nThe git status shows: "M src/tests/acp-agent.test.ts" - there\'s a modified test file that might need attention.\n\nPlease examine the repository state and determine what work needs to be done, then either complete it or ask the user for clarification on the specific task they want accomplished.',
303
- subagent_type: "general-purpose",
304
- },
305
- };
306
-
307
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
308
- kind: "think",
309
- title: "Handle user's work request",
310
- content: [
311
- {
312
- content: {
313
- text: 'The user has asked me to "Create a Task to do the work!" but hasn\'t specified what specific work they want done. I need to:\n\n1. First understand what work needs to be done by examining the current state of the repository\n2. Look at the git status to see what files have been modified\n3. Check if there are any obvious tasks that need completion based on the current state\n4. If the work isn\'t clear from the context, ask the user to specify what work they want accomplished\n\nThe git status shows: "M src/tests/acp-agent.test.ts" - there\'s a modified test file that might need attention.\n\nPlease examine the repository state and determine what work needs to be done, then either complete it or ask the user for clarification on the specific task they want accomplished.',
314
- type: "text",
315
- },
316
- type: "content",
317
- },
318
- ],
319
- });
320
- });
321
-
322
- it("should handle LS tool calls", () => {
323
- const tool_use = {
324
- type: "tool_use",
325
- id: "toolu_01EEqsX7Eb9hpx87KAHVPTey",
326
- name: "LS",
327
- input: {
328
- path: "/Users/test/github/claude-code-acp",
329
- },
330
- };
331
-
332
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
333
- kind: "search",
334
- title: "List the `/Users/test/github/claude-code-acp` directory's contents",
335
- content: [],
336
- locations: [],
337
- });
338
- });
339
-
340
- it("should handle Grep tool calls", () => {
341
- const tool_use = {
342
- type: "tool_use",
343
- id: "toolu_016j8oGSD3eAZ9KT62Y7Jsjb",
344
- name: "Grep",
345
- input: {
346
- pattern: ".*",
347
- },
348
- };
349
-
350
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
351
- kind: "search",
352
- title: 'grep ".*"',
353
- content: [],
354
- });
355
- });
356
-
357
- it("should handle Write tool calls", () => {
358
- const tool_use = {
359
- type: "tool_use",
360
- id: "toolu_01ABC123XYZ789",
361
- name: "Write",
362
- input: {
363
- file_path: "/Users/test/project/example.txt",
364
- content: "Hello, World!\nThis is test content.",
365
- },
366
- };
367
-
368
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
369
- kind: "edit",
370
- title: "Write /Users/test/project/example.txt",
371
- content: [
372
- {
373
- type: "diff",
374
- path: "/Users/test/project/example.txt",
375
- oldText: null,
376
- newText: "Hello, World!\nThis is test content.",
377
- },
378
- ],
379
- locations: [{ path: "/Users/test/project/example.txt" }],
380
- });
381
- });
382
-
383
- it("should handle mcp__acp__Write tool calls", () => {
384
- const tool_use = {
385
- type: "tool_use",
386
- id: "toolu_01GHI789JKL456",
387
- name: "mcp__acp__Write",
388
- input: {
389
- file_path: "/Users/test/project/config.json",
390
- content: '{"version": "1.0.0"}',
391
- },
392
- };
393
-
394
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
395
- kind: "edit",
396
- title: "Write /Users/test/project/config.json",
397
- content: [
398
- {
399
- type: "diff",
400
- path: "/Users/test/project/config.json",
401
- oldText: null,
402
- newText: '{"version": "1.0.0"}',
403
- },
404
- ],
405
- locations: [{ path: "/Users/test/project/config.json" }],
406
- });
407
- });
408
-
409
- it("should handle Read tool calls", () => {
410
- const tool_use = {
411
- type: "tool_use",
412
- id: "toolu_01MNO456PQR789",
413
- name: "Read",
414
- input: {
415
- file_path: "/Users/test/project/readme.md",
416
- },
417
- };
418
-
419
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
420
- kind: "read",
421
- title: "Read File",
422
- content: [],
423
- locations: [{ path: "/Users/test/project/readme.md", line: 0 }],
424
- });
425
- });
426
-
427
- it("should handle mcp__acp__Read tool calls", () => {
428
- const tool_use = {
429
- type: "tool_use",
430
- id: "toolu_01YZA789BCD123",
431
- name: "mcp__acp__Read",
432
- input: {
433
- file_path: "/Users/test/project/data.json",
434
- },
435
- };
436
-
437
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
438
- kind: "read",
439
- title: "Read /Users/test/project/data.json",
440
- content: [],
441
- locations: [{ path: "/Users/test/project/data.json", line: 0 }],
442
- });
443
- });
444
-
445
- it("should handle mcp__acp__Read with limit", () => {
446
- const tool_use = {
447
- type: "tool_use",
448
- id: "toolu_01EFG456HIJ789",
449
- name: "mcp__acp__Read",
450
- input: {
451
- file_path: "/Users/test/project/large.txt",
452
- limit: 100,
453
- },
454
- };
455
-
456
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
457
- kind: "read",
458
- title: "Read /Users/test/project/large.txt (1 - 100)",
459
- content: [],
460
- locations: [{ path: "/Users/test/project/large.txt", line: 0 }],
461
- });
462
- });
463
-
464
- it("should handle mcp__acp__Read with offset and limit", () => {
465
- const tool_use = {
466
- type: "tool_use",
467
- id: "toolu_01KLM789NOP456",
468
- name: "mcp__acp__Read",
469
- input: {
470
- file_path: "/Users/test/project/large.txt",
471
- offset: 50,
472
- limit: 100,
473
- },
474
- };
475
-
476
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
477
- kind: "read",
478
- title: "Read /Users/test/project/large.txt (51 - 150)",
479
- content: [],
480
- locations: [{ path: "/Users/test/project/large.txt", line: 50 }],
481
- });
482
- });
483
-
484
- it("should handle mcp__acp__Read with only offset", () => {
485
- const tool_use = {
486
- type: "tool_use",
487
- id: "toolu_01QRS123TUV789",
488
- name: "mcp__acp__Read",
489
- input: {
490
- file_path: "/Users/test/project/large.txt",
491
- offset: 200,
492
- },
493
- };
494
-
495
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
496
- kind: "read",
497
- title: "Read /Users/test/project/large.txt (from line 201)",
498
- content: [],
499
- locations: [{ path: "/Users/test/project/large.txt", line: 200 }],
500
- });
501
- });
502
-
503
- it("should handle KillBash entries", () => {
504
- const tool_use = {
505
- type: "tool_use",
506
- id: "toolu_01PhLms5fuvmdjy2bb6dfUKT",
507
- name: "KillShell",
508
- input: {
509
- shell_id: "bash_1",
510
- },
511
- };
512
-
513
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
514
- kind: "execute",
515
- title: `Kill Process`,
516
- content: [],
517
- });
518
- });
519
-
520
- it("should handle BashOutput entries", () => {
521
- const tool_use = {
522
- type: "tool_use",
523
- id: "toolu_01SJUWPtj1QspgANgtpqGPuN",
524
- name: "BashOutput",
525
- input: {
526
- bash_id: "bash_1",
527
- },
528
- };
529
-
530
- expect(toolInfoFromToolUse(tool_use)).toStrictEqual({
531
- kind: "execute",
532
- title: `Tail Logs`,
533
- content: [],
534
- });
535
- });
536
-
537
- it("should handle plan entries", () => {
538
- const received: SDKAssistantMessage = {
539
- type: "assistant",
540
- message: {
541
- id: "msg_017eNosJgww7F5qD4a8BcAcx",
542
- type: "message",
543
- role: "assistant",
544
- container: null,
545
- model: "claude-sonnet-4-20250514",
546
- content: [
547
- {
548
- type: "tool_use",
549
- id: "toolu_01HaXZ4LfdchSeSR8ygt4zyq",
550
- name: "TodoWrite",
551
- input: {
552
- todos: [
553
- {
554
- content: "Analyze existing test coverage and identify gaps",
555
- status: "in_progress",
556
- activeForm: "Analyzing existing test coverage",
557
- },
558
- {
559
- content: "Add comprehensive edge case tests",
560
- status: "pending",
561
- activeForm: "Adding comprehensive edge case tests",
562
- },
563
- {
564
- content: "Add performance and timing tests",
565
- status: "pending",
566
- activeForm: "Adding performance and timing tests",
567
- },
568
- {
569
- content: "Add error handling and panic behavior tests",
570
- status: "pending",
571
- activeForm: "Adding error handling tests",
572
- },
573
- {
574
- content: "Add concurrent access and race condition tests",
575
- status: "pending",
576
- activeForm: "Adding concurrent access tests",
577
- },
578
- {
579
- content: "Add tests for Each function with various data types",
580
- status: "pending",
581
- activeForm: "Adding Each function tests",
582
- },
583
- {
584
- content: "Add benchmark tests for performance measurement",
585
- status: "pending",
586
- activeForm: "Adding benchmark tests",
587
- },
588
- {
589
- content: "Improve test organization and helper functions",
590
- status: "pending",
591
- activeForm: "Improving test organization",
592
- },
593
- ],
594
- },
595
- },
596
- ],
597
- stop_reason: null,
598
- stop_sequence: null,
599
- usage: {
600
- input_tokens: 6,
601
- cache_creation_input_tokens: 326,
602
- cache_read_input_tokens: 17265,
603
- cache_creation: {
604
- ephemeral_5m_input_tokens: 326,
605
- ephemeral_1h_input_tokens: 0,
606
- },
607
- output_tokens: 1,
608
- service_tier: "standard",
609
- server_tool_use: null,
610
- },
611
- context_management: null,
612
- },
613
- parent_tool_use_id: null,
614
- session_id: "d056596f-e328-41e9-badd-b07122ae5227",
615
- uuid: "b7c3330c-de8f-4bba-ac53-68c7f76ffeb5",
616
- };
617
- expect(
618
- toAcpNotifications(
619
- received.message.content,
620
- received.message.role,
621
- "test",
622
- {},
623
- {} as AgentSideConnection,
624
- console,
625
- ),
626
- ).toStrictEqual([
627
- {
628
- sessionId: "test",
629
- update: {
630
- sessionUpdate: "plan",
631
- entries: [
632
- {
633
- content: "Analyze existing test coverage and identify gaps",
634
- priority: "medium",
635
- status: "in_progress",
636
- },
637
- {
638
- content: "Add comprehensive edge case tests",
639
- priority: "medium",
640
- status: "pending",
641
- },
642
- {
643
- content: "Add performance and timing tests",
644
- priority: "medium",
645
- status: "pending",
646
- },
647
- {
648
- content: "Add error handling and panic behavior tests",
649
- priority: "medium",
650
- status: "pending",
651
- },
652
- {
653
- content: "Add concurrent access and race condition tests",
654
- priority: "medium",
655
- status: "pending",
656
- },
657
- {
658
- content: "Add tests for Each function with various data types",
659
- priority: "medium",
660
- status: "pending",
661
- },
662
- {
663
- content: "Add benchmark tests for performance measurement",
664
- priority: "medium",
665
- status: "pending",
666
- },
667
- {
668
- content: "Improve test organization and helper functions",
669
- priority: "medium",
670
- status: "pending",
671
- },
672
- ],
673
- },
674
- },
675
- ]);
676
- });
677
-
678
- it("should return empty update for successful edit result", () => {
679
- const toolUse = {
680
- type: "tool_use",
681
- id: "toolu_01MNO345",
682
- name: "mcp__acp__Edit",
683
- input: {
684
- file_path: "/Users/test/project/test.txt",
685
- old_string: "old",
686
- new_string: "new",
687
- },
688
- };
689
-
690
- const toolResult = {
691
- content: [
692
- {
693
- type: "text" as const,
694
- text: "not valid json",
695
- },
696
- ],
697
- tool_use_id: "test",
698
- is_error: false,
699
- type: "tool_result" as const,
700
- };
701
-
702
- const update = toolUpdateFromToolResult(toolResult, toolUse);
703
-
704
- // Should return empty object when parsing fails
705
- expect(update).toEqual({});
706
- });
707
-
708
- it("should return content update for edit failure", () => {
709
- const toolUse = {
710
- type: "tool_use",
711
- id: "toolu_01MNO345",
712
- name: "mcp__acp__Edit",
713
- input: {
714
- file_path: "/Users/test/project/test.txt",
715
- old_string: "old",
716
- new_string: "new",
717
- },
718
- };
719
-
720
- const toolResult = {
721
- content: [
722
- {
723
- type: "text" as const,
724
- text: "Failed to find `old_string`",
725
- },
726
- ],
727
- tool_use_id: "test",
728
- is_error: true,
729
- type: "tool_result" as const,
730
- };
731
-
732
- const update = toolUpdateFromToolResult(toolResult, toolUse);
733
-
734
- // Should return empty object when parsing fails
735
- expect(update).toEqual({
736
- content: [
737
- {
738
- content: { type: "text", text: "```\nFailed to find `old_string`\n```" },
739
- type: "content",
740
- },
741
- ],
742
- });
743
- });
744
-
745
- it("should transform tool_reference content to valid ACP content", () => {
746
- const toolUse = {
747
- type: "tool_use",
748
- id: "toolu_01MNO345",
749
- name: "ToolSearch",
750
- input: { query: "test" },
751
- };
752
-
753
- const toolResult: BetaToolResultBlockParam = {
754
- content: [
755
- {
756
- type: "tool_reference",
757
- tool_name: "some_discovered_tool",
758
- },
759
- ],
760
- tool_use_id: "toolu_01MNO345",
761
- is_error: false,
762
- type: "tool_result",
763
- };
764
-
765
- const update = toolUpdateFromToolResult(toolResult, toolUse);
766
-
767
- expect(update).toEqual({
768
- content: [
769
- {
770
- type: "content",
771
- content: { type: "text", text: "Tool: some_discovered_tool" },
772
- },
773
- ],
774
- });
775
- });
776
-
777
- it("should transform web_search_result content to valid ACP content", () => {
778
- const toolUse = {
779
- type: "tool_use",
780
- id: "toolu_01MNO345",
781
- name: "WebSearch",
782
- input: { query: "test" },
783
- };
784
-
785
- const toolResult: BetaWebSearchToolResultBlockParam = {
786
- content: [
787
- {
788
- type: "web_search_result",
789
- title: "Test Result",
790
- url: "https://example.com",
791
- encrypted_content: "...",
792
- page_age: null,
793
- },
794
- ],
795
- tool_use_id: "toolu_01MNO345",
796
- type: "web_search_tool_result",
797
- };
798
-
799
- const update = toolUpdateFromToolResult(toolResult, toolUse);
800
-
801
- expect(update).toEqual({
802
- content: [
803
- {
804
- type: "content",
805
- content: { type: "text", text: "Test Result (https://example.com)" },
806
- },
807
- ],
808
- });
809
- });
810
-
811
- it("should transform web_search_tool_result_error to valid ACP content", () => {
812
- const toolUse = {
813
- type: "tool_use",
814
- id: "toolu_01MNO345",
815
- name: "WebSearch",
816
- input: { query: "test" },
817
- };
818
-
819
- const toolResult: BetaWebSearchToolResultBlockParam = {
820
- content: {
821
- type: "web_search_tool_result_error",
822
- error_code: "unavailable",
823
- },
824
- tool_use_id: "toolu_01MNO345",
825
- type: "web_search_tool_result",
826
- };
827
-
828
- const update = toolUpdateFromToolResult(toolResult, toolUse);
829
-
830
- expect(update).toEqual({
831
- content: [
832
- {
833
- type: "content",
834
- content: { type: "text", text: "Error: unavailable" },
835
- },
836
- ],
837
- });
838
- });
839
-
840
- it("should transform code_execution_result content to valid ACP content", () => {
841
- const toolUse = {
842
- type: "tool_use",
843
- id: "toolu_01MNO345",
844
- name: "CodeExecution",
845
- input: {},
846
- };
847
-
848
- const toolResult: BetaCodeExecutionToolResultBlockParam = {
849
- content: {
850
- type: "code_execution_result",
851
- stdout: "Hello World",
852
- stderr: "",
853
- return_code: 0,
854
- content: [],
855
- },
856
- tool_use_id: "toolu_01MNO345",
857
- type: "code_execution_tool_result",
858
- };
859
-
860
- const update = toolUpdateFromToolResult(toolResult, toolUse);
861
-
862
- expect(update).toEqual({
863
- content: [
864
- {
865
- type: "content",
866
- content: { type: "text", text: "Output: Hello World" },
867
- },
868
- ],
869
- });
870
- });
871
-
872
- it("should transform web_fetch_result content to valid ACP content", () => {
873
- const toolUse = {
874
- type: "tool_use",
875
- id: "toolu_01MNO345",
876
- name: "WebFetch",
877
- input: { url: "https://example.com" },
878
- };
879
-
880
- const toolResult: BetaWebFetchToolResultBlockParam = {
881
- content: {
882
- type: "web_fetch_result",
883
- url: "https://example.com",
884
- content: {
885
- type: "document",
886
- citations: null,
887
- title: null,
888
- source: { type: "text", media_type: "text/plain", data: "Page content here" },
889
- },
890
- },
891
- tool_use_id: "toolu_01MNO345",
892
- type: "web_fetch_tool_result",
893
- };
894
-
895
- const update = toolUpdateFromToolResult(toolResult, toolUse);
896
-
897
- expect(update).toEqual({
898
- content: [
899
- {
900
- type: "content",
901
- content: { type: "text", text: "Fetched: https://example.com" },
902
- },
903
- ],
904
- });
905
- });
906
-
907
- it("should transform tool_search_tool_search_result to valid ACP content", () => {
908
- const toolUse = {
909
- type: "tool_use",
910
- id: "toolu_01MNO345",
911
- name: "ToolSearch",
912
- input: { query: "test" },
913
- };
914
-
915
- const toolResult: BetaToolSearchToolResultBlockParam = {
916
- content: {
917
- type: "tool_search_tool_search_result",
918
- tool_references: [
919
- { type: "tool_reference", tool_name: "tool_a" },
920
- { type: "tool_reference", tool_name: "tool_b" },
921
- ],
922
- },
923
- tool_use_id: "toolu_01MNO345",
924
- type: "tool_search_tool_result",
925
- };
926
-
927
- const update = toolUpdateFromToolResult(toolResult, toolUse);
928
-
929
- expect(update).toEqual({
930
- content: [
931
- {
932
- type: "content",
933
- content: { type: "text", text: "Tools found: tool_a, tool_b" },
934
- },
935
- ],
936
- });
937
- });
938
- });
939
-
940
- describe("escape markdown", () => {
941
- it("should escape markdown characters", () => {
942
- let text = "Hello *world*!";
943
- let escaped = markdownEscape(text);
944
- expect(escaped).toEqual("```\nHello *world*!\n```");
945
-
946
- text = "for example:\n```markdown\nHello *world*!\n```\n";
947
- escaped = markdownEscape(text);
948
- expect(escaped).toEqual("````\nfor example:\n```markdown\nHello *world*!\n```\n````");
949
- });
950
- });
951
-
952
- describe("prompt conversion", () => {
953
- it("should not change built-in slash commands", () => {
954
- const message = promptToClaude({
955
- sessionId: "test",
956
- prompt: [
957
- {
958
- type: "text",
959
- text: "/compact args",
960
- },
961
- ],
962
- });
963
- expect(message.message.content).toEqual([
964
- {
965
- text: "/compact args",
966
- type: "text",
967
- },
968
- ]);
969
- });
970
-
971
- it("should remove MCP prefix from MCP slash commands", () => {
972
- const message = promptToClaude({
973
- sessionId: "test",
974
- prompt: [
975
- {
976
- type: "text",
977
- text: "/mcp:server:name args",
978
- },
979
- ],
980
- });
981
- expect(message.message.content).toEqual([
982
- {
983
- text: "/server:name (MCP) args",
984
- type: "text",
985
- },
986
- ]);
987
- });
988
- });
989
-
990
- describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("SDK behavior", () => {
991
- it("query has a 'default' model", async () => {
992
- const q = query({ prompt: "hi" });
993
- const models = await q.supportedModels();
994
- const defaultModel = models.find((m) => m.value === "default");
995
- expect(defaultModel).toBeDefined();
996
- }, 10000);
997
-
998
- it("custom session id", async () => {
999
- const sessionId = randomUUID();
1000
- const q = query({
1001
- prompt: "hi",
1002
- options: {
1003
- systemPrompt: { type: "preset", preset: "claude_code" },
1004
- extraArgs: { "session-id": sessionId },
1005
- settingSources: ["user", "project", "local"],
1006
- includePartialMessages: true,
1007
- },
1008
- });
1009
-
1010
- // The SDK may send other events (like hook_started) before init
1011
- // Iterate to find the init event
1012
- let initEvent = null;
1013
- for await (const value of q) {
1014
- if (value.type === "system" && value.subtype === "init") {
1015
- initEvent = value;
1016
- break;
1017
- }
1018
- }
1019
- expect(initEvent).toMatchObject({ type: "system", subtype: "init", session_id: sessionId });
1020
- }, 10000);
1021
- });
1022
-
1023
- describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("_session/inject e2e", () => {
1024
- let child: ReturnType<typeof spawn>;
1025
-
1026
- beforeAll(async () => {
1027
- const valid = spawnSync("tsc", { stdio: "inherit" });
1028
- if (valid.status) {
1029
- throw new Error("failed to compile");
1030
- }
1031
- child = spawn("npm", ["run", "--silent", "dev"], {
1032
- stdio: ["pipe", "pipe", "inherit"],
1033
- env: process.env,
1034
- });
1035
- child.on("error", (error) => {
1036
- console.error("Error starting subprocess:", error);
1037
- });
1038
- });
1039
-
1040
- afterAll(() => {
1041
- child.kill();
1042
- });
1043
-
1044
- class InjectTestClient implements Client {
1045
- agent: Agent;
1046
- receivedText: string = "";
1047
- messageChunks: string[] = [];
1048
-
1049
- constructor(agent: Agent) {
1050
- this.agent = agent;
1051
- }
1052
-
1053
- takeReceivedText() {
1054
- const text = this.receivedText;
1055
- this.receivedText = "";
1056
- return text;
1057
- }
1058
-
1059
- async requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {
1060
- const optionId = params.options.find((p) => p.kind === "allow_once")!.optionId;
1061
- return { outcome: { outcome: "selected", optionId } };
1062
- }
1063
-
1064
- async sessionUpdate(params: SessionNotification): Promise<void> {
1065
- if (params.update.sessionUpdate === "agent_message_chunk") {
1066
- if (params.update.content.type === "text") {
1067
- this.receivedText += params.update.content.text;
1068
- this.messageChunks.push(params.update.content.text);
1069
- }
1070
- }
1071
- }
1072
-
1073
- async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {
1074
- return {};
1075
- }
1076
-
1077
- async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {
1078
- return { content: "" };
1079
- }
1080
- }
1081
-
1082
- it("should inject message that is processed in next turn", async () => {
1083
- let client: InjectTestClient;
1084
- const input = nodeToWebWritable(child.stdin!);
1085
- const output = nodeToWebReadable(child.stdout!);
1086
- const stream = ndJsonStream(input, output);
1087
- const connection = new ClientSideConnection((agent) => {
1088
- client = new InjectTestClient(agent);
1089
- return client;
1090
- }, stream);
1091
-
1092
- await connection.initialize({
1093
- protocolVersion: 1,
1094
- clientCapabilities: {
1095
- fs: { readTextFile: true, writeTextFile: true },
1096
- },
1097
- });
1098
-
1099
- const { sessionId } = await connection.newSession({
1100
- cwd: "./",
1101
- mcpServers: [],
1102
- });
1103
-
1104
- // First prompt - simple greeting
1105
- await connection.prompt({
1106
- prompt: [{ type: "text", text: "Say hi." }],
1107
- sessionId,
1108
- });
1109
- client!.takeReceivedText(); // Clear first response
1110
-
1111
- // Inject a message into the session (this queues it for the next turn)
1112
- const injectResult = await connection.extMethod("_session/inject", {
1113
- sessionId,
1114
- message: "In your next response, include the word ELEPHANT.",
1115
- });
1116
- expect(injectResult).toEqual({ success: true });
1117
-
1118
- // Second prompt - the injected message should be processed first
1119
- await connection.prompt({
1120
- prompt: [{ type: "text", text: "What animal should you mention?" }],
1121
- sessionId,
1122
- });
1123
-
1124
- // The response should acknowledge the injected instruction
1125
- const responseText = client!.takeReceivedText().toUpperCase();
1126
- expect(responseText).toContain("ELEPHANT");
1127
- }, 60000);
1128
-
1129
- it("should inject ContentBlock array message for next turn", async () => {
1130
- let client: InjectTestClient;
1131
- const input = nodeToWebWritable(child.stdin!);
1132
- const output = nodeToWebReadable(child.stdout!);
1133
- const stream = ndJsonStream(input, output);
1134
- const connection = new ClientSideConnection((agent) => {
1135
- client = new InjectTestClient(agent);
1136
- return client;
1137
- }, stream);
1138
-
1139
- await connection.initialize({
1140
- protocolVersion: 1,
1141
- clientCapabilities: {
1142
- fs: { readTextFile: true, writeTextFile: true },
1143
- },
1144
- });
1145
-
1146
- const { sessionId } = await connection.newSession({
1147
- cwd: "./",
1148
- mcpServers: [],
1149
- });
1150
-
1151
- // First prompt
1152
- await connection.prompt({
1153
- prompt: [{ type: "text", text: "Say hi." }],
1154
- sessionId,
1155
- });
1156
- client!.takeReceivedText(); // Clear first response
1157
-
1158
- // Inject using ContentBlock array format
1159
- const injectResult = await connection.extMethod("_session/inject", {
1160
- sessionId,
1161
- message: [
1162
- { type: "text", text: "In your next response, include the word BANANA." },
1163
- ],
1164
- });
1165
- expect(injectResult).toEqual({ success: true });
1166
-
1167
- // Next prompt triggers processing of injected message
1168
- await connection.prompt({
1169
- prompt: [{ type: "text", text: "What fruit should you mention?" }],
1170
- sessionId,
1171
- });
1172
-
1173
- const responseText = client!.takeReceivedText().toUpperCase();
1174
- expect(responseText).toContain("BANANA");
1175
- }, 60000);
1176
-
1177
- it("should return error for non-existent session", async () => {
1178
- let client: InjectTestClient;
1179
- const input = nodeToWebWritable(child.stdin!);
1180
- const output = nodeToWebReadable(child.stdout!);
1181
- const stream = ndJsonStream(input, output);
1182
- const connection = new ClientSideConnection((agent) => {
1183
- client = new InjectTestClient(agent);
1184
- return client;
1185
- }, stream);
1186
-
1187
- await connection.initialize({
1188
- protocolVersion: 1,
1189
- clientCapabilities: {},
1190
- });
1191
-
1192
- const injectResult = await connection.extMethod("_session/inject", {
1193
- sessionId: "non-existent-session-id",
1194
- message: "test",
1195
- });
1196
-
1197
- expect(injectResult).toEqual({
1198
- success: false,
1199
- error: "Session non-existent-session-id not found",
1200
- });
1201
- }, 30000);
1202
- });
1203
-
1204
- describe("permission requests", () => {
1205
- it("should include title field in tool permission request structure", () => {
1206
- // Test various tool types to ensure title is correctly generated
1207
- const testCases = [
1208
- {
1209
- toolUse: {
1210
- type: "tool_use" as const,
1211
- id: "test-1",
1212
- name: "Write",
1213
- input: { file_path: "/test/file.txt", content: "test" },
1214
- },
1215
- expectedTitlePart: "/test/file.txt",
1216
- },
1217
- {
1218
- toolUse: {
1219
- type: "tool_use" as const,
1220
- id: "test-2",
1221
- name: "Bash",
1222
- input: { command: "ls -la", description: "List files" },
1223
- },
1224
- expectedTitlePart: "`ls -la`",
1225
- },
1226
- {
1227
- toolUse: {
1228
- type: "tool_use" as const,
1229
- id: "test-3",
1230
- name: "mcp__acp__Read",
1231
- input: { file_path: "/test/data.json" },
1232
- },
1233
- expectedTitlePart: "/test/data.json",
1234
- },
1235
- ];
1236
-
1237
- for (const testCase of testCases) {
1238
- // Get the tool info that would be used in requestPermission
1239
- const toolInfo = toolInfoFromToolUse(testCase.toolUse);
1240
-
1241
- // Verify toolInfo has a title
1242
- expect(toolInfo.title).toBeDefined();
1243
- expect(toolInfo.title).toContain(testCase.expectedTitlePart);
1244
-
1245
- // Verify the structure that our fix creates for requestPermission
1246
- const requestStructure = {
1247
- toolCall: {
1248
- toolCallId: testCase.toolUse.id,
1249
- rawInput: testCase.toolUse.input,
1250
- title: toolInfo.title, // This is what commit 1785d86 adds
1251
- },
1252
- };
1253
-
1254
- // Ensure the title field is present and populated
1255
- expect(requestStructure.toolCall.title).toBeDefined();
1256
- expect(requestStructure.toolCall.title).toContain(testCase.expectedTitlePart);
1257
- }
1258
- });
1259
- });
1260
-
1261
- describe("auto-compaction configuration", () => {
1262
- it("should accept compaction config in NewSessionMeta", () => {
1263
- // Test that the CompactionConfig type structure is correct
1264
- const meta: { claudeCode: { compaction: { enabled: boolean; contextTokenThreshold?: number; customInstructions?: string } } } = {
1265
- claudeCode: {
1266
- compaction: {
1267
- enabled: true,
1268
- contextTokenThreshold: 50000,
1269
- customInstructions: "Focus on the key decisions and outcomes",
1270
- },
1271
- },
1272
- };
1273
-
1274
- // Verify the structure
1275
- expect(meta.claudeCode.compaction.enabled).toBe(true);
1276
- expect(meta.claudeCode.compaction.contextTokenThreshold).toBe(50000);
1277
- expect(meta.claudeCode.compaction.customInstructions).toBe(
1278
- "Focus on the key decisions and outcomes",
1279
- );
1280
- });
1281
-
1282
- it("should have sensible defaults for compaction config", () => {
1283
- // When compaction is not configured, it should be disabled
1284
- const metaWithoutCompaction: { claudeCode: { compaction?: unknown } } = {
1285
- claudeCode: {},
1286
- };
1287
- expect(metaWithoutCompaction.claudeCode.compaction).toBeUndefined();
1288
-
1289
- // When compaction is enabled without threshold, default should be used
1290
- const metaWithDefaults: { claudeCode: { compaction: { enabled: boolean; contextTokenThreshold?: number } } } = {
1291
- claudeCode: {
1292
- compaction: {
1293
- enabled: true,
1294
- },
1295
- },
1296
- };
1297
- expect(metaWithDefaults.claudeCode.compaction.enabled).toBe(true);
1298
- expect(metaWithDefaults.claudeCode.compaction.contextTokenThreshold).toBeUndefined();
1299
- // The actual default (100000) is applied in createSession
1300
- });
1301
-
1302
- it("should support minimal compaction config with just enabled flag", () => {
1303
- const minimalConfig: { claudeCode: { compaction: { enabled: boolean } } } = {
1304
- claudeCode: {
1305
- compaction: {
1306
- enabled: false,
1307
- },
1308
- },
1309
- };
1310
-
1311
- expect(minimalConfig.claudeCode.compaction.enabled).toBe(false);
1312
- });
1313
- });
1314
-
1315
- describe("compaction event emission", () => {
1316
- it("compaction_started event should have correct structure", () => {
1317
- const event = {
1318
- sessionUpdate: "compaction_started",
1319
- sessionId: "test-session-123",
1320
- trigger: "auto" as const,
1321
- preTokens: 105000,
1322
- threshold: 100000,
1323
- };
1324
-
1325
- expect(event.sessionUpdate).toBe("compaction_started");
1326
- expect(event.sessionId).toBe("test-session-123");
1327
- expect(event.trigger).toBe("auto");
1328
- expect(event.preTokens).toBe(105000);
1329
- expect(event.threshold).toBe(100000);
1330
- });
1331
-
1332
- it("compaction_started event for manual trigger should not require threshold", () => {
1333
- const event: {
1334
- sessionUpdate: string;
1335
- sessionId: string;
1336
- trigger: "manual";
1337
- preTokens: number;
1338
- threshold?: number;
1339
- } = {
1340
- sessionUpdate: "compaction_started",
1341
- sessionId: "test-session-456",
1342
- trigger: "manual",
1343
- preTokens: 80000,
1344
- };
1345
-
1346
- expect(event.sessionUpdate).toBe("compaction_started");
1347
- expect(event.trigger).toBe("manual");
1348
- expect(event.threshold).toBeUndefined();
1349
- });
1350
-
1351
- it("compaction_completed event should have correct structure", () => {
1352
- const event = {
1353
- sessionUpdate: "compaction_completed",
1354
- sessionId: "test-session-123",
1355
- trigger: "auto" as const,
1356
- preTokens: 105000,
1357
- };
1358
-
1359
- expect(event.sessionUpdate).toBe("compaction_completed");
1360
- expect(event.sessionId).toBe("test-session-123");
1361
- expect(event.trigger).toBe("auto");
1362
- expect(event.preTokens).toBe(105000);
1363
- });
1364
-
1365
- it("compaction_completed event for manual trigger", () => {
1366
- const event = {
1367
- sessionUpdate: "compaction_completed",
1368
- sessionId: "test-session-789",
1369
- trigger: "manual" as const,
1370
- preTokens: 75000,
1371
- };
1372
-
1373
- expect(event.sessionUpdate).toBe("compaction_completed");
1374
- expect(event.trigger).toBe("manual");
1375
- });
1376
- });
1377
-
1378
- describe("compaction event emission via extNotification", () => {
1379
- it("compaction_started should be emitted via extNotification with _ prefix", async () => {
1380
- // This test verifies that compaction events are emitted via extNotification
1381
- // with the _ prefix for SDK version compatibility (SDK 0.12.x vs 0.13.x)
1382
- const { ClaudeAcpAgent } = await import("../acp-agent.js");
1383
-
1384
- const extNotificationCalls: Array<{ method: string; params: any }> = [];
1385
- const mockClient = {
1386
- extNotification: async (method: string, params: any) => {
1387
- extNotificationCalls.push({ method, params });
1388
- },
1389
- } as any;
1390
-
1391
- const agent = new ClaudeAcpAgent(mockClient);
1392
-
1393
- // The expected method name includes _ prefix for SDK compatibility
1394
- // SDK 0.12.x expects "_compaction_started" and strips the prefix
1395
- // SDK 0.13.x sends without prefix but we add it for backwards compatibility
1396
- const expectedMethodName = "_compaction_started";
1397
-
1398
- // Verify the structure of the expected call
1399
- const expectedParams = {
1400
- sessionId: "test-session",
1401
- trigger: "auto",
1402
- preTokens: 105000,
1403
- threshold: 100000,
1404
- };
1405
-
1406
- expect(expectedMethodName).toBe("_compaction_started");
1407
- expect(expectedParams.sessionId).toBe("test-session");
1408
- expect(expectedParams.trigger).toBe("auto");
1409
- expect(expectedParams.preTokens).toBe(105000);
1410
- expect(expectedParams.threshold).toBe(100000);
1411
- });
1412
-
1413
- it("compaction_completed should be emitted via extNotification with _ prefix", async () => {
1414
- // Similar to compaction_started, compaction_completed uses _ prefix
1415
- const expectedMethodName = "_compaction_completed";
1416
-
1417
- const expectedParams = {
1418
- sessionId: "test-session",
1419
- trigger: "auto",
1420
- preTokens: 105000,
1421
- };
1422
-
1423
- expect(expectedMethodName).toBe("_compaction_completed");
1424
- expect(expectedParams.sessionId).toBe("test-session");
1425
- expect(expectedParams.trigger).toBe("auto");
1426
- expect(expectedParams.preTokens).toBe(105000);
1427
- });
1428
-
1429
- it("should use extNotification instead of sessionUpdate for compaction events", () => {
1430
- // Compaction events are NOT part of the standard ACP SessionUpdate schema
1431
- // They must be sent via extNotification to avoid schema validation errors
1432
- // This is a documentation test to verify the design decision
1433
-
1434
- // Standard ACP SessionUpdate types (validated by schema):
1435
- const standardSessionUpdateTypes = [
1436
- "agent_message_chunk",
1437
- "agent_tool_call_progress",
1438
- "tool_call",
1439
- "tool_result",
1440
- "result",
1441
- "available_commands_update",
1442
- ];
1443
-
1444
- // Compaction events (sent via extNotification, not sessionUpdate):
1445
- const compactionEventTypes = ["compaction_started", "compaction_completed"];
1446
-
1447
- // Verify compaction events are NOT in the standard types
1448
- for (const compactionType of compactionEventTypes) {
1449
- expect(standardSessionUpdateTypes).not.toContain(compactionType);
1450
- }
1451
- });
1452
- });
1453
-
1454
- describe("_session/setCompaction extension method", () => {
1455
- it("should return error for non-existent session", async () => {
1456
- const { ClaudeAcpAgent } = await import("../acp-agent.js");
1457
- const mockClient = {} as any;
1458
- const agent = new ClaudeAcpAgent(mockClient);
1459
-
1460
- const result = await agent.extMethod("_session/setCompaction", {
1461
- sessionId: "non-existent-session",
1462
- enabled: true,
1463
- });
1464
-
1465
- expect(result).toEqual({
1466
- success: false,
1467
- error: "Session non-existent-session not found",
1468
- });
1469
- });
1470
-
1471
- it("should accept valid compaction configuration", async () => {
1472
- // Test the structure of valid params
1473
- const params = {
1474
- sessionId: "test-session",
1475
- enabled: true,
1476
- contextTokenThreshold: 50000,
1477
- customInstructions: "Focus on code changes",
1478
- };
1479
-
1480
- expect(params.sessionId).toBe("test-session");
1481
- expect(params.enabled).toBe(true);
1482
- expect(params.contextTokenThreshold).toBe(50000);
1483
- expect(params.customInstructions).toBe("Focus on code changes");
1484
- });
1485
-
1486
- it("should accept minimal compaction configuration", async () => {
1487
- const params: {
1488
- sessionId: string;
1489
- enabled: boolean;
1490
- contextTokenThreshold?: number;
1491
- customInstructions?: string;
1492
- } = {
1493
- sessionId: "test-session",
1494
- enabled: false,
1495
- };
1496
-
1497
- expect(params.sessionId).toBe("test-session");
1498
- expect(params.enabled).toBe(false);
1499
- expect(params.contextTokenThreshold).toBeUndefined();
1500
- expect(params.customInstructions).toBeUndefined();
1501
- });
1502
- });