factory-factory 0.4.6 → 0.4.7

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 (527) hide show
  1. package/dist/client/assets/{abnfDiagram-N423BO3Z-BcUuFtOj.js → abnfDiagram-N423BO3Z-BZQ2vUo6.js} +1 -1
  2. package/dist/client/assets/{arc-Cp8_E6ha.js → arc-XI8Jpfl3.js} +1 -1
  3. package/dist/client/assets/{architectureDiagram-T3A2C74G-C3_2J0tC.js → architectureDiagram-T3A2C74G-Dt7Y1pyP.js} +1 -1
  4. package/dist/client/assets/{blockDiagram-VBNYF7ZC-Dy0jc6lP.js → blockDiagram-VBNYF7ZC-DldefwGh.js} +1 -1
  5. package/dist/client/assets/{c4Diagram-5PPSVZJV-97TkD6w-.js → c4Diagram-5PPSVZJV-Ba08x7Ef.js} +1 -1
  6. package/dist/client/assets/channel-CRP5IiHm.js +1 -0
  7. package/dist/client/assets/{chunk-2GRJ4B5K-Dc0I7ume.js → chunk-2GRJ4B5K-B9S0F-4G.js} +1 -1
  8. package/dist/client/assets/{chunk-2Q5K7J3B-DbFPWZwu.js → chunk-2Q5K7J3B-CZXgC_Jx.js} +1 -1
  9. package/dist/client/assets/{chunk-5RXB4S5H-Dci_7ZDD.js → chunk-5RXB4S5H-3z0Q5lZX.js} +1 -1
  10. package/dist/client/assets/{chunk-5VM5RSS4-Ca82Rzl0.js → chunk-5VM5RSS4-D2hwZzSy.js} +1 -1
  11. package/dist/client/assets/{chunk-6Q2QTUOP-Be2f5Q2t.js → chunk-6Q2QTUOP-DhgyUVVB.js} +1 -1
  12. package/dist/client/assets/{chunk-GF5L2VYU-C4VRs6xS.js → chunk-GF5L2VYU-B9CpXn1z.js} +1 -1
  13. package/dist/client/assets/{chunk-JWPE2WC7-DVlW0c7f.js → chunk-JWPE2WC7-C3uO_aKI.js} +1 -1
  14. package/dist/client/assets/{chunk-KBJHAD2P-BKRpW89b.js → chunk-KBJHAD2P-BclkmYso.js} +1 -1
  15. package/dist/client/assets/{chunk-RYQCIY6F-BwMw9oh9.js → chunk-RYQCIY6F-D6aZFqMZ.js} +1 -1
  16. package/dist/client/assets/{chunk-XXDRQBXY-py-FQquv.js → chunk-XXDRQBXY-BQb7-SCi.js} +1 -1
  17. package/dist/client/assets/classDiagram-JCYQIIEL-CB4-8RDd.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-OCEON4UE-CB4-8RDd.js +1 -0
  19. package/dist/client/assets/{cose-bilkent-JH36ORCC-BMCtQCZ8.js → cose-bilkent-JH36ORCC-WLzzMmoC.js} +1 -1
  20. package/dist/client/assets/{cynefin-VYW2F7L2-BTHAy6wD.js → cynefin-VYW2F7L2-D2EF0q2Q.js} +1 -1
  21. package/dist/client/assets/{cynefinDiagram-MW4NZA55-pQCQD0Ih.js → cynefinDiagram-MW4NZA55-CwoCQCrP.js} +1 -1
  22. package/dist/client/assets/{dagre-VZM6K2ZE-CZcoEFVf.js → dagre-VZM6K2ZE-Cg4AkVGB.js} +1 -1
  23. package/dist/client/assets/{diagram-7IWD3JNH-DgQv_208.js → diagram-7IWD3JNH-D9lnDmSl.js} +1 -1
  24. package/dist/client/assets/{diagram-B4RE2ZJO-DoFotcsB.js → diagram-B4RE2ZJO-AhUFMusY.js} +1 -1
  25. package/dist/client/assets/{diagram-LBJQPF4R-C5zkL1ml.js → diagram-LBJQPF4R-C81JtkuS.js} +1 -1
  26. package/dist/client/assets/{diagram-Q27KOJAE-ERKqnoHP.js → diagram-Q27KOJAE-BOzaYlQ2.js} +1 -1
  27. package/dist/client/assets/{diagram-UB23O5K3-Dyt6sy3Z.js → diagram-UB23O5K3-uXHocDB0.js} +1 -1
  28. package/dist/client/assets/{ebnfDiagram-BXEA7PRR-DqsFEAw2.js → ebnfDiagram-BXEA7PRR-Du4yOTiI.js} +1 -1
  29. package/dist/client/assets/{erDiagram-JOGREHBK-Dn8Aqkgn.js → erDiagram-JOGREHBK-BxBwtYA0.js} +1 -1
  30. package/dist/client/assets/{flowDiagram-UKHOOZJN-DcArGyH-.js → flowDiagram-UKHOOZJN-YQc_Us9R.js} +1 -1
  31. package/dist/client/assets/{ganttDiagram-PKOTCBZU-BuHaeolc.js → ganttDiagram-PKOTCBZU-CO08NXgj.js} +1 -1
  32. package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-iKWWNsQK.js → gitGraphDiagram-DS77QQ5N-NRBrIkNv.js} +1 -1
  33. package/dist/client/assets/{index-DY0TryY7.js → index-CrLTUCBe.js} +83 -83
  34. package/dist/client/assets/{infoDiagram-6WML65LV-C7IulVvo.js → infoDiagram-6WML65LV-CcOh5qQM.js} +1 -1
  35. package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-DW4cB_Nk.js → ishikawaDiagram-WSZJBQD7-Ci4gKk1n.js} +1 -1
  36. package/dist/client/assets/{journeyDiagram-NVQOT4AX-Nzsiy4H7.js → journeyDiagram-NVQOT4AX-CpW1inrw.js} +1 -1
  37. package/dist/client/assets/{kanban-definition-27J2QSJJ-BUsK9dj9.js → kanban-definition-27J2QSJJ-jez_FwZT.js} +1 -1
  38. package/dist/client/assets/{linear-CyoW-usj.js → linear-6SNETQpS.js} +1 -1
  39. package/dist/client/assets/{mindmap-definition-FAOFIHXS-Bd9cSJjQ.js → mindmap-definition-FAOFIHXS-SmrP71Hb.js} +1 -1
  40. package/dist/client/assets/{mobile-baseline-K78aE4nt.js → mobile-baseline-8VVGaFwv.js} +1 -1
  41. package/dist/client/assets/{pegDiagram-VL7TDLO6-BrmAKdiE.js → pegDiagram-VL7TDLO6-BdZpPP9I.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-7S7Q4E2Y-Ce0k6LI1.js → pieDiagram-7S7Q4E2Y-JiNW5VtU.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-_9HxOOGa.js → quadrantDiagram-CIZ2JOQS-C2VhzPor.js} +1 -1
  44. package/dist/client/assets/{railroadDiagram-AXF67PYL-ChdF1CBw.js → railroadDiagram-AXF67PYL-BdfHLYrf.js} +1 -1
  45. package/dist/client/assets/{requirementDiagram-LRYGKXZP-Bm2gdYTE.js → requirementDiagram-LRYGKXZP-BRxDcjdJ.js} +1 -1
  46. package/dist/client/assets/{sankeyDiagram-W5VNT64P-Kf7zUiC-.js → sankeyDiagram-W5VNT64P-BvibpHKV.js} +1 -1
  47. package/dist/client/assets/{sequenceDiagram-SI44F4Z6-DyPqsgh1.js → sequenceDiagram-SI44F4Z6-CstrIf8Q.js} +1 -1
  48. package/dist/client/assets/{sizeCapture-X5ZJPWSS-Cgn8Hxr2.js → sizeCapture-X5ZJPWSS-fplvtb2v.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-OKZ733FA-CJxSzxmg.js → stateDiagram-OKZ733FA-Cb0qJfhN.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-C_Uzjhvg.js +1 -0
  51. package/dist/client/assets/{swimlanes-SLNWSIFB-Ckb_izEZ.js → swimlanes-SLNWSIFB-BAqCm7Gx.js} +2 -2
  52. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-CO4t8Utk.js +8 -0
  53. package/dist/client/assets/{terminal-instance-DWySt2_t.js → terminal-instance-B0prRfF6.js} +1 -1
  54. package/dist/client/assets/{timeline-definition-Z64GVDOM-BWx_NLrK.js → timeline-definition-Z64GVDOM-BZbQ0pZK.js} +1 -1
  55. package/dist/client/assets/{vennDiagram-T6HMQDX7-BgN2-lO-.js → vennDiagram-T6HMQDX7-B3YQXfS4.js} +1 -1
  56. package/dist/client/assets/{wardleyDiagram-T6FBY63Y-C9iwoeki.js → wardleyDiagram-T6FBY63Y-Cufi2KwO.js} +1 -1
  57. package/dist/client/assets/{xychartDiagram-ELKLHX3M-B3AYy5ZN.js → xychartDiagram-ELKLHX3M-CHGxh5zQ.js} +1 -1
  58. package/dist/client/index.html +1 -1
  59. package/dist/src/backend/app-context.d.ts.map +1 -1
  60. package/dist/src/backend/app-context.js +2 -2
  61. package/dist/src/backend/app-context.js.map +1 -1
  62. package/dist/src/backend/app-context.test.js +6 -1
  63. package/dist/src/backend/app-context.test.js.map +1 -1
  64. package/dist/src/backend/clients/git.client.d.ts +0 -8
  65. package/dist/src/backend/clients/git.client.d.ts.map +1 -1
  66. package/dist/src/backend/clients/git.client.js +0 -70
  67. package/dist/src/backend/clients/git.client.js.map +1 -1
  68. package/dist/src/backend/clients/git.client.test.js +2 -178
  69. package/dist/src/backend/clients/git.client.test.js.map +1 -1
  70. package/dist/src/backend/interceptors/branch-naming.interceptor.test.js +3 -2
  71. package/dist/src/backend/interceptors/branch-naming.interceptor.test.js.map +1 -1
  72. package/dist/src/backend/lib/file-helpers.d.ts +0 -1
  73. package/dist/src/backend/lib/file-helpers.d.ts.map +1 -1
  74. package/dist/src/backend/lib/file-helpers.js +0 -27
  75. package/dist/src/backend/lib/file-helpers.js.map +1 -1
  76. package/dist/src/backend/lib/shell.d.ts +0 -4
  77. package/dist/src/backend/lib/shell.d.ts.map +1 -1
  78. package/dist/src/backend/lib/shell.js +0 -25
  79. package/dist/src/backend/lib/shell.js.map +1 -1
  80. package/dist/src/backend/routers/websocket/chat.handler.d.ts.map +1 -1
  81. package/dist/src/backend/routers/websocket/chat.handler.js +1 -17
  82. package/dist/src/backend/routers/websocket/chat.handler.js.map +1 -1
  83. package/dist/src/backend/routers/websocket/chat.handler.test.js +2 -8
  84. package/dist/src/backend/routers/websocket/chat.handler.test.js.map +1 -1
  85. package/dist/src/backend/routers/websocket/websocket.integration.test.js +0 -4
  86. package/dist/src/backend/routers/websocket/websocket.integration.test.js.map +1 -1
  87. package/dist/src/backend/server.d.ts.map +1 -1
  88. package/dist/src/backend/server.js +2 -2
  89. package/dist/src/backend/server.js.map +1 -1
  90. package/dist/src/backend/server.upgrade.test.js +10 -4
  91. package/dist/src/backend/server.upgrade.test.js.map +1 -1
  92. package/dist/src/backend/services/decision-log/resources/decision-log.accessor.d.ts +0 -2
  93. package/dist/src/backend/services/decision-log/resources/decision-log.accessor.d.ts.map +1 -1
  94. package/dist/src/backend/services/decision-log/resources/decision-log.accessor.js +0 -6
  95. package/dist/src/backend/services/decision-log/resources/decision-log.accessor.js.map +1 -1
  96. package/dist/src/backend/services/github/service/github-cli/schemas.d.ts +0 -23
  97. package/dist/src/backend/services/github/service/github-cli/schemas.d.ts.map +1 -1
  98. package/dist/src/backend/services/github/service/github-cli/schemas.js +0 -18
  99. package/dist/src/backend/services/github/service/github-cli/schemas.js.map +1 -1
  100. package/dist/src/backend/services/github/service/github-cli.service.d.ts +0 -2
  101. package/dist/src/backend/services/github/service/github-cli.service.d.ts.map +1 -1
  102. package/dist/src/backend/services/github/service/github-cli.service.js +0 -37
  103. package/dist/src/backend/services/github/service/github-cli.service.js.map +1 -1
  104. package/dist/src/backend/services/github/service/github-cli.service.test.js +3 -13
  105. package/dist/src/backend/services/github/service/github-cli.service.test.js.map +1 -1
  106. package/dist/src/backend/services/session/resources/agent-session.accessor.d.ts +0 -1
  107. package/dist/src/backend/services/session/resources/agent-session.accessor.d.ts.map +1 -1
  108. package/dist/src/backend/services/session/resources/agent-session.accessor.js +0 -8
  109. package/dist/src/backend/services/session/resources/agent-session.accessor.js.map +1 -1
  110. package/dist/src/backend/services/session/resources/agent-session.accessor.test.js +0 -10
  111. package/dist/src/backend/services/session/resources/agent-session.accessor.test.js.map +1 -1
  112. package/dist/src/backend/services/session/service/acp/acp-client-factory.d.ts +33 -0
  113. package/dist/src/backend/services/session/service/acp/acp-client-factory.d.ts.map +1 -0
  114. package/dist/src/backend/services/session/service/acp/acp-client-factory.js +274 -0
  115. package/dist/src/backend/services/session/service/acp/acp-client-factory.js.map +1 -0
  116. package/dist/src/backend/services/session/service/acp/acp-client-factory.test.d.ts +2 -0
  117. package/dist/src/backend/services/session/service/acp/acp-client-factory.test.d.ts.map +1 -0
  118. package/dist/src/backend/services/session/service/acp/acp-client-factory.test.js +454 -0
  119. package/dist/src/backend/services/session/service/acp/acp-client-factory.test.js.map +1 -0
  120. package/dist/src/backend/services/session/service/acp/acp-client-handler.d.ts.map +1 -1
  121. package/dist/src/backend/services/session/service/acp/acp-client-handler.js +17 -0
  122. package/dist/src/backend/services/session/service/acp/acp-client-handler.js.map +1 -1
  123. package/dist/src/backend/services/session/service/acp/acp-client-handler.test.js +171 -0
  124. package/dist/src/backend/services/session/service/acp/acp-client-handler.test.js.map +1 -1
  125. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.d.ts +0 -1
  126. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.d.ts.map +1 -1
  127. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.js +0 -3
  128. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.js.map +1 -1
  129. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.test.js +0 -10
  130. package/dist/src/backend/services/session/service/acp/acp-permission-bridge.test.js.map +1 -1
  131. package/dist/src/backend/services/session/service/acp/acp-process-handle.test.js +17 -0
  132. package/dist/src/backend/services/session/service/acp/acp-process-handle.test.js.map +1 -1
  133. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.d.ts +17 -0
  134. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.d.ts.map +1 -0
  135. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.js +96 -0
  136. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.js.map +1 -0
  137. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.test.d.ts +2 -0
  138. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.test.d.ts.map +1 -0
  139. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.test.js +140 -0
  140. package/dist/src/backend/services/session/service/acp/acp-prompt-controller.test.js.map +1 -0
  141. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.d.ts +8 -0
  142. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.d.ts.map +1 -0
  143. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.js +81 -0
  144. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.js.map +1 -0
  145. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.test.d.ts +2 -0
  146. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.test.d.ts.map +1 -0
  147. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.test.js +208 -0
  148. package/dist/src/backend/services/session/service/acp/acp-runtime-config-controller.test.js.map +1 -0
  149. package/dist/src/backend/services/session/service/acp/acp-runtime-contracts.d.ts +25 -0
  150. package/dist/src/backend/services/session/service/acp/acp-runtime-contracts.d.ts.map +1 -0
  151. package/dist/src/backend/services/session/service/acp/acp-runtime-contracts.js +2 -0
  152. package/dist/src/backend/services/session/service/acp/acp-runtime-contracts.js.map +1 -0
  153. package/dist/src/backend/services/session/service/acp/acp-runtime-error-handler.d.ts +5 -0
  154. package/dist/src/backend/services/session/service/acp/acp-runtime-error-handler.d.ts.map +1 -0
  155. package/dist/src/backend/services/session/service/acp/acp-runtime-error-handler.js +39 -0
  156. package/dist/src/backend/services/session/service/acp/acp-runtime-error-handler.js.map +1 -0
  157. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.d.ts +20 -0
  158. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.d.ts.map +1 -0
  159. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.js +68 -0
  160. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.js.map +1 -0
  161. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.test.d.ts +2 -0
  162. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.test.d.ts.map +1 -0
  163. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.test.js +17 -0
  164. package/dist/src/backend/services/session/service/acp/acp-runtime-errors.test.js.map +1 -0
  165. package/dist/src/backend/services/session/service/acp/acp-runtime-events.d.ts +30 -1
  166. package/dist/src/backend/services/session/service/acp/acp-runtime-events.d.ts.map +1 -1
  167. package/dist/src/backend/services/session/service/acp/acp-runtime-exit-handler.d.ts +5 -0
  168. package/dist/src/backend/services/session/service/acp/acp-runtime-exit-handler.d.ts.map +1 -0
  169. package/dist/src/backend/services/session/service/acp/acp-runtime-exit-handler.js +35 -0
  170. package/dist/src/backend/services/session/service/acp/acp-runtime-exit-handler.js.map +1 -0
  171. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.browsing.test.d.ts +2 -0
  172. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.browsing.test.d.ts.map +1 -0
  173. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.browsing.test.js +310 -0
  174. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.browsing.test.js.map +1 -0
  175. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.config.test.d.ts +2 -0
  176. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.config.test.d.ts.map +1 -0
  177. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.config.test.js +162 -0
  178. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.config.test.js.map +1 -0
  179. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.creation.test.d.ts +2 -0
  180. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.creation.test.d.ts.map +1 -0
  181. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.creation.test.js +390 -0
  182. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.creation.test.js.map +1 -0
  183. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.d.ts +18 -68
  184. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.d.ts.map +1 -1
  185. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.facade.test.d.ts +2 -0
  186. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.facade.test.d.ts.map +1 -0
  187. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.facade.test.js +59 -0
  188. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.facade.test.js.map +1 -0
  189. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.js +65 -993
  190. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.js.map +1 -1
  191. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.prompt.test.d.ts +2 -0
  192. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.prompt.test.d.ts.map +1 -0
  193. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.prompt.test.js +185 -0
  194. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.prompt.test.js.map +1 -0
  195. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.task-status.test.d.ts +2 -0
  196. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.task-status.test.d.ts.map +1 -0
  197. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.task-status.test.js +57 -0
  198. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.task-status.test.js.map +1 -0
  199. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.termination.test.d.ts +2 -0
  200. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.termination.test.d.ts.map +1 -0
  201. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.termination.test.js +392 -0
  202. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.termination.test.js.map +1 -0
  203. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-harness.d.ts +27 -0
  204. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-harness.d.ts.map +1 -0
  205. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-harness.js +96 -0
  206. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-harness.js.map +1 -0
  207. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-helpers.d.ts +59 -0
  208. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-helpers.d.ts.map +1 -0
  209. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-helpers.js +142 -0
  210. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test-helpers.js.map +1 -0
  211. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.d.ts +21 -0
  212. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.d.ts.map +1 -0
  213. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.js +112 -0
  214. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.js.map +1 -0
  215. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.test.d.ts +2 -0
  216. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.test.d.ts.map +1 -0
  217. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.test.js +142 -0
  218. package/dist/src/backend/services/session/service/acp/acp-runtime-quiescence.test.js.map +1 -0
  219. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.creation.test.d.ts +2 -0
  220. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.creation.test.d.ts.map +1 -0
  221. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.creation.test.js +333 -0
  222. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.creation.test.js.map +1 -0
  223. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.d.ts +85 -0
  224. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.d.ts.map +1 -0
  225. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.js +633 -0
  226. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.js.map +1 -0
  227. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.status.test.d.ts +2 -0
  228. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.status.test.d.ts.map +1 -0
  229. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.status.test.js +99 -0
  230. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.status.test.js.map +1 -0
  231. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.termination.test.d.ts +2 -0
  232. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.termination.test.d.ts.map +1 -0
  233. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.termination.test.js +490 -0
  234. package/dist/src/backend/services/session/service/acp/acp-runtime-supervisor.termination.test.js.map +1 -0
  235. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.d.ts +9 -0
  236. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.d.ts.map +1 -0
  237. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.js +96 -0
  238. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.js.map +1 -0
  239. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.test.d.ts +2 -0
  240. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.test.d.ts.map +1 -0
  241. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.test.js +171 -0
  242. package/dist/src/backend/services/session/service/acp/acp-subagent-browser.test.js.map +1 -0
  243. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts +1 -1
  244. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts.map +1 -1
  245. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js +14 -6
  246. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js.map +1 -1
  247. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.notification-ordering.test.d.ts +2 -0
  248. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.notification-ordering.test.d.ts.map +1 -0
  249. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.notification-ordering.test.js +265 -0
  250. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.notification-ordering.test.js.map +1 -0
  251. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js +32 -14
  252. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js.map +1 -1
  253. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.d.ts +7 -0
  254. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.d.ts.map +1 -0
  255. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.js +98 -0
  256. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.js.map +1 -0
  257. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.test.d.ts +2 -0
  258. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.test.d.ts.map +1 -0
  259. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.test.js +148 -0
  260. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-notification-queue.test.js.map +1 -0
  261. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-subagent-mapper.test.js +10 -0
  262. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-subagent-mapper.test.js.map +1 -1
  263. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.d.ts +72 -0
  264. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.d.ts.map +1 -1
  265. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.js +46 -1
  266. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.js.map +1 -1
  267. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.test.js +39 -0
  268. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/codex-zod.test.js.map +1 -1
  269. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.d.ts +10 -1
  270. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.d.ts.map +1 -1
  271. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.js +149 -17
  272. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.js.map +1 -1
  273. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.test.js +348 -19
  274. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/stream-event-handler.test.js.map +1 -1
  275. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/task-status-protocol.d.ts +8 -0
  276. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/task-status-protocol.d.ts.map +1 -0
  277. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/task-status-protocol.js +9 -0
  278. package/dist/src/backend/services/session/service/acp/codex-app-server-adapter/task-status-protocol.js.map +1 -0
  279. package/dist/src/backend/services/session/service/acp/index.d.ts +2 -2
  280. package/dist/src/backend/services/session/service/acp/index.d.ts.map +1 -1
  281. package/dist/src/backend/services/session/service/acp/index.js +1 -0
  282. package/dist/src/backend/services/session/service/acp/index.js.map +1 -1
  283. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.d.ts.map +1 -1
  284. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.js +9 -1
  285. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.js.map +1 -1
  286. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.recovery.test.d.ts +2 -0
  287. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.recovery.test.d.ts.map +1 -0
  288. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.recovery.test.js +195 -0
  289. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.recovery.test.js.map +1 -0
  290. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.test.js +1 -23
  291. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/load-session.handler.test.js.map +1 -1
  292. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/queue-message.handler.test.js +0 -6
  293. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/queue-message.handler.test.js.map +1 -1
  294. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.js +1 -1
  295. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.js.map +1 -1
  296. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.test.js +1 -1
  297. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-config-option.handler.test.js.map +1 -1
  298. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.js +1 -1
  299. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.js.map +1 -1
  300. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.test.js +1 -1
  301. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/set-thinking-budget.handler.test.js.map +1 -1
  302. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.d.ts +4 -2
  303. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.d.ts.map +1 -1
  304. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.js +2 -7
  305. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.js.map +1 -1
  306. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.test.js +9 -11
  307. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/start.handler.test.js.map +1 -1
  308. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.js +1 -1
  309. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.js.map +1 -1
  310. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.test.js +1 -3
  311. package/dist/src/backend/services/session/service/chat/chat-message-handlers/handlers/stop.handler.test.js.map +1 -1
  312. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.d.ts.map +1 -1
  313. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.js +3 -2
  314. package/dist/src/backend/services/session/service/chat/chat-message-handlers/registry.js.map +1 -1
  315. package/dist/src/backend/services/session/service/chat/chat-message-handlers/types.d.ts +24 -8
  316. package/dist/src/backend/services/session/service/chat/chat-message-handlers/types.d.ts.map +1 -1
  317. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.d.ts +14 -15
  318. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.d.ts.map +1 -1
  319. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js +56 -114
  320. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.js.map +1 -1
  321. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js +49 -218
  322. package/dist/src/backend/services/session/service/chat/chat-message-handlers.service.test.js.map +1 -1
  323. package/dist/src/backend/services/session/service/data/session-data.service.d.ts +0 -2
  324. package/dist/src/backend/services/session/service/data/session-data.service.d.ts.map +1 -1
  325. package/dist/src/backend/services/session/service/data/session-data.service.js +0 -6
  326. package/dist/src/backend/services/session/service/data/session-data.service.js.map +1 -1
  327. package/dist/src/backend/services/session/service/data/session-data.service.test.js +0 -6
  328. package/dist/src/backend/services/session/service/data/session-data.service.test.js.map +1 -1
  329. package/dist/src/backend/services/session/service/index.d.ts +3 -4
  330. package/dist/src/backend/services/session/service/index.d.ts.map +1 -1
  331. package/dist/src/backend/services/session/service/index.js +2 -2
  332. package/dist/src/backend/services/session/service/index.js.map +1 -1
  333. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.d.ts.map +1 -1
  334. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.js +9 -0
  335. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.js.map +1 -1
  336. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.subagents.test.js +47 -0
  337. package/dist/src/backend/services/session/service/lifecycle/acp-event-processor.subagents.test.js.map +1 -1
  338. package/dist/src/backend/services/session/service/lifecycle/session-context.service.d.ts +33 -0
  339. package/dist/src/backend/services/session/service/lifecycle/session-context.service.d.ts.map +1 -0
  340. package/dist/src/backend/services/session/service/lifecycle/session-context.service.js +120 -0
  341. package/dist/src/backend/services/session/service/lifecycle/session-context.service.js.map +1 -0
  342. package/dist/src/backend/services/session/service/lifecycle/session-context.service.test.d.ts +2 -0
  343. package/dist/src/backend/services/session/service/lifecycle/session-context.service.test.d.ts.map +1 -0
  344. package/dist/src/backend/services/session/service/lifecycle/session-context.service.test.js +174 -0
  345. package/dist/src/backend/services/session/service/lifecycle/session-context.service.test.js.map +1 -0
  346. package/dist/src/backend/services/session/service/lifecycle/session-core-services.d.ts +23 -0
  347. package/dist/src/backend/services/session/service/lifecycle/session-core-services.d.ts.map +1 -0
  348. package/dist/src/backend/services/session/service/lifecycle/session-core-services.js +150 -0
  349. package/dist/src/backend/services/session/service/lifecycle/session-core-services.js.map +1 -0
  350. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.d.ts +5 -0
  351. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.d.ts.map +1 -0
  352. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.js +38 -0
  353. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.js.map +1 -0
  354. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.test.d.ts +2 -0
  355. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.test.d.ts.map +1 -0
  356. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.test.js +52 -0
  357. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-external-ports.test.js.map +1 -0
  358. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.d.ts +35 -0
  359. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.d.ts.map +1 -0
  360. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.js +120 -0
  361. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.js.map +1 -0
  362. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.test.d.ts +2 -0
  363. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.test.d.ts.map +1 -0
  364. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.test.js +192 -0
  365. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle-gate.test.js.map +1 -0
  366. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.test-helpers.d.ts +115 -0
  367. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.test-helpers.d.ts.map +1 -0
  368. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.test-helpers.js +434 -0
  369. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.test-helpers.js.map +1 -0
  370. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.types.d.ts +13 -0
  371. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.types.d.ts.map +1 -0
  372. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.types.js +2 -0
  373. package/dist/src/backend/services/session/service/lifecycle/session-lifecycle.types.js.map +1 -0
  374. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.d.ts +81 -0
  375. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.d.ts.map +1 -0
  376. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.js +242 -0
  377. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.js.map +1 -0
  378. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.test.d.ts +2 -0
  379. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.test.d.ts.map +1 -0
  380. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.test.js +528 -0
  381. package/dist/src/backend/services/session/service/lifecycle/session-notification-delivery.service.test.js.map +1 -0
  382. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.d.ts +39 -0
  383. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.d.ts.map +1 -0
  384. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.js +208 -0
  385. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.js.map +1 -0
  386. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.test.d.ts +2 -0
  387. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.test.d.ts.map +1 -0
  388. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.test.js +274 -0
  389. package/dist/src/backend/services/session/service/lifecycle/session-runtime-exit.coordinator.test.js.map +1 -0
  390. package/dist/src/backend/services/session/service/lifecycle/session-services.composition.test.d.ts +2 -0
  391. package/dist/src/backend/services/session/service/lifecycle/session-services.composition.test.d.ts.map +1 -0
  392. package/dist/src/backend/services/session/service/lifecycle/session-services.composition.test.js +105 -0
  393. package/dist/src/backend/services/session/service/lifecycle/session-services.composition.test.js.map +1 -0
  394. package/dist/src/backend/services/session/service/lifecycle/session-services.d.ts +5 -17
  395. package/dist/src/backend/services/session/service/lifecycle/session-services.d.ts.map +1 -1
  396. package/dist/src/backend/services/session/service/lifecycle/session-services.js +14 -87
  397. package/dist/src/backend/services/session/service/lifecycle/session-services.js.map +1 -1
  398. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.d.ts +64 -0
  399. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.d.ts.map +1 -0
  400. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.js +352 -0
  401. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.js.map +1 -0
  402. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.test.d.ts +2 -0
  403. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.test.d.ts.map +1 -0
  404. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.test.js +702 -0
  405. package/dist/src/backend/services/session/service/lifecycle/session-startup.coordinator.test.js.map +1 -0
  406. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.d.ts +54 -0
  407. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.d.ts.map +1 -0
  408. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.js +265 -0
  409. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.js.map +1 -0
  410. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.test.d.ts +2 -0
  411. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.test.d.ts.map +1 -0
  412. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.test.js +514 -0
  413. package/dist/src/backend/services/session/service/lifecycle/session-termination.coordinator.test.js.map +1 -0
  414. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.d.ts +62 -0
  415. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.d.ts.map +1 -0
  416. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.js +175 -0
  417. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.js.map +1 -0
  418. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.test.d.ts +2 -0
  419. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.test.d.ts.map +1 -0
  420. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.test.js +294 -0
  421. package/dist/src/backend/services/session/service/lifecycle/session-workflow-finalizer.test.js.map +1 -0
  422. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.facade.test.d.ts +2 -0
  423. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.facade.test.d.ts.map +1 -0
  424. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.facade.test.js +431 -0
  425. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.facade.test.js.map +1 -0
  426. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.d.ts +24 -116
  427. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.d.ts.map +1 -1
  428. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js +47 -1168
  429. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.js.map +1 -1
  430. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.js +11 -6
  431. package/dist/src/backend/services/session/service/lifecycle/session.prompt.service.test.js.map +1 -1
  432. package/dist/src/backend/services/session/service/lifecycle/session.service.d.ts +3 -6
  433. package/dist/src/backend/services/session/service/lifecycle/session.service.d.ts.map +1 -1
  434. package/dist/src/backend/services/session/service/lifecycle/session.service.js +9 -12
  435. package/dist/src/backend/services/session/service/lifecycle/session.service.js.map +1 -1
  436. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js +44 -35
  437. package/dist/src/backend/services/session/service/lifecycle/session.service.test.js.map +1 -1
  438. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.d.ts +3 -0
  439. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.d.ts.map +1 -0
  440. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.js +92 -0
  441. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.js.map +1 -0
  442. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.test.d.ts +2 -0
  443. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.test.d.ts.map +1 -0
  444. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.test.js +81 -0
  445. package/dist/src/backend/services/session/service/store/session-tool-call-recovery.test.js.map +1 -0
  446. package/dist/src/backend/services/workspace/resources/project.accessor.d.ts +0 -1
  447. package/dist/src/backend/services/workspace/resources/project.accessor.d.ts.map +1 -1
  448. package/dist/src/backend/services/workspace/resources/project.accessor.js +0 -13
  449. package/dist/src/backend/services/workspace/resources/project.accessor.js.map +1 -1
  450. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts +0 -1
  451. package/dist/src/backend/services/workspace/resources/workspace.accessor.d.ts.map +1 -1
  452. package/dist/src/backend/services/workspace/resources/workspace.accessor.js +0 -10
  453. package/dist/src/backend/services/workspace/resources/workspace.accessor.js.map +1 -1
  454. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js +3 -8
  455. package/dist/src/backend/services/workspace/resources/workspace.accessor.test.js.map +1 -1
  456. package/dist/src/backend/services/workspace/service/index.d.ts +9 -10
  457. package/dist/src/backend/services/workspace/service/index.d.ts.map +1 -1
  458. package/dist/src/backend/services/workspace/service/index.js +5 -5
  459. package/dist/src/backend/services/workspace/service/index.js.map +1 -1
  460. package/dist/src/backend/services/workspace/service/lifecycle/data.service.d.ts +4 -4
  461. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js +1 -7
  462. package/dist/src/backend/services/workspace/service/workspace-domain-exports.test.js.map +1 -1
  463. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.test.js +0 -1
  464. package/dist/src/backend/services/workspace/service/worktree/git-ops.service.test.js.map +1 -1
  465. package/dist/src/backend/testing/npm-publish-workflow.test.d.ts +2 -0
  466. package/dist/src/backend/testing/npm-publish-workflow.test.d.ts.map +1 -0
  467. package/dist/src/backend/testing/npm-publish-workflow.test.js +205 -0
  468. package/dist/src/backend/testing/npm-publish-workflow.test.js.map +1 -0
  469. package/dist/src/backend/trpc/index.d.ts +2 -18
  470. package/dist/src/backend/trpc/index.d.ts.map +1 -1
  471. package/dist/src/backend/trpc/pr-review.router.test.js +1 -12
  472. package/dist/src/backend/trpc/pr-review.router.test.js.map +1 -1
  473. package/dist/src/backend/trpc/pr-review.trpc.d.ts +0 -16
  474. package/dist/src/backend/trpc/pr-review.trpc.d.ts.map +1 -1
  475. package/dist/src/backend/trpc/pr-review.trpc.js +0 -14
  476. package/dist/src/backend/trpc/pr-review.trpc.js.map +1 -1
  477. package/dist/src/backend/trpc/session.router.test.js +13 -37
  478. package/dist/src/backend/trpc/session.router.test.js.map +1 -1
  479. package/dist/src/backend/trpc/workspace.router.test.js +41 -2
  480. package/dist/src/backend/trpc/workspace.router.test.js.map +1 -1
  481. package/dist/src/backend/trpc/workspace.trpc.d.ts +4 -4
  482. package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
  483. package/dist/src/backend/trpc/workspace.trpc.js +12 -1
  484. package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
  485. package/dist/src/lib/chat-protocol.d.ts +72 -0
  486. package/dist/src/lib/chat-protocol.d.ts.map +1 -0
  487. package/dist/src/lib/chat-protocol.js +514 -0
  488. package/dist/src/lib/chat-protocol.js.map +1 -0
  489. package/dist/src/test-utils/application-graph.d.ts.map +1 -1
  490. package/dist/src/test-utils/application-graph.js +1 -0
  491. package/dist/src/test-utils/application-graph.js.map +1 -1
  492. package/dist/tsconfig.backend.tsbuildinfo +1 -1
  493. package/package.json +6 -3
  494. package/scripts/postinstall.mjs +6 -2
  495. package/dist/client/assets/channel-DLBBfejH.js +0 -1
  496. package/dist/client/assets/classDiagram-JCYQIIEL-Ds5wVQR3.js +0 -1
  497. package/dist/client/assets/classDiagram-v2-OCEON4UE-Ds5wVQR3.js +0 -1
  498. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-BwUaUW2J.js +0 -1
  499. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-D87lLmuW.js +0 -8
  500. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.d.ts +0 -2
  501. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.d.ts.map +0 -1
  502. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.js +0 -1736
  503. package/dist/src/backend/services/session/service/acp/acp-runtime-manager.test.js.map +0 -1
  504. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.d.ts +0 -2
  505. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.d.ts.map +0 -1
  506. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js +0 -1520
  507. package/dist/src/backend/services/session/service/lifecycle/session.lifecycle.service.test.js.map +0 -1
  508. package/dist/src/backend/services/session/service/runtime/index.d.ts +0 -5
  509. package/dist/src/backend/services/session/service/runtime/index.d.ts.map +0 -1
  510. package/dist/src/backend/services/session/service/runtime/index.js +0 -2
  511. package/dist/src/backend/services/session/service/runtime/index.js.map +0 -1
  512. package/dist/src/backend/services/session/service/runtime/provider-runtime-manager.d.ts +0 -21
  513. package/dist/src/backend/services/session/service/runtime/provider-runtime-manager.d.ts.map +0 -1
  514. package/dist/src/backend/services/session/service/runtime/provider-runtime-manager.js +0 -2
  515. package/dist/src/backend/services/session/service/runtime/provider-runtime-manager.js.map +0 -1
  516. package/dist/src/backend/services/session/service/store/file-lock.service.d.ts +0 -97
  517. package/dist/src/backend/services/session/service/store/file-lock.service.d.ts.map +0 -1
  518. package/dist/src/backend/services/session/service/store/file-lock.service.js +0 -429
  519. package/dist/src/backend/services/session/service/store/file-lock.service.js.map +0 -1
  520. package/dist/src/backend/services/session/service/store/file-lock.service.test.d.ts +0 -2
  521. package/dist/src/backend/services/session/service/store/file-lock.service.test.d.ts.map +0 -1
  522. package/dist/src/backend/services/session/service/store/file-lock.service.test.js +0 -672
  523. package/dist/src/backend/services/session/service/store/file-lock.service.test.js.map +0 -1
  524. package/dist/src/shared/workspace-words.d.ts +0 -5
  525. package/dist/src/shared/workspace-words.d.ts.map +0 -1
  526. package/dist/src/shared/workspace-words.js +0 -146
  527. package/dist/src/shared/workspace-words.js.map +0 -1
@@ -1,1736 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import { tmpdir } from 'node:os';
3
- import { PassThrough } from 'node:stream';
4
- import { beforeEach, describe, expect, it, vi } from 'vitest';
5
- const { mockSpawn, mockInitialize, mockLoadSession, mockNewSession, mockPrompt, mockCancel, mockSetSessionConfigOption, mockSetSessionMode, mockSetSessionModel, mockExtMethod, mockNdJsonStream, } = vi.hoisted(() => ({
6
- mockSpawn: vi.fn(),
7
- mockInitialize: vi.fn(),
8
- mockLoadSession: vi.fn(),
9
- mockNewSession: vi.fn(),
10
- mockPrompt: vi.fn(),
11
- mockCancel: vi.fn(),
12
- mockSetSessionConfigOption: vi.fn(),
13
- mockSetSessionMode: vi.fn(),
14
- mockSetSessionModel: vi.fn(),
15
- mockExtMethod: vi.fn(),
16
- mockNdJsonStream: vi
17
- .fn()
18
- .mockReturnValue({ writable: {}, readable: { pipeThrough: () => ({}) } }),
19
- }));
20
- vi.mock('node:child_process', () => ({
21
- spawn: (...args) => mockSpawn(...args),
22
- }));
23
- vi.mock('@agentclientprotocol/sdk', () => {
24
- class MockCSC {
25
- toClient;
26
- initialize = mockInitialize;
27
- loadSession = mockLoadSession;
28
- newSession = mockNewSession;
29
- prompt = mockPrompt;
30
- cancel = mockCancel;
31
- setSessionConfigOption = mockSetSessionConfigOption;
32
- setSessionMode = mockSetSessionMode;
33
- unstable_setSessionModel = mockSetSessionModel;
34
- extMethod = mockExtMethod;
35
- constructor(toClient, _stream) {
36
- this.toClient = toClient;
37
- }
38
- }
39
- return {
40
- ClientSideConnection: MockCSC,
41
- ndJsonStream: (...args) => mockNdJsonStream(...args),
42
- PROTOCOL_VERSION: 1,
43
- };
44
- });
45
- vi.mock('@/backend/services/logger.service', () => ({
46
- createLogger: () => ({
47
- info: vi.fn(),
48
- debug: vi.fn(),
49
- warn: vi.fn(),
50
- error: vi.fn(),
51
- }),
52
- getCurrentProcessEnv: () => ({ ...process.env }),
53
- }));
54
- import { SUBAGENTS_CAPABILITY_META_KEY, SUBAGENTS_LIST_METHOD, SUBAGENTS_READ_METHOD, } from '../../../../../shared/acp-protocol/subagents.js';
55
- import { AcpClientHandler } from './acp-client-handler.js';
56
- import { AcpRuntimeManager, PromptTimeoutError } from './acp-runtime-manager.js';
57
- describe('PromptTimeoutError', () => {
58
- it('retains the caller-specified timeout for durable classification', () => {
59
- const error = new PromptTimeoutError('session-1', 300_000);
60
- expect(error.timeoutMs).toBe(300_000);
61
- });
62
- });
63
- function createMockChildProcess() {
64
- const child = new EventEmitter();
65
- child.pid = 12_345;
66
- child.exitCode = null;
67
- child.signalCode = null;
68
- child.killed = false;
69
- child.kill = vi.fn((signal) => {
70
- if (signal) {
71
- child.killed = true;
72
- }
73
- if (signal === 'SIGKILL') {
74
- child.exitCode = 137;
75
- child.emit('exit', 137, 'SIGKILL');
76
- }
77
- return true;
78
- });
79
- child.stdout = new PassThrough();
80
- child.stderr = new PassThrough();
81
- child.stdin = new PassThrough();
82
- return child;
83
- }
84
- function exitChildAfterSigterm(child) {
85
- child.kill = vi.fn((signal) => {
86
- if (signal === 'SIGTERM') {
87
- queueMicrotask(() => {
88
- child.signalCode = 'SIGTERM';
89
- child.emit('exit', null, 'SIGTERM');
90
- });
91
- }
92
- return true;
93
- });
94
- }
95
- function defaultOptions() {
96
- return {
97
- provider: 'CLAUDE',
98
- workingDir: '/tmp/workspace',
99
- sessionId: 'test-session-1',
100
- };
101
- }
102
- function codexOptions() {
103
- return {
104
- provider: 'CODEX',
105
- workingDir: '/tmp/workspace',
106
- sessionId: 'test-session-1',
107
- };
108
- }
109
- function defaultHandlers() {
110
- return {
111
- onSessionId: vi.fn().mockResolvedValue(undefined),
112
- onExit: vi.fn().mockResolvedValue(undefined),
113
- onError: vi.fn(),
114
- onAcpEvent: vi.fn(),
115
- };
116
- }
117
- function defaultContext() {
118
- return { workspaceId: 'w1', workingDir: '/tmp/workspace' };
119
- }
120
- function defaultConfigOptions() {
121
- return [
122
- {
123
- id: 'model',
124
- name: 'Model',
125
- type: 'select',
126
- category: 'model',
127
- currentValue: 'sonnet',
128
- options: [
129
- { value: 'sonnet', name: 'Sonnet' },
130
- { value: 'opus', name: 'Opus' },
131
- ],
132
- },
133
- {
134
- id: 'mode',
135
- name: 'Mode',
136
- type: 'select',
137
- category: 'mode',
138
- currentValue: 'default',
139
- options: [
140
- { value: 'default', name: 'Default' },
141
- { value: 'plan', name: 'Plan' },
142
- ],
143
- },
144
- ];
145
- }
146
- function setupSuccessfulSpawn(agentCapabilities = { loadSession: {} }) {
147
- const child = createMockChildProcess();
148
- mockSpawn.mockReturnValue(child);
149
- mockInitialize.mockResolvedValue({
150
- protocolVersion: 1,
151
- agentCapabilities,
152
- agentInfo: { name: 'claude-agent-acp' },
153
- });
154
- mockNewSession.mockResolvedValue({
155
- sessionId: 'provider-session-123',
156
- configOptions: defaultConfigOptions(),
157
- });
158
- mockLoadSession.mockResolvedValue({
159
- configOptions: defaultConfigOptions(),
160
- });
161
- mockSetSessionConfigOption.mockResolvedValue({
162
- configOptions: defaultConfigOptions(),
163
- });
164
- mockSetSessionMode.mockResolvedValue({});
165
- mockSetSessionModel.mockResolvedValue({});
166
- return child;
167
- }
168
- function subagentBrowseCapabilities() {
169
- return {
170
- loadSession: {},
171
- _meta: {
172
- [SUBAGENTS_CAPABILITY_META_KEY]: {
173
- version: 1,
174
- list: true,
175
- read: true,
176
- notifications: true,
177
- },
178
- },
179
- };
180
- }
181
- function createDeferred() {
182
- let resolvePromise;
183
- let rejectPromise;
184
- const promise = new Promise((resolve, reject) => {
185
- resolvePromise = resolve;
186
- rejectPromise = reject;
187
- });
188
- return { promise, resolve: resolvePromise, reject: rejectPromise };
189
- }
190
- describe('AcpRuntimeManager', () => {
191
- let manager;
192
- beforeEach(() => {
193
- manager = new AcpRuntimeManager();
194
- });
195
- describe('getOrCreateClient', () => {
196
- it('rejects before spawn when workingDir is empty', async () => {
197
- await expect(manager.getOrCreateClient('session-empty-cwd', { ...defaultOptions(), workingDir: '' }, defaultHandlers(), defaultContext())).rejects.toThrow('ACP working directory is required before spawning adapter process');
198
- expect(mockSpawn).not.toHaveBeenCalled();
199
- });
200
- it('rejects before spawn when workingDir is whitespace only', async () => {
201
- await expect(manager.getOrCreateClient('session-whitespace-cwd', { ...defaultOptions(), workingDir: ' ' }, defaultHandlers(), defaultContext())).rejects.toThrow('ACP working directory is required before spawning adapter process');
202
- expect(mockSpawn).not.toHaveBeenCalled();
203
- });
204
- it('spawns subprocess with detached:false, wires streams, initializes, creates session, returns handle', async () => {
205
- setupSuccessfulSpawn();
206
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
207
- expect(mockSpawn).toHaveBeenCalledTimes(1);
208
- const spawnArgs = mockSpawn.mock.calls[0];
209
- expect(spawnArgs[1]).toEqual([]);
210
- expect(spawnArgs[2]).toMatchObject({
211
- cwd: '/tmp/workspace',
212
- stdio: ['pipe', 'pipe', 'pipe'],
213
- detached: false,
214
- });
215
- expect(mockInitialize).toHaveBeenCalledTimes(1);
216
- expect(mockInitialize).toHaveBeenCalledWith(expect.objectContaining({
217
- protocolVersion: 1,
218
- clientCapabilities: {},
219
- clientInfo: expect.objectContaining({
220
- name: 'factory-factory',
221
- }),
222
- }));
223
- expect(mockNewSession).toHaveBeenCalledTimes(1);
224
- expect(mockNewSession).toHaveBeenCalledWith(expect.objectContaining({
225
- cwd: '/tmp/workspace',
226
- mcpServers: [],
227
- }));
228
- expect(handle.providerSessionId).toBe('provider-session-123');
229
- expect(handle.agentCapabilities).toEqual({ loadSession: {} });
230
- expect(handle.isPromptInFlight).toBe(false);
231
- expect(handle.isRunning()).toBe(true);
232
- expect(handle.getPid()).toBe(12_345);
233
- });
234
- it('spawns CODEX provider using internal CLI adapter command', async () => {
235
- setupSuccessfulSpawn();
236
- await manager.getOrCreateClient('session-1', codexOptions(), defaultHandlers(), defaultContext());
237
- expect(mockSpawn).toHaveBeenCalledTimes(1);
238
- const spawnArgs = mockSpawn.mock.calls[0];
239
- expect(spawnArgs[1]).toContain('internal');
240
- expect(spawnArgs[1]).toContain('codex-app-server-acp');
241
- expect(spawnArgs[1].some((arg) => arg.endsWith('src/cli/index.ts') || arg.endsWith('dist/src/cli/index.js'))).toBe(true);
242
- expect(typeof spawnArgs[0]).toBe('string');
243
- expect(spawnArgs[0].length).toBeGreaterThan(0);
244
- expect(spawnArgs[2].env?.DOTENV_CONFIG_QUIET).toBe('true');
245
- if (spawnArgs[0].endsWith('tsx') ||
246
- spawnArgs[0].endsWith('tsx.cmd')) {
247
- expect(spawnArgs[1]).toContain('--tsconfig');
248
- expect(spawnArgs[1].some((arg) => arg.endsWith('tsconfig.json'))).toBe(true);
249
- }
250
- expect(spawnArgs[2]).toMatchObject({
251
- cwd: '/tmp/workspace',
252
- stdio: ['pipe', 'pipe', 'pipe'],
253
- detached: false,
254
- });
255
- });
256
- it('resolves CODEX internal adapter from module location when cwd is outside repo', async () => {
257
- setupSuccessfulSpawn();
258
- const originalCwd = process.cwd();
259
- process.chdir(tmpdir());
260
- try {
261
- await manager.getOrCreateClient('session-1', codexOptions(), defaultHandlers(), defaultContext());
262
- }
263
- finally {
264
- process.chdir(originalCwd);
265
- }
266
- expect(mockSpawn).toHaveBeenCalledTimes(1);
267
- const spawnArgs = mockSpawn.mock.calls[0];
268
- const command = spawnArgs[0];
269
- const args = spawnArgs[1];
270
- expect(command.length).toBeGreaterThan(0);
271
- expect(args).toContain('internal');
272
- expect(args).toContain('codex-app-server-acp');
273
- if (command.endsWith('tsx') || command.endsWith('tsx.cmd')) {
274
- expect(args).toContain('--tsconfig');
275
- expect(args.some((arg) => arg.endsWith('tsconfig.json'))).toBe(true);
276
- }
277
- expect(args.some((arg) => arg.endsWith('src/cli/index.ts') || arg.endsWith('dist/src/cli/index.js'))).toBe(true);
278
- });
279
- it('rejects cleanly when ACP binary spawn fails (ENOENT)', async () => {
280
- const child = createMockChildProcess();
281
- mockSpawn.mockReturnValue(child);
282
- mockInitialize.mockImplementation(() => new Promise(() => {
283
- }));
284
- vi.useFakeTimers();
285
- try {
286
- const handlers = defaultHandlers();
287
- const createResult = manager
288
- .getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext())
289
- .then((handle) => ({ handle }), (error) => ({ error }));
290
- let creationSettled = false;
291
- void createResult.then(() => {
292
- creationSettled = true;
293
- });
294
- await vi.advanceTimersByTimeAsync(0);
295
- expect(mockSpawn).toHaveBeenCalledTimes(1);
296
- const spawnError = Object.assign(new Error('spawn claude-agent-acp ENOENT'), {
297
- code: 'ENOENT',
298
- });
299
- child.emit('error', spawnError);
300
- await vi.advanceTimersByTimeAsync(0);
301
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
302
- child.emit('close', -2, null);
303
- await vi.advanceTimersByTimeAsync(0);
304
- expect(creationSettled).toBe(true);
305
- await expect(createResult).resolves.toMatchObject({
306
- error: {
307
- message: expect.stringMatching(/Failed to spawn ACP adapter ".*": spawn claude-agent-acp ENOENT/),
308
- },
309
- });
310
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
311
- expect(handlers.onError).toHaveBeenCalledWith('session-1', expect.any(Error));
312
- }
313
- finally {
314
- await vi.advanceTimersByTimeAsync(5000);
315
- vi.useRealTimers();
316
- }
317
- });
318
- it('allows the subprocess to exit during the SIGTERM grace period after initialization fails', async () => {
319
- const child = createMockChildProcess();
320
- exitChildAfterSigterm(child);
321
- mockSpawn.mockReturnValue(child);
322
- mockInitialize.mockRejectedValue(new Error('handshake failed'));
323
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('handshake failed');
324
- expect(child.kill).toHaveBeenCalledTimes(1);
325
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
326
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
327
- expect(mockNewSession).not.toHaveBeenCalled();
328
- });
329
- it('does not signal a subprocess that already terminated from a signal', async () => {
330
- const child = createMockChildProcess();
331
- child.signalCode = 'SIGTERM';
332
- mockSpawn.mockReturnValue(child);
333
- mockInitialize.mockRejectedValue(new Error('handshake failed'));
334
- vi.useFakeTimers();
335
- try {
336
- const creationPromise = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
337
- const creationRejection = creationPromise.catch((error) => error);
338
- await vi.advanceTimersByTimeAsync(5000);
339
- await expect(creationRejection).resolves.toMatchObject({ message: 'handshake failed' });
340
- expect(child.kill).not.toHaveBeenCalled();
341
- }
342
- finally {
343
- vi.useRealTimers();
344
- }
345
- });
346
- it('escalates failed initialization cleanup to SIGKILL after the grace period', async () => {
347
- const child = createMockChildProcess();
348
- mockSpawn.mockReturnValue(child);
349
- mockInitialize.mockRejectedValue(new Error('handshake failed'));
350
- vi.useFakeTimers();
351
- try {
352
- const creationPromise = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
353
- const creationRejection = creationPromise.catch((error) => error);
354
- await vi.advanceTimersByTimeAsync(0);
355
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
356
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
357
- await vi.advanceTimersByTimeAsync(4999);
358
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
359
- await vi.advanceTimersByTimeAsync(1);
360
- await expect(creationRejection).resolves.toMatchObject({ message: 'handshake failed' });
361
- expect(child.kill).toHaveBeenCalledWith('SIGKILL');
362
- }
363
- finally {
364
- vi.useRealTimers();
365
- }
366
- });
367
- it('times out when ACP initialize handshake never resolves', async () => {
368
- manager.setAcpStartupTimeoutMs(20);
369
- const child = createMockChildProcess();
370
- exitChildAfterSigterm(child);
371
- mockSpawn.mockReturnValue(child);
372
- mockInitialize.mockImplementation(() => new Promise(() => {
373
- }));
374
- await expect(manager.getOrCreateClient('session-timeout-init', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('ACP initialize handshake timed out');
375
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
376
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
377
- });
378
- it('times out when ACP session creation never resolves', async () => {
379
- manager.setAcpStartupTimeoutMs(20);
380
- const child = createMockChildProcess();
381
- exitChildAfterSigterm(child);
382
- mockSpawn.mockReturnValue(child);
383
- mockInitialize.mockResolvedValue({
384
- protocolVersion: 1,
385
- agentCapabilities: { loadSession: {} },
386
- agentInfo: { name: 'claude-agent-acp' },
387
- });
388
- mockNewSession.mockImplementation(() => new Promise(() => {
389
- }));
390
- await expect(manager.getOrCreateClient('session-timeout-new-session', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('ACP session creation timed out');
391
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
392
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
393
- });
394
- it('returns existing handle if session already exists and is running', async () => {
395
- setupSuccessfulSpawn();
396
- const handle1 = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
397
- const handle2 = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
398
- expect(handle1).toBe(handle2);
399
- expect(mockSpawn).toHaveBeenCalledTimes(1);
400
- });
401
- it('deduplicates concurrent creation for same sessionId', async () => {
402
- const child = createMockChildProcess();
403
- mockSpawn.mockReturnValue(child);
404
- let resolveInit;
405
- mockInitialize.mockReturnValue(new Promise((resolve) => {
406
- resolveInit = resolve;
407
- }));
408
- mockNewSession.mockResolvedValue({
409
- sessionId: 'provider-session-123',
410
- configOptions: defaultConfigOptions(),
411
- });
412
- const first = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
413
- const second = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
414
- await new Promise((r) => setTimeout(r, 10));
415
- resolveInit({
416
- protocolVersion: 1,
417
- agentCapabilities: {},
418
- agentInfo: { name: 'test' },
419
- });
420
- const [h1, h2] = await Promise.all([first, second]);
421
- expect(h1).toBe(h2);
422
- expect(mockSpawn).toHaveBeenCalledTimes(1);
423
- });
424
- it('calls onSessionId handler with provider session ID', async () => {
425
- setupSuccessfulSpawn();
426
- const handlers = defaultHandlers();
427
- await manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext());
428
- expect(handlers.onSessionId).toHaveBeenCalledWith('session-1', 'provider-session-123');
429
- });
430
- it('calls onClientCreated callback when set', async () => {
431
- setupSuccessfulSpawn();
432
- const callback = vi.fn();
433
- manager.setOnClientCreated(callback);
434
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
435
- expect(callback).toHaveBeenCalledWith('session-1', handle, defaultContext());
436
- });
437
- it('stores config options returned by ACP newSession', async () => {
438
- setupSuccessfulSpawn();
439
- const expectedConfigOptions = [
440
- {
441
- id: 'model',
442
- name: 'Model',
443
- type: 'select',
444
- category: 'model',
445
- currentValue: 'sonnet',
446
- options: [
447
- { value: 'sonnet', name: 'Sonnet' },
448
- { value: 'opus', name: 'Opus' },
449
- ],
450
- },
451
- {
452
- id: 'mode',
453
- name: 'Mode',
454
- type: 'select',
455
- category: 'mode',
456
- currentValue: 'default',
457
- options: [
458
- { value: 'default', name: 'Default' },
459
- { value: 'plan', name: 'Plan' },
460
- ],
461
- },
462
- ];
463
- mockNewSession.mockResolvedValueOnce({
464
- sessionId: 'provider-session-123',
465
- configOptions: expectedConfigOptions,
466
- });
467
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
468
- expect(handle.configOptions).toEqual(expectedConfigOptions);
469
- });
470
- it('fails fast when ACP newSession omits configOptions', async () => {
471
- const child = setupSuccessfulSpawn();
472
- exitChildAfterSigterm(child);
473
- mockNewSession.mockResolvedValueOnce({
474
- sessionId: 'provider-session-123',
475
- });
476
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('did not include required configOptions');
477
- });
478
- it('derives required config options from models/modes when newSession omits configOptions', async () => {
479
- setupSuccessfulSpawn();
480
- mockNewSession.mockResolvedValueOnce({
481
- sessionId: 'provider-session-123',
482
- models: {
483
- availableModels: [
484
- { modelId: 'claude-opus-4-6', name: 'Claude Opus 4.6' },
485
- { modelId: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' },
486
- ],
487
- currentModelId: 'claude-opus-4-6',
488
- },
489
- modes: {
490
- availableModes: [
491
- { id: 'default', name: 'Default' },
492
- { id: 'plan', name: 'Plan' },
493
- ],
494
- currentModeId: 'default',
495
- },
496
- });
497
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
498
- const modelOption = handle.configOptions.find((option) => option.category === 'model');
499
- const modeOption = handle.configOptions.find((option) => option.category === 'mode');
500
- expect(modelOption).toMatchObject({
501
- id: 'model',
502
- currentValue: 'claude-opus-4-6',
503
- });
504
- expect(modelOption?.options).toEqual(expect.arrayContaining([
505
- expect.objectContaining({ value: 'claude-opus-4-6', name: 'Claude Opus 4.6' }),
506
- expect.objectContaining({ value: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' }),
507
- ]));
508
- expect(modeOption).toMatchObject({
509
- id: 'mode',
510
- currentValue: 'default',
511
- });
512
- expect(modeOption?.options).toEqual(expect.arrayContaining([
513
- expect.objectContaining({ value: 'default', name: 'Default' }),
514
- expect.objectContaining({ value: 'plan', name: 'Plan' }),
515
- ]));
516
- });
517
- it('fails fast when ACP newSession omits required model/mode categories', async () => {
518
- const child = setupSuccessfulSpawn();
519
- exitChildAfterSigterm(child);
520
- mockNewSession.mockResolvedValueOnce({
521
- sessionId: 'provider-session-123',
522
- configOptions: [
523
- {
524
- id: 'reasoning_effort',
525
- name: 'Reasoning Effort',
526
- type: 'select',
527
- category: 'thought_level',
528
- currentValue: 'medium',
529
- options: [{ value: 'medium', name: 'Medium' }],
530
- },
531
- ],
532
- });
533
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('missing required config option categories: model, mode');
534
- });
535
- it('uses model family name for Claude default model labels in configOptions', async () => {
536
- setupSuccessfulSpawn();
537
- mockNewSession.mockResolvedValueOnce({
538
- sessionId: 'provider-session-123',
539
- configOptions: [
540
- {
541
- id: 'model',
542
- name: 'Model',
543
- type: 'select',
544
- category: 'model',
545
- currentValue: 'default',
546
- options: [
547
- {
548
- value: 'default',
549
- name: 'Default (recommended)',
550
- description: 'Opus 4.6 · best for complex tasks',
551
- },
552
- { value: 'sonnet', name: 'Sonnet 4.5' },
553
- ],
554
- },
555
- {
556
- id: 'mode',
557
- name: 'Mode',
558
- type: 'select',
559
- category: 'mode',
560
- currentValue: 'default',
561
- options: [
562
- { value: 'default', name: 'Default' },
563
- { value: 'plan', name: 'Plan' },
564
- ],
565
- },
566
- ],
567
- });
568
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
569
- const modelOption = handle.configOptions.find((option) => option.id === 'model');
570
- const defaultEntry = modelOption?.options.find((option) => 'value' in option && option.value === 'default');
571
- expect(defaultEntry).toMatchObject({ value: 'default', name: 'Default — Opus 4.6' });
572
- });
573
- });
574
- describe('sub-agent browsing extensions', () => {
575
- it('classifies a browse-only client before provider restoration completes', async () => {
576
- const child = setupSuccessfulSpawn({ ...subagentBrowseCapabilities(), loadSession: true });
577
- const initialization = createDeferred();
578
- mockInitialize.mockReturnValueOnce(initialization.promise);
579
- const creation = manager.getOrCreateClient('db-session-1', {
580
- ...codexOptions(),
581
- purpose: 'browse',
582
- resumeProviderSessionId: 'provider-session-existing',
583
- }, defaultHandlers(), defaultContext());
584
- await vi.waitFor(() => {
585
- expect(mockSpawn).toHaveBeenCalled();
586
- });
587
- expect(manager.isBrowseOnlySession('db-session-1')).toBe(true);
588
- initialization.resolve({
589
- protocolVersion: 1,
590
- agentCapabilities: { ...subagentBrowseCapabilities(), loadSession: true },
591
- agentInfo: { name: 'codex-app-server-acp' },
592
- });
593
- await creation;
594
- expect(manager.isBrowseOnlySession('db-session-1')).toBe(true);
595
- exitChildAfterSigterm(child);
596
- await manager.stopClient('db-session-1');
597
- });
598
- it('keeps a browse-only restored client stopped until active startup promotes it', async () => {
599
- setupSuccessfulSpawn({ ...subagentBrowseCapabilities(), loadSession: true });
600
- mockExtMethod.mockResolvedValueOnce({ subagents: [], nextCursor: null });
601
- const browseHandle = await manager.getOrCreateClient('db-session-1', {
602
- ...codexOptions(),
603
- purpose: 'browse',
604
- resumeProviderSessionId: 'provider-session-existing',
605
- }, defaultHandlers(), defaultContext());
606
- await expect(manager.listSubagents('db-session-1', { cursor: null, limit: 50 })).resolves.toEqual({ subagents: [], nextCursor: null });
607
- expect(manager.getClient('db-session-1')).toBeUndefined();
608
- expect(manager.isSessionRunning('db-session-1')).toBe(false);
609
- const activeHandle = await manager.getOrCreateClient('db-session-1', { ...codexOptions(), purpose: 'active' }, defaultHandlers(), defaultContext());
610
- expect(activeHandle).toBe(browseHandle);
611
- expect(manager.getClient('db-session-1')).toBe(browseHandle);
612
- expect(manager.isSessionRunning('db-session-1')).toBe(true);
613
- expect(mockSpawn).toHaveBeenCalledTimes(1);
614
- });
615
- it('does not replace a missing browse-only provider session with a new session', async () => {
616
- const child = setupSuccessfulSpawn({ ...subagentBrowseCapabilities(), loadSession: true });
617
- exitChildAfterSigterm(child);
618
- mockLoadSession.mockRejectedValueOnce(new Error('stored provider session missing'));
619
- await expect(manager.getOrCreateClient('db-session-1', {
620
- ...codexOptions(),
621
- purpose: 'browse',
622
- resumeProviderSessionId: 'provider-session-missing',
623
- }, defaultHandlers(), defaultContext())).rejects.toMatchObject({
624
- name: 'AcpBrowseSessionUnavailableError',
625
- cause: { message: 'stored provider session missing' },
626
- });
627
- expect(mockNewSession).not.toHaveBeenCalled();
628
- });
629
- it('preserves browse-only state when an older process finishes exit handling', async () => {
630
- const firstChild = setupSuccessfulSpawn();
631
- const exitHandling = createDeferred();
632
- const firstHandlers = {
633
- ...defaultHandlers(),
634
- onExit: vi.fn(() => exitHandling.promise),
635
- };
636
- await manager.getOrCreateClient('db-session-1', defaultOptions(), firstHandlers, defaultContext());
637
- firstChild.exitCode = 1;
638
- firstChild.emit('exit', 1, null);
639
- await vi.waitFor(() => {
640
- expect(firstHandlers.onExit).toHaveBeenCalledWith('db-session-1', 1);
641
- });
642
- const replacementChild = setupSuccessfulSpawn({
643
- ...subagentBrowseCapabilities(),
644
- loadSession: true,
645
- });
646
- const replacementHandle = await manager.getOrCreateClient('db-session-1', {
647
- ...codexOptions(),
648
- purpose: 'browse',
649
- resumeProviderSessionId: 'provider-session-existing',
650
- }, defaultHandlers(), defaultContext());
651
- exitHandling.resolve();
652
- await new Promise((resolve) => setTimeout(resolve, 0));
653
- expect(manager.getBrowseClient('db-session-1')).toBe(replacementHandle);
654
- expect(manager.isBrowseOnlySession('db-session-1')).toBe(true);
655
- expect(manager.getClient('db-session-1')).toBeUndefined();
656
- exitChildAfterSigterm(replacementChild);
657
- await manager.stopClient('db-session-1');
658
- });
659
- it('classifies a provider without loadSession as unsupported for browse restoration', async () => {
660
- const child = setupSuccessfulSpawn(subagentBrowseCapabilities());
661
- exitChildAfterSigterm(child);
662
- await expect(manager.getOrCreateClient('db-session-1', {
663
- ...codexOptions(),
664
- purpose: 'browse',
665
- resumeProviderSessionId: 'provider-session-existing',
666
- }, defaultHandlers(), defaultContext())).rejects.toMatchObject({ name: 'AcpBrowseSessionUnavailableError' });
667
- expect(mockNewSession).not.toHaveBeenCalled();
668
- });
669
- it('returns the negotiated capability only for a live handle', async () => {
670
- expect(manager.getSubagentBrowseCapability('session-1')).toBeNull();
671
- const child = setupSuccessfulSpawn(subagentBrowseCapabilities());
672
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
673
- expect(manager.getSubagentBrowseCapability('session-1')).toEqual({
674
- version: 1,
675
- list: true,
676
- read: true,
677
- notifications: true,
678
- });
679
- child.killed = true;
680
- expect(manager.getSubagentBrowseCapability('session-1')).toBeNull();
681
- });
682
- it('lists sub-agents with the provider session ID and unchanged cursor', async () => {
683
- setupSuccessfulSpawn(subagentBrowseCapabilities());
684
- mockExtMethod.mockResolvedValueOnce({ subagents: [], nextCursor: null });
685
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
686
- const result = await manager.listSubagents('db-session-1', {
687
- cursor: 'list-cursor-7',
688
- limit: 50,
689
- });
690
- expect(result).toEqual({ subagents: [], nextCursor: null });
691
- expect(mockExtMethod).toHaveBeenCalledWith(SUBAGENTS_LIST_METHOD, {
692
- sessionId: 'provider-session-123',
693
- cursor: 'list-cursor-7',
694
- limit: 50,
695
- });
696
- });
697
- it('reads a transcript with the provider session ID and unchanged cursor', async () => {
698
- setupSuccessfulSpawn(subagentBrowseCapabilities());
699
- mockExtMethod.mockResolvedValueOnce({
700
- projectionBoundary: 'turn',
701
- updates: [],
702
- nextCursor: 'read-cursor-9',
703
- });
704
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
705
- const result = await manager.readSubagentTranscript('db-session-1', {
706
- subagentId: 'child-1',
707
- cursor: 'read-cursor-8',
708
- limit: 10,
709
- });
710
- expect(result).toEqual({
711
- projectionBoundary: 'turn',
712
- updates: [],
713
- nextCursor: 'read-cursor-9',
714
- });
715
- expect(mockExtMethod).toHaveBeenCalledWith(SUBAGENTS_READ_METHOD, {
716
- sessionId: 'provider-session-123',
717
- subagentId: 'child-1',
718
- cursor: 'read-cursor-8',
719
- limit: 10,
720
- });
721
- });
722
- it('rejects malformed extension inputs before calling the provider', async () => {
723
- setupSuccessfulSpawn(subagentBrowseCapabilities());
724
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
725
- await expect(manager.listSubagents('db-session-1', { cursor: null, limit: 101 })).rejects.toThrow();
726
- expect(mockExtMethod).not.toHaveBeenCalled();
727
- });
728
- it('normalizes malformed list and transcript responses as provider precondition errors', async () => {
729
- setupSuccessfulSpawn(subagentBrowseCapabilities());
730
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
731
- mockExtMethod.mockResolvedValueOnce({ subagents: 'invalid', nextCursor: null });
732
- await expect(manager.listSubagents('db-session-1', { cursor: null, limit: 50 })).rejects.toMatchObject({
733
- name: 'AcpSubagentBrowseError',
734
- code: 'PRECONDITION_FAILED',
735
- message: 'Sub-agent list is unavailable because the provider returned an invalid response.',
736
- });
737
- mockExtMethod.mockResolvedValueOnce({
738
- projectionBoundary: 'turn',
739
- updates: [{ sessionUpdate: 'unknown' }],
740
- nextCursor: null,
741
- });
742
- await expect(manager.readSubagentTranscript('db-session-1', {
743
- subagentId: 'child-1',
744
- cursor: null,
745
- limit: 10,
746
- })).rejects.toMatchObject({
747
- name: 'AcpSubagentBrowseError',
748
- code: 'PRECONDITION_FAILED',
749
- message: 'Sub-agent transcript is unavailable because the provider returned an invalid response.',
750
- });
751
- });
752
- it('normalizes provider extension errors into safe application errors', async () => {
753
- setupSuccessfulSpawn(subagentBrowseCapabilities());
754
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
755
- mockExtMethod.mockRejectedValueOnce({
756
- code: -32_602,
757
- message: 'Invalid params: secret provider detail',
758
- data: { cursor: 'invalid' },
759
- });
760
- await expect(manager.readSubagentTranscript('db-session-1', {
761
- subagentId: 'child-1',
762
- cursor: 'invalid',
763
- limit: 10,
764
- })).rejects.toMatchObject({
765
- name: 'AcpSubagentBrowseError',
766
- code: 'INVALID_INPUT',
767
- message: 'Invalid sub-agent transcript request.',
768
- });
769
- mockExtMethod.mockRejectedValueOnce({
770
- code: -32_002,
771
- message: 'Resource not found: secret provider thread',
772
- });
773
- await expect(manager.readSubagentTranscript('db-session-1', {
774
- subagentId: 'foreign-child',
775
- cursor: null,
776
- limit: 10,
777
- })).rejects.toMatchObject({
778
- name: 'AcpSubagentBrowseError',
779
- code: 'NOT_FOUND',
780
- message: 'Sub-agent transcript not found for this session.',
781
- });
782
- mockExtMethod.mockRejectedValueOnce({
783
- code: -32_603,
784
- message: 'Internal error: mismatched provider thread IDs',
785
- });
786
- await expect(manager.readSubagentTranscript('db-session-1', {
787
- subagentId: 'child-1',
788
- cursor: null,
789
- limit: 10,
790
- })).rejects.toMatchObject({
791
- name: 'AcpSubagentBrowseError',
792
- code: 'PRECONDITION_FAILED',
793
- message: 'Sub-agent transcript is unavailable because the provider returned an invalid response.',
794
- });
795
- });
796
- it('preserves JSON-RPC codes carried by Error subclasses', async () => {
797
- setupSuccessfulSpawn(subagentBrowseCapabilities());
798
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
799
- const providerError = Object.assign(new Error('Resource not found: provider thread'), {
800
- code: -32_002,
801
- data: { threadId: 'missing-child' },
802
- });
803
- mockExtMethod.mockRejectedValueOnce(providerError);
804
- await expect(manager.readSubagentTranscript('db-session-1', {
805
- subagentId: 'missing-child',
806
- cursor: null,
807
- limit: 10,
808
- })).rejects.toMatchObject({
809
- name: 'AcpSubagentBrowseError',
810
- code: 'NOT_FOUND',
811
- message: 'Sub-agent transcript not found for this session.',
812
- });
813
- });
814
- it('rejects extension requests without a live handle or negotiated capability', async () => {
815
- await expect(manager.listSubagents('missing-session', { cursor: null, limit: 50 })).rejects.toMatchObject({
816
- name: 'AcpSubagentBrowseError',
817
- code: 'PRECONDITION_FAILED',
818
- message: 'Sub-agent browsing requires a running parent session.',
819
- });
820
- setupSuccessfulSpawn();
821
- await manager.getOrCreateClient('db-session-1', defaultOptions(), defaultHandlers(), defaultContext());
822
- await expect(manager.readSubagentTranscript('db-session-1', {
823
- subagentId: 'child-1',
824
- cursor: null,
825
- limit: 10,
826
- })).rejects.toMatchObject({
827
- name: 'AcpSubagentBrowseError',
828
- code: 'PRECONDITION_FAILED',
829
- message: 'Sub-agent browsing is unavailable for this session.',
830
- });
831
- expect(mockExtMethod).not.toHaveBeenCalled();
832
- });
833
- });
834
- describe('stopClient', () => {
835
- it('keeps creation lock bookkeeping when stop is already in progress', async () => {
836
- const child = setupSuccessfulSpawn();
837
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
838
- const internalManager = manager;
839
- internalManager.creationLocks.set('session-1', vi.fn());
840
- internalManager.lockRefCounts.set('session-1', 3);
841
- child.kill = vi.fn(() => {
842
- setTimeout(() => {
843
- child.exitCode = 0;
844
- child.emit('exit', 0, null);
845
- }, 10);
846
- return true;
847
- });
848
- const stopPromise = manager.stopClient('session-1');
849
- await vi.waitFor(() => {
850
- expect(manager.isStopInProgress('session-1')).toBe(true);
851
- });
852
- await manager.stopClient('session-1');
853
- expect(internalManager.creationLocks.has('session-1')).toBe(true);
854
- expect(internalManager.lockRefCounts.has('session-1')).toBe(true);
855
- await stopPromise;
856
- });
857
- it('sends SIGTERM, waits grace period, cleans up references', async () => {
858
- const child = setupSuccessfulSpawn();
859
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
860
- child.kill = vi.fn(() => {
861
- child.exitCode = 0;
862
- child.emit('exit', 0, null);
863
- return true;
864
- });
865
- await manager.stopClient('session-1');
866
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
867
- expect(manager.getClient('session-1')).toBeUndefined();
868
- });
869
- it('clears the SIGTERM grace-period timeout when the child exits quickly', async () => {
870
- const child = setupSuccessfulSpawn();
871
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
872
- child.kill = vi.fn(() => {
873
- child.exitCode = 0;
874
- child.emit('exit', 0, null);
875
- return true;
876
- });
877
- vi.useFakeTimers();
878
- try {
879
- await manager.stopClient('session-1');
880
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
881
- expect(vi.getTimerCount()).toBe(0);
882
- }
883
- finally {
884
- vi.useRealTimers();
885
- }
886
- });
887
- it('escalates to SIGKILL after timeout', async () => {
888
- const child = setupSuccessfulSpawn();
889
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
890
- const killCalls = [];
891
- child.kill = vi.fn((signal) => {
892
- killCalls.push(signal ?? 'default');
893
- if (signal === 'SIGKILL') {
894
- child.killed = true;
895
- child.exitCode = 137;
896
- child.emit('exit', 137, 'SIGKILL');
897
- }
898
- return true;
899
- });
900
- vi.useFakeTimers();
901
- const stopPromise = manager.stopClient('session-1');
902
- await vi.advanceTimersByTimeAsync(5100);
903
- await stopPromise;
904
- expect(killCalls).toContain('SIGTERM');
905
- expect(killCalls).toContain('SIGKILL');
906
- expect(manager.getClient('session-1')).toBeUndefined();
907
- vi.useRealTimers();
908
- });
909
- it('cancels prompt if isPromptInFlight before SIGTERM', async () => {
910
- const child = setupSuccessfulSpawn();
911
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
912
- handle.isPromptInFlight = true;
913
- mockCancel.mockResolvedValue(undefined);
914
- child.kill = vi.fn(() => {
915
- child.exitCode = 0;
916
- child.emit('exit', 0, null);
917
- return true;
918
- });
919
- await manager.stopClient('session-1');
920
- expect(mockCancel).toHaveBeenCalledWith({
921
- sessionId: 'provider-session-123',
922
- });
923
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
924
- });
925
- it('waits for an existing stop when called concurrently', async () => {
926
- const child = setupSuccessfulSpawn();
927
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
928
- child.kill = vi.fn(() => true);
929
- const firstStop = manager.stopClient('session-1');
930
- await vi.waitFor(() => {
931
- expect(manager.isStopInProgress('session-1')).toBe(true);
932
- });
933
- let secondStopSettled = false;
934
- const secondStop = manager.stopClient('session-1').then(() => {
935
- secondStopSettled = true;
936
- });
937
- await Promise.resolve();
938
- expect(secondStopSettled).toBe(false);
939
- child.exitCode = 0;
940
- child.emit('exit', 0, null);
941
- await Promise.all([firstStop, secondStop]);
942
- expect(secondStopSettled).toBe(true);
943
- expect(child.kill).toHaveBeenCalledTimes(1);
944
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
945
- });
946
- it('aborts in-flight client creation and cleans up the spawned subprocess', async () => {
947
- const child = createMockChildProcess();
948
- exitChildAfterSigterm(child);
949
- mockSpawn.mockReturnValue(child);
950
- mockInitialize.mockImplementation(() => new Promise(() => {
951
- }));
952
- const createPromise = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
953
- const createRejection = createPromise.catch((error) => error);
954
- await vi.waitFor(() => {
955
- expect(mockSpawn).toHaveBeenCalledTimes(1);
956
- expect(manager.getPendingClient('session-1')).toBeDefined();
957
- });
958
- await manager.stopClient('session-1');
959
- await expect(createRejection).resolves.toMatchObject({
960
- message: expect.stringContaining('ACP session stop requested'),
961
- });
962
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
963
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
964
- expect(manager.isStopInProgress('session-1')).toBe(false);
965
- expect(manager.getClient('session-1')).toBeUndefined();
966
- expect(manager.getPendingClient('session-1')).toBeUndefined();
967
- });
968
- it('skips exit handler when stop is in progress', async () => {
969
- const child = setupSuccessfulSpawn();
970
- const handlers = defaultHandlers();
971
- await manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext());
972
- handlers.onExit.mockClear();
973
- child.kill = vi.fn(() => {
974
- child.exitCode = 0;
975
- child.emit('exit', 0, null);
976
- return true;
977
- });
978
- await manager.stopClient('session-1');
979
- expect(handlers.onExit).not.toHaveBeenCalled();
980
- });
981
- it('skips exit handler when a stopped process exits after stop timeout', async () => {
982
- const child = setupSuccessfulSpawn();
983
- const handlers = defaultHandlers();
984
- await manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext());
985
- child.kill = vi.fn((signal) => {
986
- if (signal) {
987
- child.killed = true;
988
- }
989
- return true;
990
- });
991
- vi.useFakeTimers();
992
- const stopPromise = manager.stopClient('session-1');
993
- await vi.advanceTimersByTimeAsync(5100);
994
- await stopPromise;
995
- vi.useRealTimers();
996
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
997
- expect(child.kill).toHaveBeenCalledWith('SIGKILL');
998
- expect(manager.isStopInProgress('session-1')).toBe(false);
999
- handlers.onExit.mockClear();
1000
- child.exitCode = 137;
1001
- child.emit('exit', 137, 'SIGKILL');
1002
- await new Promise((resolve) => setTimeout(resolve, 0));
1003
- expect(handlers.onExit).not.toHaveBeenCalled();
1004
- });
1005
- it('does not let a late stopped-process exit affect a replacement client', async () => {
1006
- const firstChild = setupSuccessfulSpawn();
1007
- const firstHandlers = defaultHandlers();
1008
- await manager.getOrCreateClient('session-1', defaultOptions(), firstHandlers, defaultContext());
1009
- firstChild.kill = vi.fn((signal) => {
1010
- if (signal) {
1011
- firstChild.killed = true;
1012
- }
1013
- return true;
1014
- });
1015
- vi.useFakeTimers();
1016
- const stopPromise = manager.stopClient('session-1');
1017
- await vi.advanceTimersByTimeAsync(5100);
1018
- await stopPromise;
1019
- vi.useRealTimers();
1020
- const secondChild = createMockChildProcess();
1021
- const secondHandlers = defaultHandlers();
1022
- mockSpawn.mockReturnValueOnce(secondChild);
1023
- const restartedHandle = await manager.getOrCreateClient('session-1', defaultOptions(), secondHandlers, defaultContext());
1024
- firstHandlers.onExit.mockClear();
1025
- firstChild.exitCode = 137;
1026
- firstChild.emit('exit', 137, 'SIGKILL');
1027
- await new Promise((resolve) => setTimeout(resolve, 0));
1028
- expect(firstHandlers.onExit).not.toHaveBeenCalled();
1029
- expect(manager.getClient('session-1')).toBe(restartedHandle);
1030
- });
1031
- it('does not call onExit for stale SIGKILL exit after stop completes and session restarts', async () => {
1032
- const firstChild = setupSuccessfulSpawn();
1033
- const handlers = defaultHandlers();
1034
- await manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext());
1035
- firstChild.kill = vi.fn((signal) => {
1036
- if (signal) {
1037
- firstChild.killed = true;
1038
- }
1039
- if (signal === 'SIGKILL') {
1040
- firstChild.exitCode = 137;
1041
- }
1042
- return true;
1043
- });
1044
- vi.useFakeTimers();
1045
- const stopPromise = manager.stopClient('session-1');
1046
- await vi.advanceTimersByTimeAsync(5100);
1047
- await stopPromise;
1048
- vi.useRealTimers();
1049
- const secondChild = createMockChildProcess();
1050
- mockSpawn.mockReturnValueOnce(secondChild);
1051
- const newHandle = await manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext());
1052
- expect(newHandle.child).toBe(secondChild);
1053
- handlers.onExit.mockClear();
1054
- firstChild.emit('exit', 137, 'SIGKILL');
1055
- await new Promise((resolve) => setTimeout(resolve, 0));
1056
- expect(handlers.onExit).not.toHaveBeenCalled();
1057
- expect(manager.getClient('session-1')).toBe(newHandle);
1058
- });
1059
- it('rejects client creation while a stop is in progress', async () => {
1060
- const firstChild = setupSuccessfulSpawn();
1061
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1062
- firstChild.kill = vi.fn((signal) => {
1063
- if (signal) {
1064
- firstChild.killed = true;
1065
- }
1066
- return true;
1067
- });
1068
- const stopPromise = manager.stopClient('session-1');
1069
- await vi.waitFor(() => {
1070
- expect(firstChild.kill).toHaveBeenCalledWith('SIGTERM');
1071
- });
1072
- const secondChild = createMockChildProcess();
1073
- exitChildAfterSigterm(secondChild);
1074
- mockSpawn.mockReturnValueOnce(secondChild);
1075
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('ACP session stop requested');
1076
- expect(secondChild.kill).toHaveBeenCalledWith('SIGTERM');
1077
- expect(secondChild.kill).not.toHaveBeenCalledWith('SIGKILL');
1078
- firstChild.exitCode = 0;
1079
- firstChild.emit('exit', 0, null);
1080
- await stopPromise;
1081
- expect(manager.getClient('session-1')).toBeUndefined();
1082
- });
1083
- it('wires child error handlers before aborting creation during stop', async () => {
1084
- const firstChild = setupSuccessfulSpawn();
1085
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1086
- firstChild.kill = vi.fn((signal) => {
1087
- if (signal) {
1088
- firstChild.killed = true;
1089
- }
1090
- return true;
1091
- });
1092
- const stopPromise = manager.stopClient('session-1');
1093
- await vi.waitFor(() => {
1094
- expect(firstChild.kill).toHaveBeenCalledWith('SIGTERM');
1095
- });
1096
- const secondChild = createMockChildProcess();
1097
- secondChild.kill = vi.fn((signal) => {
1098
- if (signal === 'SIGTERM') {
1099
- secondChild.emit('error', new Error('cleanup child error'));
1100
- queueMicrotask(() => {
1101
- secondChild.exitCode = 0;
1102
- secondChild.emit('exit', 0, null);
1103
- });
1104
- }
1105
- return true;
1106
- });
1107
- mockSpawn.mockReturnValueOnce(secondChild);
1108
- const handlers = defaultHandlers();
1109
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), handlers, defaultContext())).rejects.toThrow('ACP session stop requested');
1110
- expect(secondChild.kill).toHaveBeenCalledWith('SIGTERM');
1111
- expect(secondChild.kill).not.toHaveBeenCalledWith('SIGKILL');
1112
- await vi.waitFor(() => {
1113
- expect(handlers.onError).toHaveBeenCalledWith('session-1', expect.any(Error));
1114
- });
1115
- firstChild.exitCode = 0;
1116
- firstChild.emit('exit', 0, null);
1117
- await stopPromise;
1118
- });
1119
- it('clears creation lock bookkeeping when stop rejects a concurrent create', async () => {
1120
- const firstChild = setupSuccessfulSpawn();
1121
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1122
- firstChild.kill = vi.fn((signal) => {
1123
- if (signal) {
1124
- firstChild.killed = true;
1125
- }
1126
- return true;
1127
- });
1128
- const stopPromise = manager.stopClient('session-1');
1129
- await vi.waitFor(() => {
1130
- expect(firstChild.kill).toHaveBeenCalledWith('SIGTERM');
1131
- });
1132
- const secondChild = createMockChildProcess();
1133
- exitChildAfterSigterm(secondChild);
1134
- mockSpawn.mockReturnValueOnce(secondChild);
1135
- await expect(manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('ACP session stop requested');
1136
- const internalManager = manager;
1137
- expect(internalManager.creationLocks.has('session-1')).toBe(false);
1138
- expect(internalManager.lockRefCounts.has('session-1')).toBe(false);
1139
- firstChild.exitCode = 0;
1140
- firstChild.emit('exit', 0, null);
1141
- await stopPromise;
1142
- });
1143
- });
1144
- describe('stopAllClients', () => {
1145
- it('atomically closes admission and reports active and pending session ids', async () => {
1146
- const activeChild = setupSuccessfulSpawn();
1147
- await manager.getOrCreateClient('session-active', defaultOptions(), defaultHandlers(), defaultContext());
1148
- const pendingChild = createMockChildProcess();
1149
- exitChildAfterSigterm(pendingChild);
1150
- mockSpawn.mockReturnValueOnce(pendingChild);
1151
- mockInitialize.mockImplementationOnce(() => new Promise(() => {
1152
- }));
1153
- const pendingCreation = manager
1154
- .getOrCreateClient('session-pending', { ...defaultOptions(), sessionId: 'session-pending' }, defaultHandlers(), defaultContext())
1155
- .catch((error) => error);
1156
- await vi.waitFor(() => {
1157
- expect(manager.getPendingClient('session-pending')).toBeDefined();
1158
- });
1159
- const shutdownSessionIds = manager.beginShutdown();
1160
- expect(new Set(shutdownSessionIds)).toEqual(new Set(['session-active', 'session-pending']));
1161
- await expect(manager.getOrCreateClient('session-too-late', { ...defaultOptions(), sessionId: 'session-too-late' }, defaultHandlers(), defaultContext())).rejects.toThrow('ACP runtime manager is shutting down');
1162
- activeChild.kill = vi.fn(() => {
1163
- activeChild.exitCode = 0;
1164
- activeChild.emit('exit', 0, null);
1165
- return true;
1166
- });
1167
- await manager.stopAllClients(50);
1168
- await expect(pendingCreation).resolves.toMatchObject({
1169
- message: expect.stringContaining('ACP runtime manager is shutting down'),
1170
- });
1171
- });
1172
- it('clears per-client shutdown timeouts when clients stop quickly', async () => {
1173
- const firstChild = setupSuccessfulSpawn();
1174
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1175
- const secondChild = createMockChildProcess();
1176
- mockSpawn.mockReturnValueOnce(secondChild);
1177
- await manager.getOrCreateClient('session-2', { ...defaultOptions(), sessionId: 'session-2' }, defaultHandlers(), defaultContext());
1178
- firstChild.kill = vi.fn(() => {
1179
- firstChild.exitCode = 0;
1180
- firstChild.emit('exit', 0, null);
1181
- return true;
1182
- });
1183
- secondChild.kill = vi.fn(() => {
1184
- secondChild.exitCode = 0;
1185
- secondChild.emit('exit', 0, null);
1186
- return true;
1187
- });
1188
- vi.useFakeTimers();
1189
- try {
1190
- await manager.stopAllClients(10_000);
1191
- expect(firstChild.kill).toHaveBeenCalledWith('SIGTERM');
1192
- expect(secondChild.kill).toHaveBeenCalledWith('SIGTERM');
1193
- expect(vi.getTimerCount()).toBe(0);
1194
- expect([...manager.getAllClients()]).toEqual([]);
1195
- }
1196
- finally {
1197
- vi.useRealTimers();
1198
- }
1199
- });
1200
- it('rejects new client creation after shutdown begins', async () => {
1201
- await manager.stopAllClients();
1202
- await expect(manager.getOrCreateClient('session-after-shutdown', defaultOptions(), defaultHandlers(), defaultContext())).rejects.toThrow('ACP runtime manager is shutting down');
1203
- expect(mockSpawn).not.toHaveBeenCalled();
1204
- });
1205
- it('aborts in-flight client creation and cleans up the spawned subprocess', async () => {
1206
- const child = createMockChildProcess();
1207
- exitChildAfterSigterm(child);
1208
- mockSpawn.mockReturnValue(child);
1209
- mockInitialize.mockImplementation(() => new Promise(() => {
1210
- }));
1211
- const createPromise = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1212
- const createRejection = createPromise.catch((error) => error);
1213
- await vi.waitFor(() => {
1214
- expect(mockSpawn).toHaveBeenCalledTimes(1);
1215
- });
1216
- await manager.stopAllClients(50);
1217
- await expect(createRejection).resolves.toMatchObject({
1218
- message: expect.stringContaining('ACP runtime manager is shutting down'),
1219
- });
1220
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
1221
- expect(child.kill).not.toHaveBeenCalledWith('SIGKILL');
1222
- expect(manager.getClient('session-1')).toBeUndefined();
1223
- expect(manager.getPendingClient('session-1')).toBeUndefined();
1224
- });
1225
- it('rejects queued creation requests after an in-flight creation is aborted', async () => {
1226
- const child = createMockChildProcess();
1227
- exitChildAfterSigterm(child);
1228
- mockSpawn.mockReturnValue(child);
1229
- mockInitialize.mockImplementation(() => new Promise(() => {
1230
- }));
1231
- const firstCreate = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1232
- const firstRejection = firstCreate.catch((error) => error);
1233
- await vi.waitFor(() => {
1234
- expect(mockSpawn).toHaveBeenCalledTimes(1);
1235
- });
1236
- const secondCreate = manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1237
- const secondRejection = secondCreate.catch((error) => error);
1238
- await manager.stopAllClients(50);
1239
- await expect(firstRejection).resolves.toMatchObject({
1240
- message: expect.stringContaining('ACP runtime manager is shutting down'),
1241
- });
1242
- await expect(secondRejection).resolves.toMatchObject({
1243
- message: expect.stringContaining('ACP runtime manager is shutting down'),
1244
- });
1245
- expect(mockSpawn).toHaveBeenCalledTimes(1);
1246
- expect(manager.getClient('session-1')).toBeUndefined();
1247
- });
1248
- });
1249
- describe('sendPrompt', () => {
1250
- it('sets isPromptInFlight, calls connection.prompt, clears flag on resolve', async () => {
1251
- setupSuccessfulSpawn();
1252
- mockPrompt.mockResolvedValue({ stopReason: 'end_turn' });
1253
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1254
- expect(handle.isPromptInFlight).toBe(false);
1255
- const result = await manager.sendPrompt('session-1', [{ type: 'text', text: 'Hello world' }]);
1256
- expect(mockPrompt).toHaveBeenCalledWith({
1257
- sessionId: 'provider-session-123',
1258
- prompt: [{ type: 'text', text: 'Hello world' }],
1259
- });
1260
- expect(result.stopReason).toBe('end_turn');
1261
- expect(handle.isPromptInFlight).toBe(false);
1262
- });
1263
- it('clears isPromptInFlight on error', async () => {
1264
- setupSuccessfulSpawn();
1265
- mockPrompt.mockRejectedValue(new Error('prompt failed'));
1266
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1267
- await expect(manager.sendPrompt('session-1', [{ type: 'text', text: 'Hello' }])).rejects.toThrow('prompt failed');
1268
- expect(handle.isPromptInFlight).toBe(false);
1269
- });
1270
- it('keeps prompt marked in flight while cancelling after prompt timeout', async () => {
1271
- setupSuccessfulSpawn();
1272
- mockPrompt.mockReturnValue(new Promise(() => undefined));
1273
- mockCancel.mockResolvedValue(undefined);
1274
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1275
- vi.useFakeTimers();
1276
- try {
1277
- const promptPromise = manager.sendPrompt('session-1', [{ type: 'text', text: 'Hello' }], 100);
1278
- const promptRejection = promptPromise.catch((error) => error);
1279
- await vi.advanceTimersByTimeAsync(100);
1280
- await expect(promptRejection).resolves.toBeInstanceOf(PromptTimeoutError);
1281
- expect(mockCancel).toHaveBeenCalledWith({
1282
- sessionId: 'provider-session-123',
1283
- });
1284
- expect(handle.isPromptInFlight).toBe(false);
1285
- }
1286
- finally {
1287
- vi.useRealTimers();
1288
- }
1289
- });
1290
- it('stops the client when prompt timeout cancellation hangs', async () => {
1291
- const child = setupSuccessfulSpawn();
1292
- mockPrompt.mockReturnValue(new Promise(() => undefined));
1293
- mockCancel.mockReturnValue(new Promise(() => undefined));
1294
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1295
- child.kill = vi.fn((signal) => {
1296
- if (signal === 'SIGTERM') {
1297
- child.killed = true;
1298
- child.exitCode = 0;
1299
- child.emit('exit', 0, null);
1300
- }
1301
- return true;
1302
- });
1303
- vi.useFakeTimers();
1304
- try {
1305
- const promptPromise = manager.sendPrompt('session-1', [{ type: 'text', text: 'Hello' }], 100);
1306
- const promptRejection = promptPromise.catch((error) => error);
1307
- await vi.advanceTimersByTimeAsync(100);
1308
- expect(mockCancel).toHaveBeenCalledTimes(1);
1309
- await vi.advanceTimersByTimeAsync(5000);
1310
- await expect(promptRejection).resolves.toBeInstanceOf(PromptTimeoutError);
1311
- expect(child.kill).toHaveBeenCalledWith('SIGTERM');
1312
- expect(manager.getClient('session-1')).toBeUndefined();
1313
- expect(handle.isPromptInFlight).toBe(false);
1314
- }
1315
- finally {
1316
- vi.useRealTimers();
1317
- }
1318
- });
1319
- it('does not clear or stop a replacement session when timeout cancel hangs', async () => {
1320
- setupSuccessfulSpawn();
1321
- mockPrompt.mockReturnValue(new Promise(() => undefined));
1322
- mockCancel.mockReturnValue(new Promise(() => undefined));
1323
- const firstHandle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1324
- vi.useFakeTimers();
1325
- try {
1326
- const stalePrompt = manager.sendPrompt('session-1', [{ type: 'text', text: 'old prompt' }], 100);
1327
- const staleRejection = stalePrompt.catch((error) => error);
1328
- await vi.advanceTimersByTimeAsync(100);
1329
- expect(mockCancel).toHaveBeenCalledTimes(1);
1330
- const internalManager = manager;
1331
- internalManager.sessions.delete('session-1');
1332
- const replacementChild = setupSuccessfulSpawn();
1333
- const replacementHandle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1334
- replacementHandle.isPromptInFlight = true;
1335
- await vi.advanceTimersByTimeAsync(5000);
1336
- await expect(staleRejection).resolves.toBeInstanceOf(PromptTimeoutError);
1337
- expect(replacementHandle.isPromptInFlight).toBe(true);
1338
- expect(replacementChild.kill).not.toHaveBeenCalled();
1339
- expect(manager.getClient('session-1')).toBe(replacementHandle);
1340
- expect(firstHandle.isPromptInFlight).toBe(false);
1341
- }
1342
- finally {
1343
- vi.useRealTimers();
1344
- }
1345
- });
1346
- it('does not cancel a replacement session when an old prompt timeout fires', async () => {
1347
- const firstChild = setupSuccessfulSpawn();
1348
- mockPrompt.mockReturnValueOnce(new Promise(() => undefined));
1349
- mockCancel.mockResolvedValue(undefined);
1350
- const firstHandle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1351
- firstChild.kill = vi.fn((signal) => {
1352
- if (signal === 'SIGTERM') {
1353
- firstChild.killed = true;
1354
- firstChild.exitCode = 0;
1355
- firstChild.emit('exit', 0, null);
1356
- }
1357
- return true;
1358
- });
1359
- vi.useFakeTimers();
1360
- try {
1361
- const stalePrompt = manager.sendPrompt('session-1', [{ type: 'text', text: 'old prompt' }], 100);
1362
- const staleRejection = stalePrompt.catch((error) => error);
1363
- await manager.stopClient('session-1');
1364
- expect(manager.getClient('session-1')).toBeUndefined();
1365
- const replacementPrompt = createDeferred();
1366
- setupSuccessfulSpawn();
1367
- mockPrompt.mockReturnValueOnce(replacementPrompt.promise);
1368
- const replacementHandle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1369
- const replacementSend = manager.sendPrompt('session-1', [
1370
- { type: 'text', text: 'new prompt' },
1371
- ]);
1372
- await Promise.resolve();
1373
- expect(replacementHandle.isPromptInFlight).toBe(true);
1374
- const cancelCallsBeforeStaleTimeout = mockCancel.mock.calls.length;
1375
- await vi.advanceTimersByTimeAsync(100);
1376
- await expect(staleRejection).resolves.toBeInstanceOf(PromptTimeoutError);
1377
- expect(mockCancel).toHaveBeenCalledTimes(cancelCallsBeforeStaleTimeout);
1378
- expect(replacementHandle.isPromptInFlight).toBe(true);
1379
- expect(firstHandle.isPromptInFlight).toBe(false);
1380
- replacementPrompt.resolve({ stopReason: 'end_turn' });
1381
- await expect(replacementSend).resolves.toEqual({ stopReason: 'end_turn' });
1382
- expect(replacementHandle.isPromptInFlight).toBe(false);
1383
- }
1384
- finally {
1385
- vi.useRealTimers();
1386
- }
1387
- });
1388
- it('throws if no session found', async () => {
1389
- await expect(manager.sendPrompt('nonexistent', [{ type: 'text', text: 'Hello' }])).rejects.toThrow('No ACP session found');
1390
- });
1391
- });
1392
- describe('cancelPrompt', () => {
1393
- it('calls connection.cancel when prompt is in flight', async () => {
1394
- setupSuccessfulSpawn();
1395
- mockCancel.mockResolvedValue(undefined);
1396
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1397
- handle.isPromptInFlight = true;
1398
- const cancelled = await manager.cancelPrompt('session-1');
1399
- expect(mockCancel).toHaveBeenCalledWith({
1400
- sessionId: 'provider-session-123',
1401
- });
1402
- expect(cancelled).toBe(true);
1403
- });
1404
- it('does nothing when no prompt is in flight', async () => {
1405
- setupSuccessfulSpawn();
1406
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1407
- const cancelled = await manager.cancelPrompt('session-1');
1408
- expect(mockCancel).not.toHaveBeenCalled();
1409
- expect(cancelled).toBe(false);
1410
- });
1411
- it('does nothing for nonexistent session', async () => {
1412
- const cancelled = await manager.cancelPrompt('nonexistent');
1413
- expect(mockCancel).not.toHaveBeenCalled();
1414
- expect(cancelled).toBe(false);
1415
- });
1416
- });
1417
- describe('setConfigOption', () => {
1418
- it('updates cached config options from setSessionConfigOption response', async () => {
1419
- setupSuccessfulSpawn();
1420
- mockSetSessionConfigOption.mockResolvedValueOnce({
1421
- configOptions: [
1422
- {
1423
- id: 'model',
1424
- name: 'Model',
1425
- type: 'select',
1426
- category: 'model',
1427
- currentValue: 'opus',
1428
- options: [
1429
- { value: 'default', name: 'Default (recommended)', description: 'Opus 4.6 · best' },
1430
- { value: 'opus', name: 'Opus' },
1431
- ],
1432
- },
1433
- {
1434
- id: 'mode',
1435
- name: 'Mode',
1436
- type: 'select',
1437
- category: 'mode',
1438
- currentValue: 'plan',
1439
- options: [
1440
- { value: 'default', name: 'Default' },
1441
- { value: 'plan', name: 'Plan' },
1442
- ],
1443
- },
1444
- ],
1445
- });
1446
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1447
- await manager.setConfigOption('session-1', 'mode', 'plan');
1448
- const defaultModelOption = handle.configOptions
1449
- .find((option) => option.id === 'model')
1450
- ?.options.find((option) => 'value' in option && option.value === 'default');
1451
- expect(defaultModelOption).toMatchObject({
1452
- value: 'default',
1453
- name: 'Default — Opus 4.6',
1454
- });
1455
- expect(handle.configOptions.find((option) => option.id === 'mode')?.currentValue).toBe('plan');
1456
- });
1457
- it('throws when setSessionConfigOption call fails', async () => {
1458
- setupSuccessfulSpawn();
1459
- mockSetSessionConfigOption.mockRejectedValueOnce(new Error('Method not found'));
1460
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1461
- await expect(manager.setConfigOption('session-1', 'model', 'opus')).rejects.toThrow('Method not found');
1462
- });
1463
- it('fails fast when setSessionConfigOption response omits required categories', async () => {
1464
- setupSuccessfulSpawn();
1465
- mockSetSessionConfigOption.mockResolvedValueOnce({
1466
- configOptions: [
1467
- {
1468
- id: 'reasoning_effort',
1469
- name: 'Reasoning Effort',
1470
- type: 'select',
1471
- category: 'thought_level',
1472
- currentValue: 'medium',
1473
- options: [{ value: 'medium', name: 'Medium' }],
1474
- },
1475
- ],
1476
- });
1477
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1478
- await expect(manager.setConfigOption('session-1', 'mode', 'plan')).rejects.toThrow('missing required config option categories: model, mode');
1479
- });
1480
- });
1481
- describe('setSessionMode', () => {
1482
- it('calls ACP setSessionMode and updates cached mode currentValue', async () => {
1483
- setupSuccessfulSpawn();
1484
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1485
- await manager.setSessionMode('session-1', 'plan');
1486
- expect(mockSetSessionMode).toHaveBeenCalledWith({
1487
- sessionId: 'provider-session-123',
1488
- modeId: 'plan',
1489
- });
1490
- expect(handle.configOptions.find((option) => option.id === 'mode')?.currentValue).toBe('plan');
1491
- });
1492
- it('throws when setSessionMode call fails', async () => {
1493
- setupSuccessfulSpawn();
1494
- mockSetSessionMode.mockRejectedValueOnce(new Error('Invalid mode'));
1495
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1496
- await expect(manager.setSessionMode('session-1', 'acceptEdits')).rejects.toThrow('Invalid mode');
1497
- });
1498
- });
1499
- describe('setSessionModel', () => {
1500
- it('uses unstable_setSessionModel for CLAUDE and updates cached model currentValue', async () => {
1501
- setupSuccessfulSpawn();
1502
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1503
- await manager.setSessionModel('session-1', 'opus');
1504
- expect(mockSetSessionModel).toHaveBeenCalledWith({
1505
- sessionId: 'provider-session-123',
1506
- modelId: 'opus',
1507
- });
1508
- expect(mockSetSessionConfigOption).not.toHaveBeenCalled();
1509
- expect(handle.configOptions.find((option) => option.id === 'model')?.currentValue).toBe('opus');
1510
- });
1511
- it('falls back to setSessionConfigOption when unstable_setSessionModel is unavailable', async () => {
1512
- setupSuccessfulSpawn();
1513
- mockSetSessionModel.mockRejectedValueOnce({ code: -32_601, message: 'Method not found' });
1514
- mockSetSessionConfigOption.mockResolvedValueOnce({
1515
- configOptions: [
1516
- {
1517
- id: 'model',
1518
- name: 'Model',
1519
- type: 'select',
1520
- category: 'model',
1521
- currentValue: 'opus',
1522
- options: [
1523
- { value: 'sonnet', name: 'Sonnet' },
1524
- { value: 'opus', name: 'Opus' },
1525
- ],
1526
- },
1527
- {
1528
- id: 'mode',
1529
- name: 'Mode',
1530
- type: 'select',
1531
- category: 'mode',
1532
- currentValue: 'default',
1533
- options: [{ value: 'default', name: 'Default' }],
1534
- },
1535
- ],
1536
- });
1537
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1538
- await manager.setSessionModel('session-1', 'opus');
1539
- expect(mockSetSessionModel).toHaveBeenCalledWith({
1540
- sessionId: 'provider-session-123',
1541
- modelId: 'opus',
1542
- });
1543
- expect(mockSetSessionConfigOption).toHaveBeenCalledWith({
1544
- sessionId: 'provider-session-123',
1545
- configId: 'model',
1546
- value: 'opus',
1547
- });
1548
- expect(handle.configOptions.find((option) => option.id === 'model')?.currentValue).toBe('opus');
1549
- });
1550
- it('uses setSessionConfigOption path for CODEX model updates', async () => {
1551
- setupSuccessfulSpawn();
1552
- await manager.getOrCreateClient('session-1', { ...defaultOptions(), provider: 'CODEX' }, defaultHandlers(), defaultContext());
1553
- await manager.setSessionModel('session-1', 'gpt-5.2-codex');
1554
- expect(mockSetSessionModel).not.toHaveBeenCalled();
1555
- expect(mockSetSessionConfigOption).toHaveBeenCalledWith({
1556
- sessionId: 'provider-session-123',
1557
- configId: 'model',
1558
- value: 'gpt-5.2-codex',
1559
- });
1560
- });
1561
- });
1562
- describe('session status methods', () => {
1563
- it('isSessionRunning returns true for active session', async () => {
1564
- setupSuccessfulSpawn();
1565
- await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1566
- expect(manager.isSessionRunning('session-1')).toBe(true);
1567
- expect(manager.isSessionRunning('nonexistent')).toBe(false);
1568
- });
1569
- it('isSessionWorking returns true when prompt is in flight', async () => {
1570
- setupSuccessfulSpawn();
1571
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1572
- expect(manager.isSessionWorking('session-1')).toBe(false);
1573
- handle.isPromptInFlight = true;
1574
- expect(manager.isSessionWorking('session-1')).toBe(true);
1575
- });
1576
- it('isAnySessionWorking checks multiple sessions', async () => {
1577
- setupSuccessfulSpawn();
1578
- const handle = await manager.getOrCreateClient('session-1', defaultOptions(), defaultHandlers(), defaultContext());
1579
- expect(manager.isAnySessionWorking(['session-1', 'session-2'])).toBe(false);
1580
- handle.isPromptInFlight = true;
1581
- expect(manager.isAnySessionWorking(['session-1', 'session-2'])).toBe(true);
1582
- });
1583
- });
1584
- });
1585
- describe('AcpClientHandler', () => {
1586
- it('AcpEventCallback is a discriminated ACP runtime event union', () => {
1587
- const onEvent = (_sessionId, event) => {
1588
- if (event.type === 'acp_session_update') {
1589
- expect(event.update.sessionUpdate).toBe('agent_message_chunk');
1590
- return;
1591
- }
1592
- if (event.type === 'acp_permission_request') {
1593
- expect(event.params.toolCall.toolCallId).toBe('tc-1');
1594
- return;
1595
- }
1596
- expect(event.subagentId).toBe('child-1');
1597
- expect(event.change).toBe('updated');
1598
- };
1599
- onEvent('test-session', {
1600
- type: 'acp_session_update',
1601
- update: {
1602
- sessionUpdate: 'agent_message_chunk',
1603
- content: { type: 'text', text: 'Hello' },
1604
- },
1605
- });
1606
- onEvent('test-session', {
1607
- type: 'acp_permission_request',
1608
- requestId: 'req-1',
1609
- params: {
1610
- sessionId: 'provider-session-1',
1611
- toolCall: { toolCallId: 'tc-1', title: 'Write file' },
1612
- options: [{ optionId: 'allow-1', kind: 'allow_once', name: 'Allow once' }],
1613
- },
1614
- });
1615
- onEvent('test-session', {
1616
- type: 'acp_subagents_changed',
1617
- subagentId: 'child-1',
1618
- change: 'updated',
1619
- });
1620
- });
1621
- it('sessionUpdate emits logs through onLog callback', async () => {
1622
- const onEvent = vi.fn();
1623
- const onLog = vi.fn();
1624
- const handler = new AcpClientHandler('test-session', onEvent, undefined, onLog);
1625
- await handler.sessionUpdate({
1626
- sessionId: 'provider-session-1',
1627
- update: {
1628
- sessionUpdate: 'agent_message_chunk',
1629
- content: { type: 'text', text: 'Hello' },
1630
- },
1631
- });
1632
- expect(onLog).toHaveBeenCalledWith('test-session', {
1633
- eventType: 'acp_session_update',
1634
- sessionUpdate: 'agent_message_chunk',
1635
- data: expect.objectContaining({ sessionUpdate: 'agent_message_chunk' }),
1636
- });
1637
- });
1638
- it('sessionUpdate forwards all events as acp_session_update wrapper', async () => {
1639
- const onEvent = vi.fn();
1640
- const handler = new AcpClientHandler('test-session', onEvent);
1641
- await handler.sessionUpdate({
1642
- sessionId: 'provider-session-1',
1643
- update: {
1644
- sessionUpdate: 'agent_message_chunk',
1645
- content: { type: 'text', text: 'Hello' },
1646
- },
1647
- });
1648
- expect(onEvent).toHaveBeenCalledWith('test-session', {
1649
- type: 'acp_session_update',
1650
- update: {
1651
- sessionUpdate: 'agent_message_chunk',
1652
- content: { type: 'text', text: 'Hello' },
1653
- },
1654
- });
1655
- });
1656
- it('sessionUpdate forwards tool_call events as acp_session_update wrapper', async () => {
1657
- const onEvent = vi.fn();
1658
- const handler = new AcpClientHandler('test-session', onEvent);
1659
- await handler.sessionUpdate({
1660
- sessionId: 'provider-session-1',
1661
- update: {
1662
- sessionUpdate: 'tool_call',
1663
- toolCallId: 'tc-1',
1664
- title: 'Read file',
1665
- kind: 'read',
1666
- status: 'in_progress',
1667
- },
1668
- });
1669
- expect(onEvent).toHaveBeenCalledWith('test-session', {
1670
- type: 'acp_session_update',
1671
- update: {
1672
- sessionUpdate: 'tool_call',
1673
- toolCallId: 'tc-1',
1674
- title: 'Read file',
1675
- kind: 'read',
1676
- status: 'in_progress',
1677
- },
1678
- });
1679
- });
1680
- it('sessionUpdate forwards all event types including previously deferred ones', async () => {
1681
- const onEvent = vi.fn();
1682
- const handler = new AcpClientHandler('test-session', onEvent);
1683
- await handler.sessionUpdate({
1684
- sessionId: 'provider-session-1',
1685
- update: {
1686
- sessionUpdate: 'agent_thought_chunk',
1687
- content: { type: 'text', text: 'thinking...' },
1688
- },
1689
- });
1690
- expect(onEvent).toHaveBeenCalledWith('test-session', {
1691
- type: 'acp_session_update',
1692
- update: {
1693
- sessionUpdate: 'agent_thought_chunk',
1694
- content: { type: 'text', text: 'thinking...' },
1695
- },
1696
- });
1697
- });
1698
- it('requestPermission fails closed by default when no bridge exists', async () => {
1699
- const onEvent = vi.fn();
1700
- const handler = new AcpClientHandler('test-session', onEvent);
1701
- const result = await handler.requestPermission({
1702
- sessionId: 'provider-session-1',
1703
- toolCall: { toolCallId: 'tc-1', title: 'Write file' },
1704
- options: [
1705
- { optionId: 'reject-1', kind: 'reject_once', name: 'Deny' },
1706
- { optionId: 'allow-1', kind: 'allow_always', name: 'Allow Always' },
1707
- { optionId: 'allow-2', kind: 'allow_once', name: 'Allow Once' },
1708
- ],
1709
- });
1710
- expect(result).toEqual({
1711
- outcome: {
1712
- outcome: 'selected',
1713
- optionId: 'reject-1',
1714
- },
1715
- });
1716
- });
1717
- it('requestPermission selects a reject option when no bridge exists', async () => {
1718
- const onEvent = vi.fn();
1719
- const handler = new AcpClientHandler('test-session', onEvent);
1720
- const result = await handler.requestPermission({
1721
- sessionId: 'provider-session-1',
1722
- toolCall: { toolCallId: 'tc-1', title: 'Write file' },
1723
- options: [
1724
- { optionId: 'reject-1', kind: 'reject_once', name: 'Deny' },
1725
- { optionId: 'reject-2', kind: 'reject_always', name: 'Deny Always' },
1726
- ],
1727
- });
1728
- expect(result).toEqual({
1729
- outcome: {
1730
- outcome: 'selected',
1731
- optionId: 'reject-1',
1732
- },
1733
- });
1734
- });
1735
- });
1736
- //# sourceMappingURL=acp-runtime-manager.test.js.map