factory-factory 0.3.4 → 0.3.6

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 (313) hide show
  1. package/README.md +17 -0
  2. package/dist/client/assets/_basePickBy-CzLmZHC2.js +1 -0
  3. package/dist/client/assets/{_baseUniq-DisTPj-I.js → _baseUniq-B2vXSgXW.js} +1 -1
  4. package/dist/client/assets/arc-Dq49BrkB.js +1 -0
  5. package/dist/client/assets/architectureDiagram-VXUJARFQ-BGubq_o9.js +36 -0
  6. package/dist/client/assets/{blockDiagram-VD42YOAC-DXpmez0y.js → blockDiagram-VD42YOAC-CJ7hB7tD.js} +4 -4
  7. package/dist/client/assets/{c4Diagram-YG6GDRKO-C6sDxR49.js → c4Diagram-YG6GDRKO-C9-3yIl7.js} +3 -3
  8. package/dist/client/assets/channel-DMaON2vY.js +1 -0
  9. package/dist/client/assets/{chunk-4BX2VUAB-CQxlRbYu.js → chunk-4BX2VUAB-LA-tkKjD.js} +1 -1
  10. package/dist/client/assets/{chunk-55IACEB6-DxubFDep.js → chunk-55IACEB6-D8Jq3_Ne.js} +1 -1
  11. package/dist/client/assets/{chunk-B4BG7PRW-BtTQ0im9.js → chunk-B4BG7PRW-BbB1Mssd.js} +1 -1
  12. package/dist/client/assets/{chunk-DI55MBZ5-C2tNYDZj.js → chunk-DI55MBZ5-CpO3WS5m.js} +1 -1
  13. package/dist/client/assets/{chunk-FMBD7UC4-kRQRN6vP.js → chunk-FMBD7UC4-zaxR2CzR.js} +1 -1
  14. package/dist/client/assets/chunk-QN33PNHL-BMmRcEqx.js +1 -0
  15. package/dist/client/assets/{chunk-QZHKN3VN-BfxMFZDN.js → chunk-QZHKN3VN-CbCQqsiw.js} +1 -1
  16. package/dist/client/assets/chunk-TZMSLE5B-BhRzmVVB.js +1 -0
  17. package/dist/client/assets/classDiagram-2ON5EDUG-BKODUnN9.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-WZHVMYZB-BKODUnN9.js +1 -0
  19. package/dist/client/assets/clone-d5fivKBG.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-S5V4N54A-QPsUxyAe.js → cose-bilkent-S5V4N54A-BZtg5BPr.js} +1 -1
  21. package/dist/client/assets/{dagre-6UL2VRFP-BAmsmcnI.js → dagre-6UL2VRFP-DiejfPfI.js} +2 -2
  22. package/dist/client/assets/diagram-PSM6KHXK-CRE7v2e7.js +24 -0
  23. package/dist/client/assets/diagram-QEK2KX5R-DpAOzBlm.js +43 -0
  24. package/dist/client/assets/diagram-S2PKOQOG-BOJvuhJd.js +24 -0
  25. package/dist/client/assets/{erDiagram-Q2GNP2WA-DMKIVzp4.js → erDiagram-Q2GNP2WA-IM11uKRy.js} +4 -4
  26. package/dist/client/assets/{flowDiagram-NV44I4VS-op3xA_nS.js → flowDiagram-NV44I4VS-DTbQf_7g.js} +5 -5
  27. package/dist/client/assets/{ganttDiagram-JELNMOA3-nrnzVCJK.js → ganttDiagram-JELNMOA3-Bqd3rUDW.js} +2 -2
  28. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-Cd1j3VMN.js +65 -0
  29. package/dist/client/assets/{graph-D_lEcPMk.js → graph-D667hHAk.js} +1 -1
  30. package/dist/client/assets/{index-C2qHRaOH.js → index-BXRnTMjJ.js} +170 -171
  31. package/dist/client/assets/index-DllMnbgu.css +1 -0
  32. package/dist/client/assets/infoDiagram-HS3SLOUP-CzpZPq7Y.js +2 -0
  33. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-Bnhe4U1x.js → journeyDiagram-XKPGCS4Q-Br2GUbhE.js} +1 -1
  34. package/dist/client/assets/{kanban-definition-3W4ZIXB7-DpTaTXko.js → kanban-definition-3W4ZIXB7-D0SM1ldH.js} +6 -6
  35. package/dist/client/assets/{layout-HT5qr--Q.js → layout-BPE9Dzp9.js} +1 -1
  36. package/dist/client/assets/{linear-CDmQ8HG8.js → linear-5exZFNBA.js} +1 -1
  37. package/dist/client/assets/{mindmap-definition-VGOIOE7T-zDr7s4o2.js → mindmap-definition-VGOIOE7T-D1W9h2lc.js} +3 -3
  38. package/dist/client/assets/mobile-baseline-BHP-K4kd.js +10 -0
  39. package/dist/client/assets/pieDiagram-ADFJNKIX-DG-umOTY.js +30 -0
  40. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-DzdJzkAJ.js → quadrantDiagram-AYHSOK5B-Cb0ciONq.js} +1 -1
  41. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-ChrLzx8S.js → requirementDiagram-UZGBJVZJ-BKYaJZ83.js} +1 -1
  42. package/dist/client/assets/sankeyDiagram-TZEHDZUN-DkR9L4Vw.js +10 -0
  43. package/dist/client/assets/{sequenceDiagram-WL72ISMW-BHxEpSCU.js → sequenceDiagram-WL72ISMW-Cys03qhv.js} +6 -6
  44. package/dist/client/assets/stateDiagram-FKZM4ZOC-DQWCRtS7.js +1 -0
  45. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-DoWi8XaX.js +1 -0
  46. package/dist/client/assets/terminal-instance-CpEqekOB.js +1 -0
  47. package/dist/client/assets/{timeline-definition-IT6M3QCI-BcCmIxix.js → timeline-definition-IT6M3QCI-C0mVV_zL.js} +4 -4
  48. package/dist/client/assets/treemap-GDKQZRPO-DK-Wlxvy.js +160 -0
  49. package/dist/client/assets/{xychartDiagram-PRI3JC2R-DrgKBPUM.js → xychartDiagram-PRI3JC2R-CFg2MfK9.js} +4 -4
  50. package/dist/client/index.html +3 -3
  51. package/dist/prisma/generated/commonInputTypes.d.ts +69 -39
  52. package/dist/prisma/generated/commonInputTypes.d.ts.map +1 -1
  53. package/dist/prisma/generated/enums.d.ts +6 -0
  54. package/dist/prisma/generated/enums.d.ts.map +1 -1
  55. package/dist/prisma/generated/enums.js +6 -1
  56. package/dist/prisma/generated/enums.js.map +1 -1
  57. package/dist/prisma/generated/internal/class.d.ts.map +1 -1
  58. package/dist/prisma/generated/internal/class.js +12 -4
  59. package/dist/prisma/generated/internal/class.js.map +1 -1
  60. package/dist/prisma/generated/internal/prismaNamespace.d.ts +13 -7
  61. package/dist/prisma/generated/internal/prismaNamespace.d.ts.map +1 -1
  62. package/dist/prisma/generated/internal/prismaNamespace.js +11 -6
  63. package/dist/prisma/generated/internal/prismaNamespace.js.map +1 -1
  64. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts +10 -5
  65. package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  66. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js +9 -4
  67. package/dist/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
  68. package/dist/prisma/generated/models/Project.d.ts +63 -1
  69. package/dist/prisma/generated/models/Project.d.ts.map +1 -1
  70. package/dist/prisma/generated/models/Workspace.d.ts +130 -1
  71. package/dist/prisma/generated/models/Workspace.d.ts.map +1 -1
  72. package/dist/prompts/quick-actions/screenshots.md +12 -6
  73. package/dist/prompts/ratchet/dispatch.md +4 -0
  74. package/dist/src/backend/domains/linear/index.d.ts +3 -0
  75. package/dist/src/backend/domains/linear/index.d.ts.map +1 -0
  76. package/dist/src/backend/domains/linear/index.js +3 -0
  77. package/dist/src/backend/domains/linear/index.js.map +1 -0
  78. package/dist/src/backend/domains/linear/linear-client.service.d.ts +40 -0
  79. package/dist/src/backend/domains/linear/linear-client.service.d.ts.map +1 -0
  80. package/dist/src/backend/domains/linear/linear-client.service.js +134 -0
  81. package/dist/src/backend/domains/linear/linear-client.service.js.map +1 -0
  82. package/dist/src/backend/domains/linear/linear-state-sync.service.d.ts +7 -0
  83. package/dist/src/backend/domains/linear/linear-state-sync.service.d.ts.map +1 -0
  84. package/dist/src/backend/domains/linear/linear-state-sync.service.js +29 -0
  85. package/dist/src/backend/domains/linear/linear-state-sync.service.js.map +1 -0
  86. package/dist/src/backend/domains/ratchet/bridges.d.ts +5 -1
  87. package/dist/src/backend/domains/ratchet/bridges.d.ts.map +1 -1
  88. package/dist/src/backend/domains/ratchet/ratchet.service.d.ts +2 -0
  89. package/dist/src/backend/domains/ratchet/ratchet.service.d.ts.map +1 -1
  90. package/dist/src/backend/domains/ratchet/ratchet.service.js +43 -53
  91. package/dist/src/backend/domains/ratchet/ratchet.service.js.map +1 -1
  92. package/dist/src/backend/domains/ratchet/ratchet.service.test.js +61 -18
  93. package/dist/src/backend/domains/ratchet/ratchet.service.test.js.map +1 -1
  94. package/dist/src/backend/domains/session/acp/acp-runtime-manager.d.ts.map +1 -1
  95. package/dist/src/backend/domains/session/acp/acp-runtime-manager.js +5 -1
  96. package/dist/src/backend/domains/session/acp/acp-runtime-manager.js.map +1 -1
  97. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts +13 -2
  98. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts.map +1 -1
  99. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js +839 -106
  100. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js.map +1 -1
  101. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js +735 -8
  102. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js.map +1 -1
  103. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.d.ts +20 -0
  104. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.d.ts.map +1 -1
  105. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.js +16 -0
  106. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.js.map +1 -1
  107. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.test.js +15 -0
  108. package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.test.js.map +1 -1
  109. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.d.ts +2 -2
  110. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.d.ts.map +1 -1
  111. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.js +32 -1
  112. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.js.map +1 -1
  113. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.test.js +79 -9
  114. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.test.js.map +1 -1
  115. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.d.ts +2 -2
  116. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.d.ts.map +1 -1
  117. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.js +3 -1
  118. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.js.map +1 -1
  119. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.test.js +10 -1
  120. package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.test.js.map +1 -1
  121. package/dist/src/backend/domains/session/chat/chat-message-handlers/registry.js +2 -2
  122. package/dist/src/backend/domains/session/chat/chat-message-handlers/registry.js.map +1 -1
  123. package/dist/src/backend/domains/session/chat/chat-message-handlers/types.d.ts +1 -0
  124. package/dist/src/backend/domains/session/chat/chat-message-handlers/types.d.ts.map +1 -1
  125. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.d.ts +5 -1
  126. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.d.ts.map +1 -1
  127. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.js +39 -13
  128. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.js.map +1 -1
  129. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.test.js +81 -0
  130. package/dist/src/backend/domains/session/chat/chat-message-handlers.service.test.js.map +1 -1
  131. package/dist/src/backend/domains/session/data/codex-session-history-loader.service.d.ts.map +1 -1
  132. package/dist/src/backend/domains/session/data/codex-session-history-loader.service.js +12 -59
  133. package/dist/src/backend/domains/session/data/codex-session-history-loader.service.js.map +1 -1
  134. package/dist/src/backend/domains/session/data/codex-session-history-loader.service.test.js +11 -21
  135. package/dist/src/backend/domains/session/data/codex-session-history-loader.service.test.js.map +1 -1
  136. package/dist/src/backend/domains/session/data/session-data.service.d.ts +6 -0
  137. package/dist/src/backend/domains/session/data/session-data.service.d.ts.map +1 -1
  138. package/dist/src/backend/domains/session/lifecycle/session.service.d.ts +7 -0
  139. package/dist/src/backend/domains/session/lifecycle/session.service.d.ts.map +1 -1
  140. package/dist/src/backend/domains/session/lifecycle/session.service.js +105 -6
  141. package/dist/src/backend/domains/session/lifecycle/session.service.js.map +1 -1
  142. package/dist/src/backend/domains/session/lifecycle/session.service.test.js +84 -0
  143. package/dist/src/backend/domains/session/lifecycle/session.service.test.js.map +1 -1
  144. package/dist/src/backend/domains/session/session-domain.service.d.ts +8 -1
  145. package/dist/src/backend/domains/session/session-domain.service.d.ts.map +1 -1
  146. package/dist/src/backend/domains/session/session-domain.service.js +43 -2
  147. package/dist/src/backend/domains/session/session-domain.service.js.map +1 -1
  148. package/dist/src/backend/domains/session/session-domain.service.test.js +21 -0
  149. package/dist/src/backend/domains/session/session-domain.service.test.js.map +1 -1
  150. package/dist/src/backend/domains/session/store/session-store.types.d.ts +1 -1
  151. package/dist/src/backend/domains/session/store/session-store.types.d.ts.map +1 -1
  152. package/dist/src/backend/domains/session/store/session-transcript.d.ts +1 -0
  153. package/dist/src/backend/domains/session/store/session-transcript.d.ts.map +1 -1
  154. package/dist/src/backend/domains/session/store/session-transcript.js +8 -0
  155. package/dist/src/backend/domains/session/store/session-transcript.js.map +1 -1
  156. package/dist/src/backend/domains/workspace/lifecycle/creation.service.d.ts +9 -0
  157. package/dist/src/backend/domains/workspace/lifecycle/creation.service.d.ts.map +1 -1
  158. package/dist/src/backend/domains/workspace/lifecycle/creation.service.js +18 -0
  159. package/dist/src/backend/domains/workspace/lifecycle/creation.service.js.map +1 -1
  160. package/dist/src/backend/domains/workspace/lifecycle/creation.service.test.js +46 -0
  161. package/dist/src/backend/domains/workspace/lifecycle/creation.service.test.js.map +1 -1
  162. package/dist/src/backend/domains/workspace/lifecycle/data.service.d.ts +25 -0
  163. package/dist/src/backend/domains/workspace/lifecycle/data.service.d.ts.map +1 -1
  164. package/dist/src/backend/domains/workspace/query/project-management.service.d.ts +16 -0
  165. package/dist/src/backend/domains/workspace/query/project-management.service.d.ts.map +1 -1
  166. package/dist/src/backend/domains/workspace/query/project-management.service.js.map +1 -1
  167. package/dist/src/backend/domains/workspace/query/workspace-query.service.d.ts +6 -0
  168. package/dist/src/backend/domains/workspace/query/workspace-query.service.d.ts.map +1 -1
  169. package/dist/src/backend/interceptors/pr-detection.interceptor.d.ts.map +1 -1
  170. package/dist/src/backend/interceptors/pr-detection.interceptor.js +5 -1
  171. package/dist/src/backend/interceptors/pr-detection.interceptor.js.map +1 -1
  172. package/dist/src/backend/interceptors/pr-detection.interceptor.test.js +14 -0
  173. package/dist/src/backend/interceptors/pr-detection.interceptor.test.js.map +1 -1
  174. package/dist/src/backend/migrate.d.ts.map +1 -1
  175. package/dist/src/backend/migrate.js +13 -3
  176. package/dist/src/backend/migrate.js.map +1 -1
  177. package/dist/src/backend/migrate.test.js +44 -0
  178. package/dist/src/backend/migrate.test.js.map +1 -1
  179. package/dist/src/backend/orchestration/cli-health.service.d.ts +1 -0
  180. package/dist/src/backend/orchestration/cli-health.service.d.ts.map +1 -1
  181. package/dist/src/backend/orchestration/cli-health.service.js +16 -1
  182. package/dist/src/backend/orchestration/cli-health.service.js.map +1 -1
  183. package/dist/src/backend/orchestration/cli-health.service.test.js +23 -0
  184. package/dist/src/backend/orchestration/cli-health.service.test.js.map +1 -1
  185. package/dist/src/backend/orchestration/data-backup.service.d.ts.map +1 -1
  186. package/dist/src/backend/orchestration/data-backup.service.js +21 -1
  187. package/dist/src/backend/orchestration/data-backup.service.js.map +1 -1
  188. package/dist/src/backend/orchestration/data-backup.service.test.js +19 -9
  189. package/dist/src/backend/orchestration/data-backup.service.test.js.map +1 -1
  190. package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts.map +1 -1
  191. package/dist/src/backend/orchestration/event-collector.orchestrator.js +63 -3
  192. package/dist/src/backend/orchestration/event-collector.orchestrator.js.map +1 -1
  193. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js +49 -3
  194. package/dist/src/backend/orchestration/event-collector.orchestrator.test.js.map +1 -1
  195. package/dist/src/backend/orchestration/linear-config.helper.d.ts +9 -0
  196. package/dist/src/backend/orchestration/linear-config.helper.d.ts.map +1 -0
  197. package/dist/src/backend/orchestration/linear-config.helper.js +23 -0
  198. package/dist/src/backend/orchestration/linear-config.helper.js.map +1 -0
  199. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts +3 -0
  200. package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts.map +1 -1
  201. package/dist/src/backend/orchestration/workspace-init.orchestrator.d.ts.map +1 -1
  202. package/dist/src/backend/orchestration/workspace-init.orchestrator.js +228 -3
  203. package/dist/src/backend/orchestration/workspace-init.orchestrator.js.map +1 -1
  204. package/dist/src/backend/prompts/ratchet-dispatch.d.ts +8 -1
  205. package/dist/src/backend/prompts/ratchet-dispatch.d.ts.map +1 -1
  206. package/dist/src/backend/prompts/ratchet-dispatch.js +20 -3
  207. package/dist/src/backend/prompts/ratchet-dispatch.js.map +1 -1
  208. package/dist/src/backend/resource_accessors/project.accessor.d.ts +7 -1
  209. package/dist/src/backend/resource_accessors/project.accessor.d.ts.map +1 -1
  210. package/dist/src/backend/resource_accessors/project.accessor.js +8 -1
  211. package/dist/src/backend/resource_accessors/project.accessor.js.map +1 -1
  212. package/dist/src/backend/resource_accessors/workspace.accessor.d.ts +4 -1
  213. package/dist/src/backend/resource_accessors/workspace.accessor.d.ts.map +1 -1
  214. package/dist/src/backend/resource_accessors/workspace.accessor.js +3 -0
  215. package/dist/src/backend/resource_accessors/workspace.accessor.js.map +1 -1
  216. package/dist/src/backend/server.d.ts.map +1 -1
  217. package/dist/src/backend/server.js +11 -9
  218. package/dist/src/backend/server.js.map +1 -1
  219. package/dist/src/backend/services/constants.d.ts +1 -0
  220. package/dist/src/backend/services/constants.d.ts.map +1 -1
  221. package/dist/src/backend/services/constants.js +1 -0
  222. package/dist/src/backend/services/constants.js.map +1 -1
  223. package/dist/src/backend/services/crypto.service.d.ts +10 -0
  224. package/dist/src/backend/services/crypto.service.d.ts.map +1 -0
  225. package/dist/src/backend/services/crypto.service.js +61 -0
  226. package/dist/src/backend/services/crypto.service.js.map +1 -0
  227. package/dist/src/backend/trpc/admin.trpc.d.ts +14 -4
  228. package/dist/src/backend/trpc/admin.trpc.d.ts.map +1 -1
  229. package/dist/src/backend/trpc/index.d.ts +169 -9
  230. package/dist/src/backend/trpc/index.d.ts.map +1 -1
  231. package/dist/src/backend/trpc/index.js +2 -0
  232. package/dist/src/backend/trpc/index.js.map +1 -1
  233. package/dist/src/backend/trpc/linear.trpc.d.ts +44 -0
  234. package/dist/src/backend/trpc/linear.trpc.d.ts.map +1 -0
  235. package/dist/src/backend/trpc/linear.trpc.js +69 -0
  236. package/dist/src/backend/trpc/linear.trpc.js.map +1 -0
  237. package/dist/src/backend/trpc/project.trpc.d.ts +50 -5
  238. package/dist/src/backend/trpc/project.trpc.d.ts.map +1 -1
  239. package/dist/src/backend/trpc/project.trpc.js +46 -18
  240. package/dist/src/backend/trpc/project.trpc.js.map +1 -1
  241. package/dist/src/backend/trpc/session.trpc.d.ts +13 -0
  242. package/dist/src/backend/trpc/session.trpc.d.ts.map +1 -1
  243. package/dist/src/backend/trpc/session.trpc.js +5 -1
  244. package/dist/src/backend/trpc/session.trpc.js.map +1 -1
  245. package/dist/src/backend/trpc/workspace/git.trpc.d.ts +10 -0
  246. package/dist/src/backend/trpc/workspace/git.trpc.d.ts.map +1 -1
  247. package/dist/src/backend/trpc/workspace/git.trpc.js +25 -0
  248. package/dist/src/backend/trpc/workspace/git.trpc.js.map +1 -1
  249. package/dist/src/backend/trpc/workspace/init.trpc.d.ts +3 -0
  250. package/dist/src/backend/trpc/workspace/init.trpc.d.ts.map +1 -1
  251. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts +8 -0
  252. package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts.map +1 -1
  253. package/dist/src/backend/trpc/workspace.trpc.d.ts +49 -0
  254. package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
  255. package/dist/src/backend/trpc/workspace.trpc.js +20 -4
  256. package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
  257. package/dist/src/cli/index.js +17 -91
  258. package/dist/src/cli/index.js.map +1 -1
  259. package/dist/src/cli/proxy.d.ts +80 -0
  260. package/dist/src/cli/proxy.d.ts.map +1 -0
  261. package/dist/src/cli/proxy.js +1054 -0
  262. package/dist/src/cli/proxy.js.map +1 -0
  263. package/dist/src/cli/proxy.test.d.ts +2 -0
  264. package/dist/src/cli/proxy.test.d.ts.map +1 -0
  265. package/dist/src/cli/proxy.test.js +249 -0
  266. package/dist/src/cli/proxy.test.js.map +1 -0
  267. package/dist/src/cli/runtime-utils.d.ts +9 -0
  268. package/dist/src/cli/runtime-utils.d.ts.map +1 -0
  269. package/dist/src/cli/runtime-utils.js +86 -0
  270. package/dist/src/cli/runtime-utils.js.map +1 -0
  271. package/dist/src/shared/core/enums.d.ts +6 -0
  272. package/dist/src/shared/core/enums.d.ts.map +1 -1
  273. package/dist/src/shared/core/enums.js +5 -0
  274. package/dist/src/shared/core/enums.js.map +1 -1
  275. package/dist/src/shared/core/index.d.ts +1 -1
  276. package/dist/src/shared/core/index.d.ts.map +1 -1
  277. package/dist/src/shared/core/index.js +1 -1
  278. package/dist/src/shared/core/index.js.map +1 -1
  279. package/dist/src/shared/schemas/export-data.schema.d.ts +19 -1
  280. package/dist/src/shared/schemas/export-data.schema.d.ts.map +1 -1
  281. package/dist/src/shared/schemas/export-data.schema.js +8 -2
  282. package/dist/src/shared/schemas/export-data.schema.js.map +1 -1
  283. package/dist/src/shared/schemas/issue-tracker-config.schema.d.ts +35 -0
  284. package/dist/src/shared/schemas/issue-tracker-config.schema.d.ts.map +1 -0
  285. package/dist/src/shared/schemas/issue-tracker-config.schema.js +29 -0
  286. package/dist/src/shared/schemas/issue-tracker-config.schema.js.map +1 -0
  287. package/dist/tsconfig.backend.tsbuildinfo +1 -1
  288. package/package.json +40 -36
  289. package/prisma/migrations/20260217190642_add_linear_integration/migration.sql +34 -0
  290. package/prisma/schema.prisma +13 -0
  291. package/prompts/quick-actions/screenshots.md +12 -6
  292. package/prompts/ratchet/dispatch.md +4 -0
  293. package/dist/client/assets/_basePickBy-kS1IrKFQ.js +0 -1
  294. package/dist/client/assets/arc-CWpVTRns.js +0 -1
  295. package/dist/client/assets/architectureDiagram-VXUJARFQ-Dp1AYPMt.js +0 -36
  296. package/dist/client/assets/channel-D5BCeybW.js +0 -1
  297. package/dist/client/assets/chunk-QN33PNHL-DP72lCp6.js +0 -1
  298. package/dist/client/assets/chunk-TZMSLE5B-G3wPktxK.js +0 -1
  299. package/dist/client/assets/classDiagram-2ON5EDUG-BUS1JDwr.js +0 -1
  300. package/dist/client/assets/classDiagram-v2-WZHVMYZB-BUS1JDwr.js +0 -1
  301. package/dist/client/assets/clone-C5xhPZw8.js +0 -1
  302. package/dist/client/assets/diagram-PSM6KHXK-QA-3O0wr.js +0 -24
  303. package/dist/client/assets/diagram-QEK2KX5R-VZkRJLXU.js +0 -43
  304. package/dist/client/assets/diagram-S2PKOQOG-DwLmogjW.js +0 -24
  305. package/dist/client/assets/gitGraphDiagram-NY62KEGX-CK2ytvyZ.js +0 -65
  306. package/dist/client/assets/index-D5ywoSOH.css +0 -1
  307. package/dist/client/assets/infoDiagram-WHAUD3N6-DO5X8HkW.js +0 -2
  308. package/dist/client/assets/pieDiagram-ADFJNKIX-BVBJCvYL.js +0 -30
  309. package/dist/client/assets/sankeyDiagram-TZEHDZUN-GIzxIQQB.js +0 -10
  310. package/dist/client/assets/stateDiagram-FKZM4ZOC-ByvdYZKl.js +0 -1
  311. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-ynQtAOKH.js +0 -1
  312. package/dist/client/assets/terminal-instance-xdECz0dx.js +0 -1
  313. package/dist/client/assets/treemap-KMMF4GRG-CVpLLzhu.js +0 -128
@@ -45,7 +45,7 @@ const DEFAULT_COLLABORATION_MODES = [
45
45
  { name: 'Default', mode: 'default' },
46
46
  { name: 'Plan', mode: 'plan' },
47
47
  ];
48
- async function initializeAdapterWithDefaultModel(adapter, codex) {
48
+ async function initializeAdapterWithDefaultModel(adapter, codex, options) {
49
49
  codex.request.mockResolvedValueOnce({});
50
50
  codex.request.mockResolvedValueOnce({
51
51
  requirements: {
@@ -54,7 +54,7 @@ async function initializeAdapterWithDefaultModel(adapter, codex) {
54
54
  },
55
55
  });
56
56
  codex.request.mockResolvedValueOnce({
57
- data: DEFAULT_COLLABORATION_MODES,
57
+ data: options?.collaborationModes ?? DEFAULT_COLLABORATION_MODES,
58
58
  nextCursor: null,
59
59
  });
60
60
  codex.request.mockResolvedValueOnce({
@@ -327,6 +327,11 @@ describe('CodexAppServerAcpAdapter', () => {
327
327
  id: 'item_c1',
328
328
  command: 'pwd',
329
329
  },
330
+ {
331
+ type: 'reasoning',
332
+ id: 'item_r1',
333
+ summary: [{ type: 'summary_text', text: '**Thinking through replay**' }],
334
+ },
330
335
  ],
331
336
  },
332
337
  ],
@@ -340,9 +345,506 @@ describe('CodexAppServerAcpAdapter', () => {
340
345
  const updates = connection.sessionUpdate.mock.calls.map((call) => call[0].update);
341
346
  expect(updates.some((update) => update.sessionUpdate === 'user_message_chunk')).toBe(true);
342
347
  expect(updates.some((update) => update.sessionUpdate === 'agent_message_chunk')).toBe(true);
348
+ expect(updates.some((update) => update.sessionUpdate === 'agent_thought_chunk' &&
349
+ update.content?.type === 'text' &&
350
+ update.content.text === '**Thinking through replay**')).toBe(true);
343
351
  expect(updates.some((update) => update.sessionUpdate === 'tool_call' &&
344
352
  update.status === 'completed' &&
345
- update.toolCallId === 'codex:thread_abc:turn_1:item_c1')).toBe(true);
353
+ update.toolCallId === 'item_c1')).toBe(true);
354
+ });
355
+ it('does not duplicate replayed tool and reasoning updates when matching live events arrive', async () => {
356
+ const { connection } = createMockConnection();
357
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
358
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
359
+ await initializeAdapterWithDefaultModel(adapter, codex);
360
+ codex.request.mockResolvedValueOnce({
361
+ thread: { id: 'thread_replay_dedupe', cwd: '/tmp/workspace' },
362
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
363
+ reasoningEffort: 'medium',
364
+ });
365
+ codex.request.mockResolvedValueOnce({
366
+ thread: {
367
+ id: 'thread_replay_dedupe',
368
+ turns: [
369
+ {
370
+ id: 'turn_replay_dedupe',
371
+ items: [
372
+ {
373
+ type: 'commandExecution',
374
+ id: 'item_replayed_command',
375
+ command: 'cat README.md',
376
+ },
377
+ {
378
+ type: 'reasoning',
379
+ id: 'item_replayed_reasoning',
380
+ summary: [{ type: 'summary_text', text: '**From replay**' }],
381
+ },
382
+ ],
383
+ },
384
+ ],
385
+ },
386
+ });
387
+ await adapter.loadSession({
388
+ sessionId: 'sess_thread_replay_dedupe',
389
+ cwd: '/tmp/workspace',
390
+ mcpServers: [],
391
+ });
392
+ connection.sessionUpdate.mockClear();
393
+ await adapter.handleCodexNotification('item/started', {
394
+ threadId: 'thread_replay_dedupe',
395
+ turnId: 'turn_replay_dedupe',
396
+ item: {
397
+ type: 'commandExecution',
398
+ id: 'item_replayed_command',
399
+ status: 'inProgress',
400
+ command: 'cat README.md',
401
+ },
402
+ });
403
+ await adapter.handleCodexNotification('item/completed', {
404
+ threadId: 'thread_replay_dedupe',
405
+ turnId: 'turn_replay_dedupe',
406
+ item: {
407
+ type: 'commandExecution',
408
+ id: 'item_replayed_command',
409
+ status: 'completed',
410
+ command: 'cat README.md',
411
+ },
412
+ });
413
+ await adapter.handleCodexNotification('item/reasoning/summaryTextDelta', {
414
+ threadId: 'thread_replay_dedupe',
415
+ turnId: 'turn_replay_dedupe',
416
+ itemId: 'item_replayed_reasoning',
417
+ delta: '**From live**',
418
+ });
419
+ await adapter.handleCodexNotification('item/completed', {
420
+ threadId: 'thread_replay_dedupe',
421
+ turnId: 'turn_replay_dedupe',
422
+ item: {
423
+ type: 'reasoning',
424
+ id: 'item_replayed_reasoning',
425
+ status: 'completed',
426
+ summary: [{ type: 'summary_text', text: '**From live**' }],
427
+ },
428
+ });
429
+ expect(connection.sessionUpdate).not.toHaveBeenCalled();
430
+ });
431
+ it('prefers codex callId for tool call ids and enriches command metadata', async () => {
432
+ const { connection } = createMockConnection();
433
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
434
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
435
+ await initializeAdapterWithDefaultModel(adapter, codex);
436
+ codex.request.mockResolvedValueOnce({
437
+ thread: { id: 'thread_call_id', cwd: '/tmp/workspace' },
438
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
439
+ reasoningEffort: 'medium',
440
+ });
441
+ await adapter.newSession({
442
+ cwd: '/tmp/workspace',
443
+ mcpServers: [],
444
+ });
445
+ await adapter.handleCodexNotification('item/started', {
446
+ threadId: 'thread_call_id',
447
+ turnId: 'turn_call_id',
448
+ item: {
449
+ type: 'commandExecution',
450
+ id: 'item_call_id',
451
+ callId: 'call_123',
452
+ status: 'inProgress',
453
+ command: 'cat README.md',
454
+ },
455
+ });
456
+ await adapter.handleCodexNotification('item/completed', {
457
+ threadId: 'thread_call_id',
458
+ turnId: 'turn_call_id',
459
+ item: {
460
+ type: 'commandExecution',
461
+ id: 'item_call_id',
462
+ callId: 'call_123',
463
+ status: 'completed',
464
+ command: 'cat README.md',
465
+ },
466
+ });
467
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
468
+ [
469
+ expect.objectContaining({
470
+ update: expect.objectContaining({
471
+ sessionUpdate: 'tool_call',
472
+ toolCallId: 'call_123',
473
+ title: 'Read README.md',
474
+ kind: 'read',
475
+ locations: [{ path: '/tmp/workspace/README.md' }],
476
+ }),
477
+ }),
478
+ ],
479
+ [
480
+ expect.objectContaining({
481
+ update: expect.objectContaining({
482
+ sessionUpdate: 'tool_call_update',
483
+ toolCallId: 'call_123',
484
+ title: 'Read README.md',
485
+ kind: 'read',
486
+ }),
487
+ }),
488
+ ],
489
+ ]));
490
+ });
491
+ it('synthesizes completion when command output hands off to a session id', async () => {
492
+ const { connection } = createMockConnection();
493
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
494
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
495
+ await initializeAdapterWithDefaultModel(adapter, codex);
496
+ codex.request.mockResolvedValueOnce({
497
+ thread: { id: 'thread_command_handoff', cwd: '/tmp/workspace' },
498
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
499
+ reasoningEffort: 'medium',
500
+ });
501
+ await adapter.newSession({
502
+ cwd: '/tmp/workspace',
503
+ mcpServers: [],
504
+ });
505
+ await adapter.handleCodexNotification('item/started', {
506
+ threadId: 'thread_command_handoff',
507
+ turnId: 'turn_command_handoff',
508
+ item: {
509
+ type: 'commandExecution',
510
+ id: 'item_command_handoff',
511
+ callId: 'call_command_handoff',
512
+ status: 'inProgress',
513
+ command: 'git commit -m "test"',
514
+ },
515
+ });
516
+ await adapter.handleCodexNotification('item/commandExecution/outputDelta', {
517
+ threadId: 'thread_command_handoff',
518
+ turnId: 'turn_command_handoff',
519
+ itemId: 'item_command_handoff',
520
+ delta: 'Process running with session ID 96081',
521
+ });
522
+ await adapter.handleCodexNotification('item/commandExecution/outputDelta', {
523
+ threadId: 'thread_command_handoff',
524
+ turnId: 'turn_command_handoff',
525
+ itemId: 'item_command_handoff',
526
+ delta: 'still running',
527
+ });
528
+ const updates = connection.sessionUpdate.mock.calls.map((call) => call[0].update);
529
+ const inProgressUpdates = updates.filter((update) => update.sessionUpdate === 'tool_call_update' &&
530
+ update.toolCallId === 'call_command_handoff' &&
531
+ update.status === 'in_progress');
532
+ expect(inProgressUpdates).toHaveLength(1);
533
+ expect(updates).toEqual(expect.arrayContaining([
534
+ expect.objectContaining({
535
+ sessionUpdate: 'tool_call_update',
536
+ toolCallId: 'call_command_handoff',
537
+ status: 'completed',
538
+ rawOutput: 'Process running with session ID 96081',
539
+ }),
540
+ ]));
541
+ });
542
+ it('does not synthesize completion for normal output that mentions session handoff text', async () => {
543
+ const { connection } = createMockConnection();
544
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
545
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
546
+ await initializeAdapterWithDefaultModel(adapter, codex);
547
+ codex.request.mockResolvedValueOnce({
548
+ thread: { id: 'thread_command_log_output', cwd: '/tmp/workspace' },
549
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
550
+ reasoningEffort: 'medium',
551
+ });
552
+ await adapter.newSession({
553
+ cwd: '/tmp/workspace',
554
+ mcpServers: [],
555
+ });
556
+ await adapter.handleCodexNotification('item/started', {
557
+ threadId: 'thread_command_log_output',
558
+ turnId: 'turn_command_log_output',
559
+ item: {
560
+ type: 'commandExecution',
561
+ id: 'item_command_log_output',
562
+ callId: 'call_command_log_output',
563
+ status: 'inProgress',
564
+ command: 'bash script.sh',
565
+ },
566
+ });
567
+ await adapter.handleCodexNotification('item/commandExecution/outputDelta', {
568
+ threadId: 'thread_command_log_output',
569
+ turnId: 'turn_command_log_output',
570
+ itemId: 'item_command_log_output',
571
+ delta: 'worker log: process running with session ID 96081 and waiting',
572
+ });
573
+ await adapter.handleCodexNotification('item/commandExecution/outputDelta', {
574
+ threadId: 'thread_command_log_output',
575
+ turnId: 'turn_command_log_output',
576
+ itemId: 'item_command_log_output',
577
+ delta: 'still running',
578
+ });
579
+ const updates = connection.sessionUpdate.mock.calls.map((call) => call[0].update);
580
+ const completedUpdates = updates.filter((update) => update.sessionUpdate === 'tool_call_update' &&
581
+ update.toolCallId === 'call_command_log_output' &&
582
+ update.status === 'completed');
583
+ expect(completedUpdates).toHaveLength(0);
584
+ expect(updates).toEqual(expect.arrayContaining([
585
+ expect.objectContaining({
586
+ sessionUpdate: 'tool_call_update',
587
+ toolCallId: 'call_command_log_output',
588
+ status: 'in_progress',
589
+ rawOutput: 'worker log: process running with session ID 96081 and waiting',
590
+ }),
591
+ expect.objectContaining({
592
+ sessionUpdate: 'tool_call_update',
593
+ toolCallId: 'call_command_log_output',
594
+ status: 'in_progress',
595
+ rawOutput: 'still running',
596
+ }),
597
+ ]));
598
+ });
599
+ it('parses escaped quotes in quoted command arguments for metadata', async () => {
600
+ const { connection } = createMockConnection();
601
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
602
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
603
+ await initializeAdapterWithDefaultModel(adapter, codex);
604
+ codex.request.mockResolvedValueOnce({
605
+ thread: { id: 'thread_escaped_quotes', cwd: '/tmp/workspace' },
606
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
607
+ reasoningEffort: 'medium',
608
+ });
609
+ await adapter.newSession({
610
+ cwd: '/tmp/workspace',
611
+ mcpServers: [],
612
+ });
613
+ await adapter.handleCodexNotification('item/started', {
614
+ threadId: 'thread_escaped_quotes',
615
+ turnId: 'turn_escaped_quotes',
616
+ item: {
617
+ type: 'commandExecution',
618
+ id: 'item_escaped_quotes',
619
+ status: 'inProgress',
620
+ command: 'cat "nested \\"quotes\\".md"',
621
+ },
622
+ });
623
+ await adapter.handleCodexNotification('item/completed', {
624
+ threadId: 'thread_escaped_quotes',
625
+ turnId: 'turn_escaped_quotes',
626
+ item: {
627
+ type: 'commandExecution',
628
+ id: 'item_escaped_quotes',
629
+ status: 'completed',
630
+ command: 'cat "nested \\"quotes\\".md"',
631
+ },
632
+ });
633
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
634
+ [
635
+ expect.objectContaining({
636
+ update: expect.objectContaining({
637
+ sessionUpdate: 'tool_call',
638
+ title: 'Read nested "quotes".md',
639
+ kind: 'read',
640
+ locations: [{ path: '/tmp/workspace/nested "quotes".md' }],
641
+ }),
642
+ }),
643
+ ],
644
+ [
645
+ expect.objectContaining({
646
+ update: expect.objectContaining({
647
+ sessionUpdate: 'tool_call_update',
648
+ title: 'Read nested "quotes".md',
649
+ kind: 'read',
650
+ locations: [{ path: '/tmp/workspace/nested "quotes".md' }],
651
+ }),
652
+ }),
653
+ ],
654
+ ]));
655
+ });
656
+ it('parses escaped single quotes and escaped spaces in command metadata', async () => {
657
+ const { connection } = createMockConnection();
658
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
659
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
660
+ await initializeAdapterWithDefaultModel(adapter, codex);
661
+ codex.request.mockResolvedValueOnce({
662
+ thread: { id: 'thread_escaped_single_quotes', cwd: '/tmp/workspace' },
663
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
664
+ reasoningEffort: 'medium',
665
+ });
666
+ await adapter.newSession({
667
+ cwd: '/tmp/workspace',
668
+ mcpServers: [],
669
+ });
670
+ await adapter.handleCodexNotification('item/started', {
671
+ threadId: 'thread_escaped_single_quotes',
672
+ turnId: 'turn_escaped_single_quotes',
673
+ item: {
674
+ type: 'commandExecution',
675
+ id: 'item_escaped_single_quotes',
676
+ status: 'inProgress',
677
+ command: "cat 'it\\'s file.txt'",
678
+ },
679
+ });
680
+ await adapter.handleCodexNotification('item/completed', {
681
+ threadId: 'thread_escaped_single_quotes',
682
+ turnId: 'turn_escaped_single_quotes',
683
+ item: {
684
+ type: 'commandExecution',
685
+ id: 'item_escaped_single_quotes',
686
+ status: 'completed',
687
+ command: "cat 'it\\'s file.txt'",
688
+ },
689
+ });
690
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
691
+ [
692
+ expect.objectContaining({
693
+ update: expect.objectContaining({
694
+ sessionUpdate: 'tool_call',
695
+ title: "Read it's file.txt",
696
+ kind: 'read',
697
+ locations: [{ path: "/tmp/workspace/it's file.txt" }],
698
+ }),
699
+ }),
700
+ ],
701
+ [
702
+ expect.objectContaining({
703
+ update: expect.objectContaining({
704
+ sessionUpdate: 'tool_call_update',
705
+ title: "Read it's file.txt",
706
+ kind: 'read',
707
+ locations: [{ path: "/tmp/workspace/it's file.txt" }],
708
+ }),
709
+ }),
710
+ ],
711
+ ]));
712
+ });
713
+ it('derives command metadata from actionable chained subcommands', async () => {
714
+ const { connection } = createMockConnection();
715
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
716
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
717
+ await initializeAdapterWithDefaultModel(adapter, codex);
718
+ codex.request.mockResolvedValueOnce({
719
+ thread: { id: 'thread_chained_command', cwd: '/tmp/workspace' },
720
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
721
+ reasoningEffort: 'medium',
722
+ });
723
+ await adapter.newSession({
724
+ cwd: '/tmp/workspace',
725
+ mcpServers: [],
726
+ });
727
+ await adapter.handleCodexNotification('item/started', {
728
+ threadId: 'thread_chained_command',
729
+ turnId: 'turn_chained_command',
730
+ item: {
731
+ type: 'commandExecution',
732
+ id: 'item_chained_command',
733
+ status: 'inProgress',
734
+ command: 'cd src && rg "TODO" README.md',
735
+ },
736
+ });
737
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
738
+ [
739
+ expect.objectContaining({
740
+ update: expect.objectContaining({
741
+ sessionUpdate: 'tool_call',
742
+ title: 'Search TODO in README.md',
743
+ kind: 'search',
744
+ locations: [{ path: '/tmp/workspace/README.md' }],
745
+ }),
746
+ }),
747
+ ],
748
+ ]));
749
+ });
750
+ it('keeps escaped apostrophes inside single quotes when splitting chained commands', async () => {
751
+ const { connection } = createMockConnection();
752
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
753
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
754
+ await initializeAdapterWithDefaultModel(adapter, codex);
755
+ codex.request.mockResolvedValueOnce({
756
+ thread: { id: 'thread_chain_single_quote_escape', cwd: '/tmp/workspace' },
757
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
758
+ reasoningEffort: 'medium',
759
+ });
760
+ await adapter.newSession({
761
+ cwd: '/tmp/workspace',
762
+ mcpServers: [],
763
+ });
764
+ await adapter.handleCodexNotification('item/started', {
765
+ threadId: 'thread_chain_single_quote_escape',
766
+ turnId: 'turn_chain_single_quote_escape',
767
+ item: {
768
+ type: 'commandExecution',
769
+ id: 'item_chain_single_quote_escape',
770
+ status: 'inProgress',
771
+ command: "cat 'it\\'s file.txt' && rg TODO README.md",
772
+ },
773
+ });
774
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
775
+ [
776
+ expect.objectContaining({
777
+ update: expect.objectContaining({
778
+ sessionUpdate: 'tool_call',
779
+ title: "Read it's file.txt, Search TODO in README.md",
780
+ kind: 'read',
781
+ locations: [
782
+ { path: "/tmp/workspace/it's file.txt" },
783
+ { path: '/tmp/workspace/README.md' },
784
+ ],
785
+ }),
786
+ }),
787
+ ],
788
+ ]));
789
+ });
790
+ it('avoids duplicate thought chunks when reasoning started item already contains summary text', async () => {
791
+ const { connection } = createMockConnection();
792
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
793
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
794
+ await initializeAdapterWithDefaultModel(adapter, codex);
795
+ codex.request.mockResolvedValueOnce({
796
+ thread: { id: 'thread_reasoning', cwd: '/tmp/workspace' },
797
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
798
+ reasoningEffort: 'medium',
799
+ });
800
+ await adapter.newSession({
801
+ cwd: '/tmp/workspace',
802
+ mcpServers: [],
803
+ });
804
+ await adapter.handleCodexNotification('item/started', {
805
+ threadId: 'thread_reasoning',
806
+ turnId: 'turn_reasoning',
807
+ item: {
808
+ type: 'reasoning',
809
+ id: 'item_reasoning',
810
+ status: 'inProgress',
811
+ summary: [{ type: 'summary_text', text: '**Analyzing approach**' }],
812
+ },
813
+ });
814
+ await adapter.handleCodexNotification('item/reasoning/summaryTextDelta', {
815
+ threadId: 'thread_reasoning',
816
+ turnId: 'turn_reasoning',
817
+ itemId: 'item_reasoning',
818
+ delta: '**Analyzing approach**',
819
+ });
820
+ await adapter.handleCodexNotification('item/completed', {
821
+ threadId: 'thread_reasoning',
822
+ turnId: 'turn_reasoning',
823
+ item: {
824
+ type: 'reasoning',
825
+ id: 'item_reasoning',
826
+ status: 'completed',
827
+ summary: [{ type: 'summary_text', text: '**Analyzing approach**' }],
828
+ },
829
+ });
830
+ const updates = connection.sessionUpdate.mock.calls.map((call) => call[0].update);
831
+ const thoughtChunks = updates.filter((update) => update.sessionUpdate === 'agent_thought_chunk');
832
+ expect(thoughtChunks).toEqual([
833
+ {
834
+ sessionUpdate: 'agent_thought_chunk',
835
+ content: { type: 'text', text: '**Analyzing approach**' },
836
+ },
837
+ ]);
838
+ expect(updates.some((update) => update.sessionUpdate === 'tool_call' &&
839
+ update.toolCallId === 'item_reasoning' &&
840
+ update.kind === 'think' &&
841
+ update.status === 'pending')).toBe(true);
842
+ expect(updates.some((update) => update.sessionUpdate === 'tool_call_update' &&
843
+ update.toolCallId === 'item_reasoning' &&
844
+ update.status === 'in_progress')).toBe(true);
845
+ expect(updates.some((update) => update.sessionUpdate === 'tool_call_update' &&
846
+ update.toolCallId === 'item_reasoning' &&
847
+ update.status === 'completed')).toBe(true);
346
848
  });
347
849
  it('writes provided MCP servers to Codex config and reloads on loadSession', async () => {
348
850
  const { connection } = createMockConnection();
@@ -567,7 +1069,7 @@ describe('CodexAppServerAcpAdapter', () => {
567
1069
  it('requests ExitPlanMode approval after completed plan item in plan mode', async () => {
568
1070
  const { connection } = createMockConnection();
569
1071
  connection.requestPermission.mockResolvedValue({
570
- outcome: { outcome: 'selected', optionId: 'allow_once' },
1072
+ outcome: { outcome: 'selected', optionId: 'default' },
571
1073
  });
572
1074
  const { client: codexClient, mocks: codex } = createMockCodexClient();
573
1075
  const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
@@ -612,8 +1114,8 @@ describe('CodexAppServerAcpAdapter', () => {
612
1114
  kind: 'switch_mode',
613
1115
  }),
614
1116
  options: [
615
- { optionId: 'allow_once', name: 'Approve plan', kind: 'allow_once' },
616
- { optionId: 'reject_once', name: 'Request changes', kind: 'reject_once' },
1117
+ { optionId: 'default', name: 'Approve and switch to Default', kind: 'allow_once' },
1118
+ { optionId: 'plan', name: 'Keep planning', kind: 'reject_once' },
617
1119
  ],
618
1120
  }));
619
1121
  expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
@@ -659,6 +1161,77 @@ describe('CodexAppServerAcpAdapter', () => {
659
1161
  ],
660
1162
  ]));
661
1163
  });
1164
+ it('switches to the selected non-plan mode id when plan approval is accepted', async () => {
1165
+ const { connection } = createMockConnection();
1166
+ connection.requestPermission.mockResolvedValue({
1167
+ outcome: { outcome: 'selected', optionId: 'code' },
1168
+ });
1169
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
1170
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
1171
+ await initializeAdapterWithDefaultModel(adapter, codex, {
1172
+ collaborationModes: [
1173
+ { name: 'Default', mode: 'default' },
1174
+ { name: 'Code', mode: 'code' },
1175
+ { name: 'Plan', mode: 'plan' },
1176
+ ],
1177
+ });
1178
+ codex.request.mockResolvedValueOnce({
1179
+ thread: { id: 'thread_plan_mode_switch', cwd: '/tmp/workspace' },
1180
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
1181
+ reasoningEffort: 'medium',
1182
+ });
1183
+ const session = await adapter.newSession({
1184
+ cwd: '/tmp/workspace',
1185
+ mcpServers: [],
1186
+ });
1187
+ await adapter.setSessionMode({ sessionId: session.sessionId, modeId: 'plan' });
1188
+ await adapter.handleCodexNotification('item/started', {
1189
+ threadId: 'thread_plan_mode_switch',
1190
+ turnId: 'turn_plan_mode_switch',
1191
+ item: {
1192
+ type: 'plan',
1193
+ id: 'item_plan_mode_switch',
1194
+ status: 'inProgress',
1195
+ },
1196
+ });
1197
+ await adapter.handleCodexNotification('item/plan/delta', {
1198
+ threadId: 'thread_plan_mode_switch',
1199
+ turnId: 'turn_plan_mode_switch',
1200
+ itemId: 'item_plan_mode_switch',
1201
+ delta: '# Plan\n- implement this',
1202
+ });
1203
+ await adapter.handleCodexNotification('item/completed', {
1204
+ threadId: 'thread_plan_mode_switch',
1205
+ turnId: 'turn_plan_mode_switch',
1206
+ item: {
1207
+ type: 'plan',
1208
+ id: 'item_plan_mode_switch',
1209
+ status: 'completed',
1210
+ },
1211
+ });
1212
+ expect(connection.requestPermission).toHaveBeenCalledWith(expect.objectContaining({
1213
+ options: expect.arrayContaining([
1214
+ expect.objectContaining({ optionId: 'default', kind: 'allow_once' }),
1215
+ expect.objectContaining({ optionId: 'code', kind: 'allow_once' }),
1216
+ expect.objectContaining({ optionId: 'plan', kind: 'reject_once' }),
1217
+ ]),
1218
+ }));
1219
+ expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
1220
+ [
1221
+ expect.objectContaining({
1222
+ update: expect.objectContaining({
1223
+ sessionUpdate: 'config_option_update',
1224
+ configOptions: expect.arrayContaining([
1225
+ expect.objectContaining({
1226
+ id: 'mode',
1227
+ currentValue: 'code',
1228
+ }),
1229
+ ]),
1230
+ }),
1231
+ }),
1232
+ ],
1233
+ ]));
1234
+ });
662
1235
  it('holds prompt completion until plan approval resolves and exits plan mode', async () => {
663
1236
  let resolvePlanApproval = () => {
664
1237
  throw new Error('expected plan approval request callback');
@@ -727,7 +1300,7 @@ describe('CodexAppServerAcpAdapter', () => {
727
1300
  await new Promise((resolve) => setTimeout(resolve, 0));
728
1301
  expect(promptSettled).toBe(false);
729
1302
  resolvePlanApproval({
730
- outcome: { outcome: 'selected', optionId: 'allow_once' },
1303
+ outcome: { outcome: 'selected', optionId: 'default' },
731
1304
  });
732
1305
  await itemCompletedPromise;
733
1306
  await expect(promptPromise).resolves.toEqual({ stopReason: 'end_turn' });
@@ -751,7 +1324,7 @@ describe('CodexAppServerAcpAdapter', () => {
751
1324
  it('marks synthetic ExitPlanMode approval as failed when user rejects', async () => {
752
1325
  const { connection } = createMockConnection();
753
1326
  connection.requestPermission.mockResolvedValue({
754
- outcome: { outcome: 'selected', optionId: 'reject_once' },
1327
+ outcome: { outcome: 'selected', optionId: 'plan' },
755
1328
  });
756
1329
  const { client: codexClient, mocks: codex } = createMockCodexClient();
757
1330
  const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
@@ -1287,6 +1860,14 @@ describe('CodexAppServerAcpAdapter', () => {
1287
1860
  },
1288
1861
  });
1289
1862
  expect(codex.respondSuccess).toHaveBeenCalledWith(18, { decision: 'decline' });
1863
+ const sessionUpdateMock = connection.sessionUpdate;
1864
+ const pendingPermissionUpdateIndex = sessionUpdateMock.mock.calls.findIndex((call) => call[0].update?.sessionUpdate === 'tool_call_update' && call[0].update?.status === 'pending');
1865
+ expect(pendingPermissionUpdateIndex).toBeGreaterThanOrEqual(0);
1866
+ const pendingPermissionInvocationOrder = sessionUpdateMock.mock.invocationCallOrder[pendingPermissionUpdateIndex];
1867
+ const requestPermissionInvocationOrder = connection.requestPermission.mock.invocationCallOrder[0];
1868
+ expect(pendingPermissionInvocationOrder).toBeDefined();
1869
+ expect(requestPermissionInvocationOrder).toBeDefined();
1870
+ expect(pendingPermissionInvocationOrder < requestPermissionInvocationOrder).toBe(true);
1290
1871
  expect(connection.sessionUpdate.mock.calls).toEqual(expect.arrayContaining([
1291
1872
  [
1292
1873
  expect.objectContaining({
@@ -1298,6 +1879,152 @@ describe('CodexAppServerAcpAdapter', () => {
1298
1879
  ],
1299
1880
  ]));
1300
1881
  });
1882
+ it('scopes allow_always command approvals by command pattern and cwd', async () => {
1883
+ const { connection } = createMockConnection();
1884
+ connection.requestPermission.mockResolvedValueOnce({
1885
+ outcome: { outcome: 'selected', optionId: 'allow_always' },
1886
+ });
1887
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
1888
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
1889
+ await initializeAdapterWithDefaultModel(adapter, codex);
1890
+ codex.request.mockResolvedValueOnce({
1891
+ thread: { id: 'thread_allow_always', cwd: '/tmp/workspace' },
1892
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
1893
+ reasoningEffort: 'medium',
1894
+ });
1895
+ await adapter.newSession({
1896
+ cwd: '/tmp/workspace',
1897
+ mcpServers: [],
1898
+ });
1899
+ await adapter.handleCodexServerRequest({
1900
+ id: 91,
1901
+ method: 'item/commandExecution/requestApproval',
1902
+ params: {
1903
+ threadId: 'thread_allow_always',
1904
+ turnId: 'turn_allow_always',
1905
+ itemId: 'item_allow_always',
1906
+ command: 'cat README.md',
1907
+ cwd: '/tmp/workspace',
1908
+ },
1909
+ });
1910
+ expect(connection.requestPermission).toHaveBeenCalledWith(expect.objectContaining({
1911
+ toolCall: expect.objectContaining({
1912
+ title: 'Read README.md',
1913
+ kind: 'read',
1914
+ }),
1915
+ options: expect.arrayContaining([
1916
+ expect.objectContaining({ optionId: 'allow_always', kind: 'allow_always' }),
1917
+ expect.objectContaining({ optionId: 'allow_once', kind: 'allow_once' }),
1918
+ expect.objectContaining({ optionId: 'reject_once', kind: 'reject_once' }),
1919
+ ]),
1920
+ }));
1921
+ expect(codex.respondSuccess).toHaveBeenCalledWith(91, { decision: 'accept' });
1922
+ connection.requestPermission.mockClear();
1923
+ codex.respondSuccess.mockClear();
1924
+ await adapter.handleCodexServerRequest({
1925
+ id: 92,
1926
+ method: 'item/commandExecution/requestApproval',
1927
+ params: {
1928
+ threadId: 'thread_allow_always',
1929
+ turnId: 'turn_allow_always',
1930
+ itemId: 'item_allow_always_2',
1931
+ command: 'cat README.md',
1932
+ cwd: '/tmp/workspace',
1933
+ },
1934
+ });
1935
+ expect(connection.requestPermission).not.toHaveBeenCalled();
1936
+ expect(codex.respondSuccess).toHaveBeenCalledWith(92, { decision: 'accept' });
1937
+ codex.respondSuccess.mockClear();
1938
+ await adapter.handleCodexServerRequest({
1939
+ id: 93,
1940
+ method: 'item/commandExecution/requestApproval',
1941
+ params: {
1942
+ threadId: 'thread_allow_always',
1943
+ turnId: 'turn_allow_always',
1944
+ itemId: 'item_allow_always_3',
1945
+ command: 'ls src',
1946
+ cwd: '/tmp/workspace',
1947
+ },
1948
+ });
1949
+ expect(connection.requestPermission).toHaveBeenCalledTimes(1);
1950
+ expect(codex.respondSuccess).toHaveBeenCalledWith(93, { decision: 'accept' });
1951
+ connection.requestPermission.mockClear();
1952
+ codex.respondSuccess.mockClear();
1953
+ await adapter.handleCodexServerRequest({
1954
+ id: 94,
1955
+ method: 'item/commandExecution/requestApproval',
1956
+ params: {
1957
+ threadId: 'thread_allow_always',
1958
+ turnId: 'turn_allow_always',
1959
+ itemId: 'item_allow_always_4',
1960
+ command: 'cat README.md',
1961
+ cwd: '/tmp/other-workspace',
1962
+ },
1963
+ });
1964
+ expect(connection.requestPermission).toHaveBeenCalledTimes(1);
1965
+ expect(codex.respondSuccess).toHaveBeenCalledWith(94, { decision: 'accept' });
1966
+ });
1967
+ it('does not reuse allow_always scope when a chained command changes cwd', async () => {
1968
+ const { connection } = createMockConnection();
1969
+ connection.requestPermission.mockResolvedValueOnce({
1970
+ outcome: { outcome: 'selected', optionId: 'allow_always' },
1971
+ });
1972
+ const { client: codexClient, mocks: codex } = createMockCodexClient();
1973
+ const adapter = new CodexAppServerAcpAdapter(connection, codexClient);
1974
+ await initializeAdapterWithDefaultModel(adapter, codex);
1975
+ codex.request.mockResolvedValueOnce({
1976
+ thread: { id: 'thread_allow_always_cd_scope', cwd: '/tmp/workspace' },
1977
+ approvalPolicy: DEFAULT_APPROVAL_POLICY,
1978
+ reasoningEffort: 'medium',
1979
+ });
1980
+ await adapter.newSession({
1981
+ cwd: '/tmp/workspace',
1982
+ mcpServers: [],
1983
+ });
1984
+ await adapter.handleCodexServerRequest({
1985
+ id: 101,
1986
+ method: 'item/commandExecution/requestApproval',
1987
+ params: {
1988
+ threadId: 'thread_allow_always_cd_scope',
1989
+ turnId: 'turn_allow_always_cd_scope',
1990
+ itemId: 'item_allow_always_cd_scope_1',
1991
+ command: 'cd nested && cat README.md',
1992
+ cwd: '/tmp/workspace',
1993
+ },
1994
+ });
1995
+ expect(connection.requestPermission).toHaveBeenCalledTimes(1);
1996
+ expect(codex.respondSuccess).toHaveBeenCalledWith(101, { decision: 'accept' });
1997
+ connection.requestPermission.mockClear();
1998
+ codex.respondSuccess.mockClear();
1999
+ await adapter.handleCodexServerRequest({
2000
+ id: 102,
2001
+ method: 'item/commandExecution/requestApproval',
2002
+ params: {
2003
+ threadId: 'thread_allow_always_cd_scope',
2004
+ turnId: 'turn_allow_always_cd_scope',
2005
+ itemId: 'item_allow_always_cd_scope_2',
2006
+ command: 'cat README.md',
2007
+ cwd: '/tmp/workspace',
2008
+ },
2009
+ });
2010
+ expect(connection.requestPermission).toHaveBeenCalledTimes(1);
2011
+ expect(codex.respondSuccess).toHaveBeenCalledWith(102, { decision: 'accept' });
2012
+ connection.requestPermission.mockClear();
2013
+ codex.respondSuccess.mockClear();
2014
+ await adapter.handleCodexServerRequest({
2015
+ id: 103,
2016
+ method: 'item/commandExecution/requestApproval',
2017
+ params: {
2018
+ threadId: 'thread_allow_always_cd_scope',
2019
+ turnId: 'turn_allow_always_cd_scope',
2020
+ itemId: 'item_allow_always_cd_scope_3',
2021
+ command: 'cd nested && cat README.md',
2022
+ cwd: '/tmp/workspace',
2023
+ },
2024
+ });
2025
+ expect(connection.requestPermission).not.toHaveBeenCalled();
2026
+ expect(codex.respondSuccess).toHaveBeenCalledWith(103, { decision: 'accept' });
2027
+ });
1301
2028
  it('reconciles turn/completed notifications that arrive before prompt attaches active turn', async () => {
1302
2029
  const { connection } = createMockConnection();
1303
2030
  const { client: codexClient, mocks: codex } = createMockCodexClient();