factory-factory 0.2.4 → 0.2.5

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 (287) hide show
  1. package/dist/client/assets/{_basePickBy-CCB8XrLV.js → _basePickBy-BXw54oMQ.js} +1 -1
  2. package/dist/client/assets/{_baseUniq-CnpEKy-E.js → _baseUniq-_2-lN-JZ.js} +1 -1
  3. package/dist/client/assets/{arc-BVt3NpFL.js → arc-DaCKgXo4.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-VXUJARFQ-DQXtRVG1.js → architectureDiagram-VXUJARFQ-D5dlDvyJ.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-VD42YOAC-C_GKWlYL.js → blockDiagram-VD42YOAC-CEAiD2S_.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-YG6GDRKO-njABqJg1.js → c4Diagram-YG6GDRKO-DTNRx2b5.js} +1 -1
  7. package/dist/client/assets/channel-BusoDFL5.js +1 -0
  8. package/dist/client/assets/{chunk-4BX2VUAB-DNMCzzfR.js → chunk-4BX2VUAB-yvp0WNZ0.js} +1 -1
  9. package/dist/client/assets/{chunk-55IACEB6-CajLRh0F.js → chunk-55IACEB6-Cse3ExNd.js} +1 -1
  10. package/dist/client/assets/{chunk-B4BG7PRW-BLSFZNLe.js → chunk-B4BG7PRW-Bl2GpPLn.js} +1 -1
  11. package/dist/client/assets/{chunk-DI55MBZ5-DtQPQERJ.js → chunk-DI55MBZ5-CV5Cqkss.js} +1 -1
  12. package/dist/client/assets/{chunk-FMBD7UC4-BhtFvMT5.js → chunk-FMBD7UC4-CP3yjlO6.js} +1 -1
  13. package/dist/client/assets/{chunk-QN33PNHL-DBHUU683.js → chunk-QN33PNHL-DUdJaEPB.js} +1 -1
  14. package/dist/client/assets/{chunk-QZHKN3VN-B1rA-SBe.js → chunk-QZHKN3VN-DYTUnPIc.js} +1 -1
  15. package/dist/client/assets/{chunk-TZMSLE5B-BJUlg6Pf.js → chunk-TZMSLE5B-CtWiqR24.js} +1 -1
  16. package/dist/client/assets/classDiagram-2ON5EDUG-C3RMRasv.js +1 -0
  17. package/dist/client/assets/classDiagram-v2-WZHVMYZB-C3RMRasv.js +1 -0
  18. package/dist/client/assets/clone-D6B-nWvg.js +1 -0
  19. package/dist/client/assets/{cose-bilkent-S5V4N54A-CyjRxz-A.js → cose-bilkent-S5V4N54A-B67RdhOB.js} +1 -1
  20. package/dist/client/assets/{dagre-6UL2VRFP-CURGwkx9.js → dagre-6UL2VRFP-D9u_oxJL.js} +1 -1
  21. package/dist/client/assets/{diagram-PSM6KHXK-CaOIVsbD.js → diagram-PSM6KHXK-DOWfPnpa.js} +1 -1
  22. package/dist/client/assets/{diagram-QEK2KX5R-0zoz9z8_.js → diagram-QEK2KX5R-CqJwZbAA.js} +1 -1
  23. package/dist/client/assets/{diagram-S2PKOQOG-D6WyG3pJ.js → diagram-S2PKOQOG-D0ri9ztm.js} +1 -1
  24. package/dist/client/assets/{erDiagram-Q2GNP2WA-BwfTai9D.js → erDiagram-Q2GNP2WA-0cRKPUY7.js} +1 -1
  25. package/dist/client/assets/{flowDiagram-NV44I4VS-z6idjLXa.js → flowDiagram-NV44I4VS-Cj_5-ww1.js} +1 -1
  26. package/dist/client/assets/{ganttDiagram-JELNMOA3-BLAK0GDW.js → ganttDiagram-JELNMOA3-Cwm2arni.js} +1 -1
  27. package/dist/client/assets/{gitGraphDiagram-NY62KEGX-DsC9TQow.js → gitGraphDiagram-NY62KEGX-DKyLuO26.js} +1 -1
  28. package/dist/client/assets/{graph-72LNxX96.js → graph-BhRkLhV1.js} +1 -1
  29. package/dist/client/assets/{index-C0E1P_GL.js → index-1HR_eYGL.js} +222 -184
  30. package/dist/client/assets/index-DHENAn70.css +1 -0
  31. package/dist/client/assets/{infoDiagram-WHAUD3N6-CInk5tUs.js → infoDiagram-WHAUD3N6-DuzPbELj.js} +1 -1
  32. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-nTrHP_HR.js → journeyDiagram-XKPGCS4Q-BfearpNr.js} +1 -1
  33. package/dist/client/assets/{kanban-definition-3W4ZIXB7-xiF9MwcX.js → kanban-definition-3W4ZIXB7-R5KMtAj4.js} +1 -1
  34. package/dist/client/assets/{layout-BxYnyUX2.js → layout-B-tL36G2.js} +1 -1
  35. package/dist/client/assets/{linear-BOpSSl-n.js → linear-CvIBiHN-.js} +1 -1
  36. package/dist/client/assets/{mindmap-definition-VGOIOE7T-BxYEWuiO.js → mindmap-definition-VGOIOE7T-CHYN0wBz.js} +1 -1
  37. package/dist/client/assets/{pieDiagram-ADFJNKIX-DHQkQuZp.js → pieDiagram-ADFJNKIX-LkA8WwD-.js} +1 -1
  38. package/dist/client/assets/{quadrantDiagram-AYHSOK5B--dbc4LsQ.js → quadrantDiagram-AYHSOK5B-B5s8Qc9j.js} +1 -1
  39. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-Dr-h39fn.js → requirementDiagram-UZGBJVZJ-BMLpjBJA.js} +1 -1
  40. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-BwKHqT4R.js → sankeyDiagram-TZEHDZUN-BIj9RGlp.js} +1 -1
  41. package/dist/client/assets/{sequenceDiagram-WL72ISMW-DizdB6A9.js → sequenceDiagram-WL72ISMW-uGM-Jh_O.js} +1 -1
  42. package/dist/client/assets/{stateDiagram-FKZM4ZOC-C-J72Wtl.js → stateDiagram-FKZM4ZOC-CQQhnUok.js} +1 -1
  43. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BUJPEM7D.js +1 -0
  44. package/dist/client/assets/{terminal-instance-qIJHj7KS.js → terminal-instance-DpK3PfW4.js} +1 -1
  45. package/dist/client/assets/{timeline-definition-IT6M3QCI-DAGw_FKd.js → timeline-definition-IT6M3QCI-BusXMYfI.js} +1 -1
  46. package/dist/client/assets/{treemap-KMMF4GRG-Bo4f4Al3.js → treemap-KMMF4GRG-XF3-w8dz.js} +1 -1
  47. package/dist/client/assets/{xychartDiagram-PRI3JC2R-CAJ9NVad.js → xychartDiagram-PRI3JC2R-DhKTXxb3.js} +1 -1
  48. package/dist/client/index.html +2 -2
  49. package/dist/prompts/ratchet/dispatch.md +31 -0
  50. package/dist/src/backend/app-context.d.ts +4 -0
  51. package/dist/src/backend/app-context.d.ts.map +1 -1
  52. package/dist/src/backend/app-context.js +4 -0
  53. package/dist/src/backend/app-context.js.map +1 -1
  54. package/dist/src/backend/claude/protocol.d.ts +2 -2
  55. package/dist/src/backend/claude/protocol.d.ts.map +1 -1
  56. package/dist/src/backend/claude/protocol.js +13 -4
  57. package/dist/src/backend/claude/protocol.js.map +1 -1
  58. package/dist/src/backend/claude/protocol.test.js +18 -0
  59. package/dist/src/backend/claude/protocol.test.js.map +1 -1
  60. package/dist/src/backend/claude/session.d.ts.map +1 -1
  61. package/dist/src/backend/claude/session.js +40 -6
  62. package/dist/src/backend/claude/session.js.map +1 -1
  63. package/dist/src/backend/claude/session.test.js +46 -0
  64. package/dist/src/backend/claude/session.test.js.map +1 -1
  65. package/dist/src/backend/claude/types.d.ts +3 -0
  66. package/dist/src/backend/claude/types.d.ts.map +1 -1
  67. package/dist/src/backend/claude/types.js +5 -0
  68. package/dist/src/backend/claude/types.js.map +1 -1
  69. package/dist/src/backend/prompts/markdown-loader.d.ts +22 -0
  70. package/dist/src/backend/prompts/markdown-loader.d.ts.map +1 -0
  71. package/dist/src/backend/prompts/markdown-loader.js +77 -0
  72. package/dist/src/backend/prompts/markdown-loader.js.map +1 -0
  73. package/dist/src/backend/prompts/markdown-loader.test.d.ts +2 -0
  74. package/dist/src/backend/prompts/markdown-loader.test.d.ts.map +1 -0
  75. package/dist/src/backend/prompts/markdown-loader.test.js +190 -0
  76. package/dist/src/backend/prompts/markdown-loader.test.js.map +1 -0
  77. package/dist/src/backend/prompts/quick-actions.d.ts.map +1 -1
  78. package/dist/src/backend/prompts/quick-actions.js +34 -92
  79. package/dist/src/backend/prompts/quick-actions.js.map +1 -1
  80. package/dist/src/backend/prompts/ratchet-dispatch.d.ts +3 -0
  81. package/dist/src/backend/prompts/ratchet-dispatch.d.ts.map +1 -0
  82. package/dist/src/backend/prompts/ratchet-dispatch.js +53 -0
  83. package/dist/src/backend/prompts/ratchet-dispatch.js.map +1 -0
  84. package/dist/src/backend/prompts/ratchet-dispatch.test.d.ts +2 -0
  85. package/dist/src/backend/prompts/ratchet-dispatch.test.d.ts.map +1 -0
  86. package/dist/src/backend/prompts/ratchet-dispatch.test.js +34 -0
  87. package/dist/src/backend/prompts/ratchet-dispatch.test.js.map +1 -0
  88. package/dist/src/backend/prompts/workflows.d.ts.map +1 -1
  89. package/dist/src/backend/prompts/workflows.js +23 -76
  90. package/dist/src/backend/prompts/workflows.js.map +1 -1
  91. package/dist/src/backend/resource_accessors/workspace.accessor.d.ts +4 -3
  92. package/dist/src/backend/resource_accessors/workspace.accessor.d.ts.map +1 -1
  93. package/dist/src/backend/resource_accessors/workspace.accessor.js +4 -2
  94. package/dist/src/backend/resource_accessors/workspace.accessor.js.map +1 -1
  95. package/dist/src/backend/routers/websocket/chat.handler.d.ts.map +1 -1
  96. package/dist/src/backend/routers/websocket/chat.handler.js +1 -30
  97. package/dist/src/backend/routers/websocket/chat.handler.js.map +1 -1
  98. package/dist/src/backend/services/chat-event-forwarder.service.d.ts.map +1 -1
  99. package/dist/src/backend/services/chat-event-forwarder.service.js +9 -13
  100. package/dist/src/backend/services/chat-event-forwarder.service.js.map +1 -1
  101. package/dist/src/backend/services/chat-message-handlers/handlers/get-history.handler.d.ts +2 -1
  102. package/dist/src/backend/services/chat-message-handlers/handlers/get-history.handler.d.ts.map +1 -1
  103. package/dist/src/backend/services/chat-message-handlers/handlers/get-history.handler.js.map +1 -1
  104. package/dist/src/backend/services/chat-message-handlers/handlers/get-queue.handler.d.ts +2 -1
  105. package/dist/src/backend/services/chat-message-handlers/handlers/get-queue.handler.d.ts.map +1 -1
  106. package/dist/src/backend/services/chat-message-handlers/handlers/get-queue.handler.js +7 -3
  107. package/dist/src/backend/services/chat-message-handlers/handlers/get-queue.handler.js.map +1 -1
  108. package/dist/src/backend/services/chat-message-handlers/handlers/handlers.test.js +124 -8
  109. package/dist/src/backend/services/chat-message-handlers/handlers/handlers.test.js.map +1 -1
  110. package/dist/src/backend/services/chat-message-handlers/handlers/list-sessions.handler.d.ts +2 -1
  111. package/dist/src/backend/services/chat-message-handlers/handlers/list-sessions.handler.d.ts.map +1 -1
  112. package/dist/src/backend/services/chat-message-handlers/handlers/list-sessions.handler.js.map +1 -1
  113. package/dist/src/backend/services/chat-message-handlers/handlers/load-session.handler.d.ts +2 -1
  114. package/dist/src/backend/services/chat-message-handlers/handlers/load-session.handler.d.ts.map +1 -1
  115. package/dist/src/backend/services/chat-message-handlers/handlers/load-session.handler.js +41 -31
  116. package/dist/src/backend/services/chat-message-handlers/handlers/load-session.handler.js.map +1 -1
  117. package/dist/src/backend/services/chat-message-handlers/handlers/permission-response.handler.d.ts +2 -1
  118. package/dist/src/backend/services/chat-message-handlers/handlers/permission-response.handler.d.ts.map +1 -1
  119. package/dist/src/backend/services/chat-message-handlers/handlers/permission-response.handler.js +1 -2
  120. package/dist/src/backend/services/chat-message-handlers/handlers/permission-response.handler.js.map +1 -1
  121. package/dist/src/backend/services/chat-message-handlers/handlers/question-response.handler.d.ts +2 -1
  122. package/dist/src/backend/services/chat-message-handlers/handlers/question-response.handler.d.ts.map +1 -1
  123. package/dist/src/backend/services/chat-message-handlers/handlers/question-response.handler.js +1 -2
  124. package/dist/src/backend/services/chat-message-handlers/handlers/question-response.handler.js.map +1 -1
  125. package/dist/src/backend/services/chat-message-handlers/handlers/queue-message.handler.d.ts +2 -1
  126. package/dist/src/backend/services/chat-message-handlers/handlers/queue-message.handler.d.ts.map +1 -1
  127. package/dist/src/backend/services/chat-message-handlers/handlers/queue-message.handler.js +6 -7
  128. package/dist/src/backend/services/chat-message-handlers/handlers/queue-message.handler.js.map +1 -1
  129. package/dist/src/backend/services/chat-message-handlers/handlers/remove-queued-message.handler.d.ts +2 -1
  130. package/dist/src/backend/services/chat-message-handlers/handlers/remove-queued-message.handler.d.ts.map +1 -1
  131. package/dist/src/backend/services/chat-message-handlers/handlers/remove-queued-message.handler.js +1 -2
  132. package/dist/src/backend/services/chat-message-handlers/handlers/remove-queued-message.handler.js.map +1 -1
  133. package/dist/src/backend/services/chat-message-handlers/handlers/rewind-files.handler.d.ts +2 -1
  134. package/dist/src/backend/services/chat-message-handlers/handlers/rewind-files.handler.d.ts.map +1 -1
  135. package/dist/src/backend/services/chat-message-handlers/handlers/rewind-files.handler.js +8 -9
  136. package/dist/src/backend/services/chat-message-handlers/handlers/rewind-files.handler.js.map +1 -1
  137. package/dist/src/backend/services/chat-message-handlers/handlers/set-model.handler.d.ts +2 -1
  138. package/dist/src/backend/services/chat-message-handlers/handlers/set-model.handler.d.ts.map +1 -1
  139. package/dist/src/backend/services/chat-message-handlers/handlers/set-model.handler.js +4 -5
  140. package/dist/src/backend/services/chat-message-handlers/handlers/set-model.handler.js.map +1 -1
  141. package/dist/src/backend/services/chat-message-handlers/handlers/set-thinking-budget.handler.d.ts +2 -1
  142. package/dist/src/backend/services/chat-message-handlers/handlers/set-thinking-budget.handler.d.ts.map +1 -1
  143. package/dist/src/backend/services/chat-message-handlers/handlers/set-thinking-budget.handler.js +4 -5
  144. package/dist/src/backend/services/chat-message-handlers/handlers/set-thinking-budget.handler.js.map +1 -1
  145. package/dist/src/backend/services/chat-message-handlers/handlers/start.handler.d.ts +2 -1
  146. package/dist/src/backend/services/chat-message-handlers/handlers/start.handler.d.ts.map +1 -1
  147. package/dist/src/backend/services/chat-message-handlers/handlers/start.handler.js +4 -2
  148. package/dist/src/backend/services/chat-message-handlers/handlers/start.handler.js.map +1 -1
  149. package/dist/src/backend/services/chat-message-handlers/handlers/stop.handler.d.ts +2 -1
  150. package/dist/src/backend/services/chat-message-handlers/handlers/stop.handler.d.ts.map +1 -1
  151. package/dist/src/backend/services/chat-message-handlers/handlers/stop.handler.js +7 -2
  152. package/dist/src/backend/services/chat-message-handlers/handlers/stop.handler.js.map +1 -1
  153. package/dist/src/backend/services/chat-message-handlers/handlers/user-input.handler.d.ts +2 -1
  154. package/dist/src/backend/services/chat-message-handlers/handlers/user-input.handler.d.ts.map +1 -1
  155. package/dist/src/backend/services/chat-message-handlers/handlers/user-input.handler.js +1 -2
  156. package/dist/src/backend/services/chat-message-handlers/handlers/user-input.handler.js.map +1 -1
  157. package/dist/src/backend/services/chat-message-handlers/registry.d.ts +5 -1
  158. package/dist/src/backend/services/chat-message-handlers/registry.d.ts.map +1 -1
  159. package/dist/src/backend/services/chat-message-handlers/registry.js.map +1 -1
  160. package/dist/src/backend/services/chat-message-handlers.service.d.ts.map +1 -1
  161. package/dist/src/backend/services/chat-message-handlers.service.js +4 -8
  162. package/dist/src/backend/services/chat-message-handlers.service.js.map +1 -1
  163. package/dist/src/backend/services/chat-transport-adapter.service.d.ts +2 -0
  164. package/dist/src/backend/services/chat-transport-adapter.service.d.ts.map +1 -1
  165. package/dist/src/backend/services/chat-transport-adapter.service.js +32 -1
  166. package/dist/src/backend/services/chat-transport-adapter.service.js.map +1 -1
  167. package/dist/src/backend/services/chat-transport-adapter.service.test.js +14 -0
  168. package/dist/src/backend/services/chat-transport-adapter.service.test.js.map +1 -1
  169. package/dist/src/backend/services/data-backup.service.d.ts +2 -622
  170. package/dist/src/backend/services/data-backup.service.d.ts.map +1 -1
  171. package/dist/src/backend/services/data-backup.service.js +3 -143
  172. package/dist/src/backend/services/data-backup.service.js.map +1 -1
  173. package/dist/src/backend/services/file-lock.service.d.ts.map +1 -1
  174. package/dist/src/backend/services/file-lock.service.js +3 -5
  175. package/dist/src/backend/services/file-lock.service.js.map +1 -1
  176. package/dist/src/backend/services/file-lock.service.test.js +55 -0
  177. package/dist/src/backend/services/file-lock.service.test.js.map +1 -1
  178. package/dist/src/backend/services/github-cli.service.d.ts.map +1 -1
  179. package/dist/src/backend/services/github-cli.service.js +118 -19
  180. package/dist/src/backend/services/github-cli.service.js.map +1 -1
  181. package/dist/src/backend/services/github-cli.service.test.js +126 -0
  182. package/dist/src/backend/services/github-cli.service.test.js.map +1 -1
  183. package/dist/src/backend/services/index.d.ts +1 -0
  184. package/dist/src/backend/services/index.d.ts.map +1 -1
  185. package/dist/src/backend/services/index.js +1 -0
  186. package/dist/src/backend/services/index.js.map +1 -1
  187. package/dist/src/backend/services/message-state-machine.d.ts.map +1 -1
  188. package/dist/src/backend/services/message-state-machine.js +11 -5
  189. package/dist/src/backend/services/message-state-machine.js.map +1 -1
  190. package/dist/src/backend/services/message-state.service.d.ts +16 -18
  191. package/dist/src/backend/services/message-state.service.d.ts.map +1 -1
  192. package/dist/src/backend/services/message-state.service.js +8 -14
  193. package/dist/src/backend/services/message-state.service.js.map +1 -1
  194. package/dist/src/backend/services/message-state.service.test.js +36 -45
  195. package/dist/src/backend/services/message-state.service.test.js.map +1 -1
  196. package/dist/src/backend/services/ratchet.service.d.ts +14 -69
  197. package/dist/src/backend/services/ratchet.service.d.ts.map +1 -1
  198. package/dist/src/backend/services/ratchet.service.js +198 -412
  199. package/dist/src/backend/services/ratchet.service.js.map +1 -1
  200. package/dist/src/backend/services/ratchet.service.test.js +199 -424
  201. package/dist/src/backend/services/ratchet.service.test.js.map +1 -1
  202. package/dist/src/backend/services/run-script-state-machine.service.d.ts +27 -0
  203. package/dist/src/backend/services/run-script-state-machine.service.d.ts.map +1 -0
  204. package/dist/src/backend/services/run-script-state-machine.service.js +149 -0
  205. package/dist/src/backend/services/run-script-state-machine.service.js.map +1 -0
  206. package/dist/src/backend/services/run-script-state-machine.service.test.d.ts +2 -0
  207. package/dist/src/backend/services/run-script-state-machine.service.test.d.ts.map +1 -0
  208. package/dist/src/backend/services/run-script-state-machine.service.test.js +453 -0
  209. package/dist/src/backend/services/run-script-state-machine.service.test.js.map +1 -0
  210. package/dist/src/backend/services/run-script.service.d.ts +0 -7
  211. package/dist/src/backend/services/run-script.service.d.ts.map +1 -1
  212. package/dist/src/backend/services/run-script.service.js +145 -76
  213. package/dist/src/backend/services/run-script.service.js.map +1 -1
  214. package/dist/src/backend/services/session-runtime-store.service.d.ts +38 -0
  215. package/dist/src/backend/services/session-runtime-store.service.d.ts.map +1 -0
  216. package/dist/src/backend/services/session-runtime-store.service.js +111 -0
  217. package/dist/src/backend/services/session-runtime-store.service.js.map +1 -0
  218. package/dist/src/backend/services/session-runtime-store.service.test.d.ts +2 -0
  219. package/dist/src/backend/services/session-runtime-store.service.test.d.ts.map +1 -0
  220. package/dist/src/backend/services/session-runtime-store.service.test.js +15 -0
  221. package/dist/src/backend/services/session-runtime-store.service.test.js.map +1 -0
  222. package/dist/src/backend/services/session.service.test.js.map +1 -1
  223. package/dist/src/backend/services/workspace-query.service.d.ts +1 -0
  224. package/dist/src/backend/services/workspace-query.service.d.ts.map +1 -1
  225. package/dist/src/backend/services/workspace-query.service.js +8 -0
  226. package/dist/src/backend/services/workspace-query.service.js.map +1 -1
  227. package/dist/src/backend/services/worktree-lifecycle.service.d.ts.map +1 -1
  228. package/dist/src/backend/services/worktree-lifecycle.service.js +139 -19
  229. package/dist/src/backend/services/worktree-lifecycle.service.js.map +1 -1
  230. package/dist/src/backend/services/worktree-lifecycle.service.test.js +48 -1
  231. package/dist/src/backend/services/worktree-lifecycle.service.test.js.map +1 -1
  232. package/dist/src/backend/trpc/admin.trpc.d.ts +13 -13
  233. package/dist/src/backend/trpc/admin.trpc.d.ts.map +1 -1
  234. package/dist/src/backend/trpc/admin.trpc.js +2 -1
  235. package/dist/src/backend/trpc/admin.trpc.js.map +1 -1
  236. package/dist/src/backend/trpc/index.d.ts +18 -23
  237. package/dist/src/backend/trpc/index.d.ts.map +1 -1
  238. package/dist/src/backend/trpc/session.trpc.d.ts +3 -3
  239. package/dist/src/backend/trpc/workspace/run-script.trpc.d.ts +0 -7
  240. package/dist/src/backend/trpc/workspace/run-script.trpc.d.ts.map +1 -1
  241. package/dist/src/backend/trpc/workspace.trpc.d.ts +2 -7
  242. package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
  243. package/dist/src/backend/trpc/workspace.trpc.js +12 -1
  244. package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
  245. package/dist/src/shared/ci-status.d.ts +9 -0
  246. package/dist/src/shared/ci-status.d.ts.map +1 -0
  247. package/dist/src/shared/ci-status.js +44 -0
  248. package/dist/src/shared/ci-status.js.map +1 -0
  249. package/dist/src/shared/claude/index.d.ts +1 -0
  250. package/dist/src/shared/claude/index.d.ts.map +1 -1
  251. package/dist/src/shared/claude/index.js +1 -0
  252. package/dist/src/shared/claude/index.js.map +1 -1
  253. package/dist/src/shared/claude/protocol.d.ts +6 -3
  254. package/dist/src/shared/claude/protocol.d.ts.map +1 -1
  255. package/dist/src/shared/claude/protocol.js.map +1 -1
  256. package/dist/src/shared/schemas/export-data.schema.d.ts +865 -0
  257. package/dist/src/shared/schemas/export-data.schema.d.ts.map +1 -0
  258. package/dist/src/shared/schemas/export-data.schema.js +167 -0
  259. package/dist/src/shared/schemas/export-data.schema.js.map +1 -0
  260. package/dist/src/shared/schemas/persisted-stores.schema.d.ts +19 -0
  261. package/dist/src/shared/schemas/persisted-stores.schema.d.ts.map +1 -0
  262. package/dist/src/shared/schemas/persisted-stores.schema.js +17 -0
  263. package/dist/src/shared/schemas/persisted-stores.schema.js.map +1 -0
  264. package/dist/src/shared/session-runtime.d.ts +17 -0
  265. package/dist/src/shared/session-runtime.d.ts.map +1 -0
  266. package/dist/src/shared/session-runtime.js +9 -0
  267. package/dist/src/shared/session-runtime.js.map +1 -0
  268. package/dist/src/shared/websocket/chat-message.schema.d.ts +24 -11
  269. package/dist/src/shared/websocket/chat-message.schema.d.ts.map +1 -1
  270. package/dist/src/shared/websocket/chat-message.schema.js +4 -1
  271. package/dist/src/shared/websocket/chat-message.schema.js.map +1 -1
  272. package/dist/src/shared/websocket/index.d.ts +1 -1
  273. package/dist/src/shared/websocket/index.d.ts.map +1 -1
  274. package/dist/src/shared/websocket/index.js.map +1 -1
  275. package/dist/src/shared/workspace-sidebar-status.d.ts +20 -0
  276. package/dist/src/shared/workspace-sidebar-status.d.ts.map +1 -0
  277. package/dist/src/shared/workspace-sidebar-status.js +73 -0
  278. package/dist/src/shared/workspace-sidebar-status.js.map +1 -0
  279. package/dist/tsconfig.backend.tsbuildinfo +1 -1
  280. package/package.json +2 -2
  281. package/prompts/ratchet/dispatch.md +31 -0
  282. package/dist/client/assets/channel-DXVcwOT7.js +0 -1
  283. package/dist/client/assets/classDiagram-2ON5EDUG-DSXhUv2N.js +0 -1
  284. package/dist/client/assets/classDiagram-v2-WZHVMYZB-DSXhUv2N.js +0 -1
  285. package/dist/client/assets/clone-Cel7XaEC.js +0 -1
  286. package/dist/client/assets/index-DI1BSYUN.css +0 -1
  287. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-waz9l7Vx.js +0 -1
@@ -1,7 +1,7 @@
1
1
  import { CIStatus, RatchetState, SessionStatus } from '../../../prisma/generated/client.js';
2
2
  import pLimit from 'p-limit';
3
+ import { buildRatchetDispatchPrompt } from '../prompts/ratchet-dispatch.js';
3
4
  import { claudeSessionAccessor } from '../resource_accessors/claude-session.accessor.js';
4
- import { userSettingsAccessor } from '../resource_accessors/user-settings.accessor.js';
5
5
  import { workspaceAccessor } from '../resource_accessors/workspace.accessor.js';
6
6
  import { fixerSessionService } from './fixer-session.service.js';
7
7
  import { githubCLIService } from './github-cli.service.js';
@@ -12,10 +12,12 @@ const logger = createLogger('ratchet');
12
12
  const RATCHET_POLL_INTERVAL_MS = 60_000;
13
13
  const MAX_CONCURRENT_CHECKS = 5;
14
14
  const RATCHET_WORKFLOW = 'ratchet';
15
+ const AUTHENTICATED_USERNAME_CACHE_TTL_MS = 5 * 60_000;
15
16
  class RatchetService {
16
17
  isShuttingDown = false;
17
18
  monitorLoop = null;
18
19
  checkLimit = pLimit(MAX_CONCURRENT_CHECKS);
20
+ cachedAuthenticatedUsername = null;
19
21
  start() {
20
22
  if (this.monitorLoop) {
21
23
  return;
@@ -53,21 +55,13 @@ class RatchetService {
53
55
  if (this.isShuttingDown) {
54
56
  return { checked: 0, stateChanges: 0, actionsTriggered: 0, results: [] };
55
57
  }
56
- const userSettings = await userSettingsAccessor.get();
57
- const settings = {
58
- autoFixCi: userSettings.ratchetAutoFixCi,
59
- autoFixReviews: userSettings.ratchetAutoFixReviews,
60
- autoMerge: userSettings.ratchetAutoMerge,
61
- allowedReviewers: userSettings.ratchetAllowedReviewers ?? [],
62
- };
63
58
  const workspaces = await workspaceAccessor.findWithPRsForRatchet();
64
59
  if (workspaces.length === 0) {
65
60
  return { checked: 0, stateChanges: 0, actionsTriggered: 0, results: [] };
66
61
  }
67
- logger.debug('Checking workspaces for ratchet progression', { count: workspaces.length });
68
- const results = await Promise.all(workspaces.map((workspace) => this.checkLimit(() => this.processWorkspace(workspace, settings))));
62
+ const results = await Promise.all(workspaces.map((workspace) => this.checkLimit(() => this.processWorkspace(workspace))));
69
63
  const stateChanges = results.filter((r) => r.previousState !== r.newState).length;
70
- const actionsTriggered = results.filter((r) => r.action.type === 'TRIGGERED_FIXER' || r.action.type === 'NOTIFIED_ACTIVE_FIXER').length;
64
+ const actionsTriggered = results.filter((r) => r.action.type === 'TRIGGERED_FIXER').length;
71
65
  if (stateChanges > 0 || actionsTriggered > 0) {
72
66
  logger.info('Ratchet check completed', {
73
67
  checked: workspaces.length,
@@ -85,16 +79,9 @@ class RatchetService {
85
79
  if (!workspace) {
86
80
  return null;
87
81
  }
88
- const userSettings = await userSettingsAccessor.get();
89
- const settings = {
90
- autoFixCi: userSettings.ratchetAutoFixCi,
91
- autoFixReviews: userSettings.ratchetAutoFixReviews,
92
- autoMerge: userSettings.ratchetAutoMerge,
93
- allowedReviewers: userSettings.ratchetAllowedReviewers ?? [],
94
- };
95
- return this.processWorkspace(workspace, settings);
82
+ return this.processWorkspace(workspace);
96
83
  }
97
- async processWorkspace(workspace, settings) {
84
+ async processWorkspace(workspace) {
98
85
  if (this.isShuttingDown) {
99
86
  return {
100
87
  workspaceId: workspace.id,
@@ -104,7 +91,8 @@ class RatchetService {
104
91
  };
105
92
  }
106
93
  try {
107
- const prStateInfo = await this.fetchPRState(workspace, settings.allowedReviewers);
94
+ const authenticatedUsername = await this.getAuthenticatedUsernameCached();
95
+ const prStateInfo = await this.fetchPRState(workspace, authenticatedUsername);
108
96
  if (!prStateInfo) {
109
97
  return {
110
98
  workspaceId: workspace.id,
@@ -113,37 +101,16 @@ class RatchetService {
113
101
  action: { type: 'ERROR', error: 'Failed to fetch PR state' },
114
102
  };
115
103
  }
116
- const newState = this.determineRatchetState(prStateInfo);
117
104
  const previousState = workspace.ratchetState;
118
- if (newState !== previousState) {
119
- logger.info('Ratchet state transition', {
120
- workspaceId: workspace.id,
121
- from: previousState,
122
- to: newState,
123
- prNumber: prStateInfo.prNumber,
124
- });
125
- }
126
- const latestWorkspace = await workspaceAccessor.findById(workspace.id);
127
- const shouldTakeAction = latestWorkspace?.ratchetEnabled ?? workspace.ratchetEnabled;
128
- const action = shouldTakeAction
129
- ? await this.executeRatchetAction(workspace, newState, prStateInfo, settings)
105
+ const newState = this.determineRatchetState(prStateInfo);
106
+ const action = workspace.ratchetEnabled
107
+ ? await this.evaluateAndDispatch(workspace, prStateInfo)
130
108
  : { type: 'DISABLED', reason: 'Workspace ratcheting disabled' };
131
- const now = new Date();
132
- const shouldRecordCiRunId = shouldTakeAction &&
133
- prStateInfo.ciStatus === CIStatus.FAILURE &&
134
- !!prStateInfo.ciRunId &&
135
- (action.type === 'NOTIFIED_ACTIVE_FIXER' ||
136
- (action.type === 'TRIGGERED_FIXER' && action.promptSent));
137
- await workspaceAccessor.update(workspace.id, {
138
- ratchetState: shouldTakeAction ? newState : RatchetState.IDLE,
139
- ratchetLastCheckedAt: now,
140
- ...(shouldRecordCiRunId ? { ratchetLastCiRunId: prStateInfo.ciRunId } : {}),
141
- ...(prStateInfo.hasNewReviewComments ? { prReviewLastCheckedAt: now } : {}),
142
- });
109
+ await this.updateWorkspaceAfterCheck(workspace, prStateInfo, action, workspace.ratchetEnabled ? newState : RatchetState.IDLE);
143
110
  return {
144
111
  workspaceId: workspace.id,
145
112
  previousState,
146
- newState: shouldTakeAction ? newState : RatchetState.IDLE,
113
+ newState: workspace.ratchetEnabled ? newState : RatchetState.IDLE,
147
114
  action,
148
115
  };
149
116
  }
@@ -160,6 +127,95 @@ class RatchetService {
160
127
  };
161
128
  }
162
129
  }
130
+ async evaluateAndDispatch(workspace, prStateInfo) {
131
+ if (prStateInfo.prState === 'MERGED') {
132
+ return { type: 'COMPLETED' };
133
+ }
134
+ if (prStateInfo.prState !== 'OPEN') {
135
+ return { type: 'WAITING', reason: 'PR is not open' };
136
+ }
137
+ if (this.shouldSkipCleanPR(workspace, prStateInfo)) {
138
+ return {
139
+ type: 'WAITING',
140
+ reason: 'PR is clean (green CI and no new review activity)',
141
+ };
142
+ }
143
+ const activeRatchetSession = await this.getActiveRatchetSession(workspace);
144
+ if (activeRatchetSession) {
145
+ return activeRatchetSession;
146
+ }
147
+ if (!this.hasStateChangedSinceLastDispatch(workspace, prStateInfo)) {
148
+ return { type: 'WAITING', reason: 'PR state unchanged since last ratchet dispatch' };
149
+ }
150
+ const hasOtherActiveSession = await this.hasNonRatchetActiveSession(workspace.id);
151
+ if (hasOtherActiveSession) {
152
+ return {
153
+ type: 'WAITING',
154
+ reason: 'Workspace is not idle (active non-ratchet chat session)',
155
+ };
156
+ }
157
+ return this.triggerFixer(workspace, prStateInfo);
158
+ }
159
+ shouldSkipCleanPR(workspace, prStateInfo) {
160
+ if (prStateInfo.ciStatus !== CIStatus.SUCCESS || prStateInfo.hasChangesRequested) {
161
+ return false;
162
+ }
163
+ return !this.hasNewReviewActivitySinceLastDispatch(workspace, prStateInfo);
164
+ }
165
+ hasNewReviewActivitySinceLastDispatch(workspace, prStateInfo) {
166
+ if (prStateInfo.latestReviewActivityAtMs === null) {
167
+ return false;
168
+ }
169
+ if (!workspace.prReviewLastCheckedAt) {
170
+ return true;
171
+ }
172
+ return prStateInfo.latestReviewActivityAtMs > workspace.prReviewLastCheckedAt.getTime();
173
+ }
174
+ hasStateChangedSinceLastDispatch(workspace, prStateInfo) {
175
+ return workspace.ratchetLastCiRunId !== prStateInfo.snapshotKey;
176
+ }
177
+ async updateWorkspaceAfterCheck(workspace, prStateInfo, action, nextState) {
178
+ const now = new Date();
179
+ const dispatched = action.type === 'TRIGGERED_FIXER' && action.promptSent;
180
+ await workspaceAccessor.update(workspace.id, {
181
+ ratchetState: nextState,
182
+ ratchetLastCheckedAt: now,
183
+ ...(dispatched
184
+ ? {
185
+ ratchetLastCiRunId: prStateInfo.snapshotKey,
186
+ prReviewLastCheckedAt: now,
187
+ }
188
+ : {}),
189
+ });
190
+ }
191
+ async getActiveRatchetSession(workspace) {
192
+ if (!workspace.ratchetActiveSessionId) {
193
+ return null;
194
+ }
195
+ const session = await claudeSessionAccessor.findById(workspace.ratchetActiveSessionId);
196
+ if (!session) {
197
+ await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
198
+ return null;
199
+ }
200
+ if (session.status !== SessionStatus.RUNNING) {
201
+ await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
202
+ return null;
203
+ }
204
+ if (!sessionService.isSessionRunning(session.id)) {
205
+ await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
206
+ return null;
207
+ }
208
+ return { type: 'FIXER_ACTIVE', sessionId: workspace.ratchetActiveSessionId };
209
+ }
210
+ async hasNonRatchetActiveSession(workspaceId) {
211
+ const sessions = await claudeSessionAccessor.findByWorkspaceId(workspaceId);
212
+ return sessions.some((session) => {
213
+ if (session.workflow === RATCHET_WORKFLOW) {
214
+ return false;
215
+ }
216
+ return (session.status === SessionStatus.RUNNING || sessionService.isSessionRunning(session.id));
217
+ });
218
+ }
163
219
  resolveRatchetPrContext(workspace) {
164
220
  const prInfo = githubCLIService.extractPRInfo(workspace.prUrl);
165
221
  if (!prInfo) {
@@ -179,7 +235,7 @@ class RatchetService {
179
235
  prNumber,
180
236
  };
181
237
  }
182
- async fetchPRState(workspace, allowedReviewers) {
238
+ async fetchPRState(workspace, authenticatedUsername) {
183
239
  const prContext = this.resolveRatchetPrContext(workspace);
184
240
  if (!prContext) {
185
241
  return null;
@@ -194,52 +250,14 @@ class RatchetService {
194
250
  conclusion: check.conclusion ?? undefined,
195
251
  })) ?? null;
196
252
  const ciStatus = githubCLIService.computeCIStatus(statusCheckRollup);
197
- const failedChecks = [];
198
- if (prDetails.statusCheckRollup) {
199
- for (const check of prDetails.statusCheckRollup) {
200
- const conclusion = String(check.conclusion || check.status);
201
- if (conclusion === 'FAILURE' ||
202
- conclusion === 'ACTION_REQUIRED' ||
203
- conclusion === 'ERROR') {
204
- failedChecks.push({
205
- name: check.name || 'Unknown check',
206
- conclusion,
207
- detailsUrl: check.detailsUrl,
208
- });
209
- }
210
- }
211
- }
212
- const ciRunId = this.extractFailedCiSignature(failedChecks);
213
- const hasChangesRequested = prDetails.reviews.some((r) => r.state === 'CHANGES_REQUESTED');
214
- const lastCheckedAt = workspace.prReviewLastCheckedAt?.getTime() ?? 0;
215
- const filterByReviewer = allowedReviewers.length > 0;
216
- const newReviewComments = reviewComments.filter((comment) => {
217
- const createdTime = new Date(comment.createdAt).getTime();
218
- const updatedTime = new Date(comment.updatedAt).getTime();
219
- const isNewOrEdited = createdTime > lastCheckedAt || updatedTime > lastCheckedAt;
220
- const isAllowedReviewer = !filterByReviewer || allowedReviewers.includes(comment.author.login);
221
- return isNewOrEdited && isAllowedReviewer;
222
- });
223
- const newPRComments = prDetails.comments.filter((comment) => {
224
- const createdTime = new Date(comment.createdAt).getTime();
225
- const updatedTime = new Date(comment.updatedAt).getTime();
226
- const isNewOrEdited = createdTime > lastCheckedAt || updatedTime > lastCheckedAt;
227
- const isAllowedReviewer = !filterByReviewer || allowedReviewers.includes(comment.author.login);
228
- return isNewOrEdited && isAllowedReviewer;
229
- });
230
- const hasNewReviewComments = newReviewComments.length > 0 || newPRComments.length > 0;
253
+ const hasChangesRequested = prDetails.reviewDecision === 'CHANGES_REQUESTED';
254
+ const latestReviewActivityAtMs = this.computeLatestReviewActivityAtMs(prDetails, reviewComments, authenticatedUsername);
255
+ const snapshotKey = this.computeDispatchSnapshotKey(ciStatus, hasChangesRequested, latestReviewActivityAtMs, prDetails.statusCheckRollup);
231
256
  return {
232
257
  ciStatus,
233
- mergeStateStatus: prDetails.mergeStateStatus,
258
+ snapshotKey,
234
259
  hasChangesRequested,
235
- hasNewReviewComments,
236
- failedChecks,
237
- ciRunId,
238
- reviews: prDetails.reviews,
239
- comments: prDetails.comments,
240
- reviewComments,
241
- newReviewComments,
242
- newPRComments,
260
+ latestReviewActivityAtMs,
243
261
  prState: prDetails.state,
244
262
  prNumber: prDetails.number,
245
263
  };
@@ -252,168 +270,94 @@ class RatchetService {
252
270
  return null;
253
271
  }
254
272
  }
273
+ computeDispatchSnapshotKey(ciStatus, hasChangesRequested, latestReviewActivityAtMs, statusChecks) {
274
+ const ciKey = this.computeCiSnapshotKey(ciStatus, statusChecks);
275
+ const reviewKey = `${hasChangesRequested ? 'changes-requested' : 'no-changes-requested'}:${latestReviewActivityAtMs ?? 'none'}`;
276
+ return `${ciKey}|${reviewKey}`;
277
+ }
278
+ computeCiSnapshotKey(ciStatus, statusChecks) {
279
+ if (ciStatus !== CIStatus.FAILURE) {
280
+ return `ci:${ciStatus}`;
281
+ }
282
+ const failedChecks = statusChecks?.filter((check) => {
283
+ const conclusion = check.conclusion?.toUpperCase();
284
+ return (conclusion === 'FAILURE' ||
285
+ conclusion === 'TIMED_OUT' ||
286
+ conclusion === 'CANCELLED' ||
287
+ conclusion === 'ERROR' ||
288
+ conclusion === 'ACTION_REQUIRED');
289
+ }) ?? [];
290
+ if (failedChecks.length === 0) {
291
+ return 'ci:FAILURE:unknown';
292
+ }
293
+ const signature = failedChecks
294
+ .map((check) => {
295
+ const runIdMatch = check.detailsUrl?.match(/\/actions\/runs\/(\d+)/);
296
+ const runId = runIdMatch?.[1] ?? 'no-run-id';
297
+ return `${check.name ?? 'unknown'}:${check.conclusion ?? 'UNKNOWN'}:${runId}`;
298
+ })
299
+ .sort()
300
+ .join('|');
301
+ return `ci:FAILURE:${signature}`;
302
+ }
303
+ computeLatestReviewActivityAtMs(prDetails, reviewComments, authenticatedUsername) {
304
+ const entries = [
305
+ ...prDetails.reviews.map((review) => ({
306
+ authorLogin: review.author.login,
307
+ timestamp: review.submittedAt,
308
+ })),
309
+ ...prDetails.comments.map((comment) => ({
310
+ authorLogin: comment.author.login,
311
+ timestamp: comment.updatedAt,
312
+ })),
313
+ ...reviewComments.map((reviewComment) => ({
314
+ authorLogin: reviewComment.author.login,
315
+ timestamp: reviewComment.updatedAt,
316
+ })),
317
+ ];
318
+ const timestamps = entries
319
+ .filter((entry) => !this.isIgnoredReviewAuthor(entry.authorLogin, authenticatedUsername))
320
+ .map((entry) => Date.parse(entry.timestamp))
321
+ .filter((timestamp) => Number.isFinite(timestamp));
322
+ return timestamps.length > 0 ? Math.max(...timestamps) : null;
323
+ }
324
+ isIgnoredReviewAuthor(authorLogin, authenticatedUsername) {
325
+ if (!authenticatedUsername) {
326
+ return false;
327
+ }
328
+ return authorLogin === authenticatedUsername;
329
+ }
330
+ async getAuthenticatedUsernameCached() {
331
+ const nowMs = Date.now();
332
+ if (this.cachedAuthenticatedUsername && this.cachedAuthenticatedUsername.expiresAtMs > nowMs) {
333
+ return this.cachedAuthenticatedUsername.value;
334
+ }
335
+ const username = await githubCLIService.getAuthenticatedUsername();
336
+ this.cachedAuthenticatedUsername = {
337
+ value: username,
338
+ expiresAtMs: nowMs + AUTHENTICATED_USERNAME_CACHE_TTL_MS,
339
+ };
340
+ return username;
341
+ }
255
342
  determineRatchetState(pr) {
256
343
  if (pr.prState === 'MERGED') {
257
344
  return RatchetState.MERGED;
258
345
  }
259
- if (pr.ciStatus === CIStatus.PENDING) {
346
+ if (pr.prState !== 'OPEN') {
347
+ return RatchetState.IDLE;
348
+ }
349
+ if (pr.ciStatus === CIStatus.PENDING || pr.ciStatus === CIStatus.UNKNOWN) {
260
350
  return RatchetState.CI_RUNNING;
261
351
  }
262
352
  if (pr.ciStatus === CIStatus.FAILURE) {
263
353
  return RatchetState.CI_FAILED;
264
354
  }
265
- if (pr.ciStatus === CIStatus.UNKNOWN) {
266
- return RatchetState.CI_RUNNING;
267
- }
268
- if (pr.hasChangesRequested || pr.hasNewReviewComments) {
355
+ if (pr.hasChangesRequested) {
269
356
  return RatchetState.REVIEW_PENDING;
270
357
  }
271
358
  return RatchetState.READY;
272
359
  }
273
- async executeRatchetAction(workspace, state, prStateInfo, settings) {
274
- const existingFixerResult = await this.handleExistingFixerSession(workspace, state, prStateInfo);
275
- if (existingFixerResult) {
276
- return existingFixerResult;
277
- }
278
- return this.handleStateWithoutActiveFixer(workspace, state, prStateInfo, settings);
279
- }
280
- async handleExistingFixerSession(workspace, state, prStateInfo) {
281
- if (!workspace.ratchetActiveSessionId) {
282
- return null;
283
- }
284
- const session = await claudeSessionAccessor.findById(workspace.ratchetActiveSessionId);
285
- const client = sessionService.getClient(workspace.ratchetActiveSessionId);
286
- if (!session) {
287
- await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
288
- return null;
289
- }
290
- if (session.status === SessionStatus.IDLE) {
291
- if (!client) {
292
- await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
293
- }
294
- return null;
295
- }
296
- if (session.status !== SessionStatus.RUNNING || !client) {
297
- await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
298
- return null;
299
- }
300
- const shouldNotify = this.shouldNotifyActiveFixer(state, workspace.ratchetLastNotifiedState, prStateInfo.ciRunId, workspace.ratchetLastCiRunId);
301
- if (!shouldNotify) {
302
- return { type: 'FIXER_ACTIVE', sessionId: workspace.ratchetActiveSessionId };
303
- }
304
- const delivered = await this.notifyActiveFixer(workspace, state, prStateInfo, client);
305
- if (delivered) {
306
- return {
307
- type: 'NOTIFIED_ACTIVE_FIXER',
308
- sessionId: workspace.ratchetActiveSessionId,
309
- issue: state,
310
- };
311
- }
312
- logger.warn('Failed to notify active fixer; clearing stale reference and retrying', {
313
- workspaceId: workspace.id,
314
- sessionId: workspace.ratchetActiveSessionId,
315
- state,
316
- });
317
- await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
318
- return null;
319
- }
320
- async handleStateWithoutActiveFixer(workspace, state, prStateInfo, settings) {
321
- switch (state) {
322
- case RatchetState.IDLE:
323
- return { type: 'WAITING', reason: 'No PR or ratchet not active' };
324
- case RatchetState.CI_RUNNING:
325
- return { type: 'WAITING', reason: 'CI is running' };
326
- case RatchetState.CI_FAILED:
327
- if (!settings.autoFixCi) {
328
- return { type: 'DISABLED', reason: 'CI auto-fix disabled' };
329
- }
330
- if (prStateInfo.ciRunId && prStateInfo.ciRunId === workspace.ratchetLastCiRunId) {
331
- logger.info('Skipping CI fixer dispatch — already handled this CI run', {
332
- workspaceId: workspace.id,
333
- ciRunId: prStateInfo.ciRunId,
334
- });
335
- return {
336
- type: 'WAITING',
337
- reason: 'Already dispatched fixer for this CI run; waiting for new run',
338
- };
339
- }
340
- return await this.triggerFixer(workspace, 'ci', prStateInfo, settings);
341
- case RatchetState.REVIEW_PENDING:
342
- if (!settings.autoFixReviews) {
343
- return { type: 'DISABLED', reason: 'Review auto-fix disabled' };
344
- }
345
- return await this.triggerFixer(workspace, 'review', prStateInfo, settings);
346
- case RatchetState.READY:
347
- if (settings.autoMerge) {
348
- logger.info('PR ready for merge (auto-merge not yet implemented)', {
349
- workspaceId: workspace.id,
350
- prNumber: workspace.prNumber,
351
- });
352
- return { type: 'READY_FOR_MERGE' };
353
- }
354
- return { type: 'READY_FOR_MERGE' };
355
- case RatchetState.MERGED:
356
- return { type: 'COMPLETED' };
357
- default:
358
- return { type: 'WAITING', reason: `Unknown state: ${state}` };
359
- }
360
- }
361
- shouldNotifyActiveFixer(currentState, lastNotifiedState, currentCiRunId, lastCiRunId) {
362
- if (currentState === RatchetState.CI_FAILED &&
363
- currentCiRunId &&
364
- currentCiRunId !== lastCiRunId) {
365
- return true;
366
- }
367
- if (currentState === lastNotifiedState) {
368
- return false;
369
- }
370
- return currentState === RatchetState.CI_FAILED;
371
- }
372
- async notifyActiveFixer(workspace, state, prStateInfo, client) {
373
- if (!workspace.ratchetActiveSessionId) {
374
- logger.warn('notifyActiveFixer called without active session ID', {
375
- workspaceId: workspace.id,
376
- });
377
- return false;
378
- }
379
- let message = '';
380
- if (state === RatchetState.CI_FAILED) {
381
- message = `⚠️ **CI Failed**
382
-
383
- The CI checks have failed. This may be due to your recent changes.
384
-
385
- **Failed checks:**
386
- ${prStateInfo.failedChecks.map((c) => `- **${c.name}**: ${c.conclusion}${c.detailsUrl ? ` ([logs](${c.detailsUrl}))` : ''}`).join('\n')}
387
-
388
- Please investigate and fix the CI failure before continuing with your current task.
389
- Use \`gh pr checks ${prStateInfo.prNumber}\` to see current status.
390
- Use \`gh run view <run-id> --log-failed\` to see detailed logs.`;
391
- }
392
- if (message) {
393
- try {
394
- await client.sendMessage(message);
395
- logger.info('Notified active fixer about state change', {
396
- workspaceId: workspace.id,
397
- sessionId: workspace.ratchetActiveSessionId,
398
- state,
399
- });
400
- await workspaceAccessor.update(workspace.id, {
401
- ratchetLastNotifiedState: state,
402
- });
403
- return true;
404
- }
405
- catch (error) {
406
- logger.warn('Failed to notify fixer about state change', {
407
- workspaceId: workspace.id,
408
- state,
409
- error,
410
- });
411
- return false;
412
- }
413
- }
414
- return false;
415
- }
416
- async triggerFixer(workspace, fixerType, prStateInfo, settings) {
360
+ async triggerFixer(workspace, prStateInfo) {
417
361
  try {
418
362
  const result = await fixerSessionService.acquireAndDispatch({
419
363
  workspaceId: workspace.id,
@@ -421,30 +365,31 @@ Use \`gh run view <run-id> --log-failed\` to see detailed logs.`;
421
365
  sessionName: 'Ratchet',
422
366
  runningIdleAction: 'restart',
423
367
  dispatchMode: 'start_empty_and_send',
424
- buildPrompt: () => this.buildInitialPrompt(fixerType, workspace.prUrl, prStateInfo, settings),
368
+ buildPrompt: () => buildRatchetDispatchPrompt(workspace.prUrl, prStateInfo.prNumber),
425
369
  beforeStart: ({ sessionId, prompt }) => {
426
370
  messageStateService.injectCommittedUserMessage(sessionId, prompt);
427
371
  },
428
372
  });
429
373
  if (result.status === 'started') {
430
- const shouldMarkNotified = result.promptSent ?? true;
374
+ const promptSent = result.promptSent ?? true;
375
+ if (!promptSent) {
376
+ logger.warn('Ratchet session started but prompt delivery failed', {
377
+ workspaceId: workspace.id,
378
+ sessionId: result.sessionId,
379
+ });
380
+ await workspaceAccessor.update(workspace.id, { ratchetActiveSessionId: null });
381
+ if (sessionService.isSessionRunning(result.sessionId)) {
382
+ await sessionService.stopClaudeSession(result.sessionId);
383
+ }
384
+ return { type: 'ERROR', error: 'Failed to deliver initial ratchet prompt' };
385
+ }
431
386
  await workspaceAccessor.update(workspace.id, {
432
387
  ratchetActiveSessionId: result.sessionId,
433
- ...(shouldMarkNotified && {
434
- ratchetLastNotifiedState: this.determineRatchetState(prStateInfo),
435
- }),
436
- });
437
- logger.info('Ratchet fixer session started', {
438
- workspaceId: workspace.id,
439
- sessionId: result.sessionId,
440
- fixerType,
441
- prNumber: prStateInfo.prNumber,
442
388
  });
443
389
  return {
444
390
  type: 'TRIGGERED_FIXER',
445
391
  sessionId: result.sessionId,
446
- fixerType,
447
- promptSent: shouldMarkNotified,
392
+ promptSent,
448
393
  };
449
394
  }
450
395
  if (result.status === 'already_active') {
@@ -460,169 +405,10 @@ Use \`gh run view <run-id> --log-failed\` to see detailed logs.`;
460
405
  const errorMessage = error instanceof Error ? error.message : String(error);
461
406
  logger.error('Failed to trigger ratchet fixer', error, {
462
407
  workspaceId: workspace.id,
463
- fixerType,
464
408
  });
465
409
  return { type: 'ERROR', error: errorMessage };
466
410
  }
467
411
  }
468
- buildInitialPrompt(fixerType, prUrl, prStateInfo, settings) {
469
- const prNumber = prStateInfo.prNumber;
470
- switch (fixerType) {
471
- case 'ci':
472
- return this.buildCIFixPrompt(prNumber, prUrl, prStateInfo);
473
- case 'review':
474
- return this.buildReviewFixPrompt(prNumber, prUrl, prStateInfo, settings);
475
- default:
476
- return `Please investigate the issue with PR #${prNumber}.`;
477
- }
478
- }
479
- buildCIFixPrompt(prNumber, prUrl, prStateInfo) {
480
- let prompt = `## CI Failure Alert
481
-
482
- The CI checks for PR #${prNumber} have failed.
483
-
484
- **PR URL:** ${prUrl}
485
-
486
- `;
487
- if (prStateInfo.failedChecks.length > 0) {
488
- prompt += `### Failed Checks\n\n`;
489
- for (const check of prStateInfo.failedChecks) {
490
- prompt += `- **${check.name}**: ${check.conclusion}`;
491
- if (check.detailsUrl) {
492
- prompt += ` ([logs](${check.detailsUrl}))`;
493
- }
494
- prompt += `\n`;
495
- }
496
- prompt += `\n`;
497
- }
498
- prompt += `### Next Steps
499
-
500
- 1. Sync with main first: \`git fetch origin && git merge origin/main\` (resolve any conflicts)
501
- 2. Use \`gh pr checks ${prNumber}\` to see the current check status
502
- 3. Use \`gh run view <run-id> --log-failed\` to see detailed failure logs
503
- 4. Identify the root cause and implement a fix
504
- 5. Run tests locally to verify: \`pnpm test\`
505
- 6. Run type checking: \`pnpm typecheck\`
506
- 7. Run linting: \`pnpm check:fix\`
507
- 8. Commit and push your changes
508
-
509
- Please investigate and fix these CI failures.`;
510
- return prompt;
511
- }
512
- filterByAllowedReviewers(items, allowedReviewers) {
513
- if (allowedReviewers.length === 0) {
514
- return items;
515
- }
516
- return items.filter((item) => allowedReviewers.includes(item.author.login));
517
- }
518
- formatReviewsSection(reviews) {
519
- if (reviews.length === 0) {
520
- return '';
521
- }
522
- const lines = ['### Reviews Requesting Changes\n\n'];
523
- for (const review of reviews) {
524
- lines.push(`**${review.author.login}** (${new Date(review.submittedAt).toLocaleDateString()}):\n`);
525
- if (review.body) {
526
- lines.push(`> ${review.body.split('\n').join('\n> ')}\n`);
527
- }
528
- lines.push('\n');
529
- }
530
- return lines.join('');
531
- }
532
- formatCodeCommentsSection(comments) {
533
- if (comments.length === 0) {
534
- return '';
535
- }
536
- const lines = ['### Review Comments on Code\n\n'];
537
- for (const comment of comments) {
538
- const location = comment.line ? `:${comment.line}` : '';
539
- lines.push(`**${comment.author.login}** on \`${comment.path}\`${location}:\n`);
540
- lines.push(`> ${comment.body.split('\n').join('\n> ')}\n`);
541
- lines.push(`> [View comment](${comment.url})\n\n`);
542
- }
543
- return lines.join('');
544
- }
545
- formatPRCommentsSection(comments) {
546
- if (comments.length === 0) {
547
- return '';
548
- }
549
- const lines = ['### PR Comments\n\n'];
550
- for (const comment of comments) {
551
- lines.push(`**${comment.author.login}** (${new Date(comment.createdAt).toLocaleDateString()}):\n`);
552
- lines.push(`> ${comment.body.split('\n').join('\n> ')}\n\n`);
553
- }
554
- return lines.join('');
555
- }
556
- buildReviewFixPrompt(prNumber, prUrl, prStateInfo, settings) {
557
- const parts = [
558
- `## PR Review Comments Alert
559
-
560
- New review comments have been received on PR #${prNumber}.
561
-
562
- **PR URL:** ${prUrl}
563
-
564
- `,
565
- ];
566
- const changesRequestedReviews = prStateInfo.reviews.filter((r) => r.state === 'CHANGES_REQUESTED');
567
- const filteredReviews = this.filterByAllowedReviewers(changesRequestedReviews, settings.allowedReviewers);
568
- parts.push(this.formatReviewsSection(filteredReviews));
569
- parts.push(this.formatCodeCommentsSection(prStateInfo.newReviewComments));
570
- parts.push(this.formatPRCommentsSection(prStateInfo.newPRComments));
571
- const reviewerSet = new Set([
572
- ...filteredReviews.map((r) => r.author.login),
573
- ...prStateInfo.newReviewComments.map((c) => c.author.login),
574
- ...prStateInfo.newPRComments.map((c) => c.author.login),
575
- ]);
576
- const reviewerMentions = Array.from(reviewerSet)
577
- .map((r) => `@${r}`)
578
- .join(' ');
579
- parts.push(`### Instructions
580
-
581
- **IMPORTANT: Execute autonomously. Do not ask the user for input or confirmation. Complete all steps without waiting.**
582
-
583
- 1. **Sync with main** - Before making changes, sync your branch:
584
- \`\`\`bash
585
- git fetch origin && git merge origin/main
586
- \`\`\`
587
- Resolve any conflicts as part of your fix.
588
-
589
- 2. **Analyze each comment** - Determine what changes are requested. If a comment is purely informational (e.g., automated coverage reports with no action items), note it and move on.
590
-
591
- 3. **Implement fixes** - Address each actionable comment systematically. Make focused changes that directly address the feedback.
592
-
593
- 4. **Verify changes**:
594
- \`\`\`bash
595
- pnpm test && pnpm typecheck && pnpm check:fix
596
- \`\`\`
597
-
598
- 5. **Commit and push**:
599
- \`\`\`bash
600
- git add -A && git commit -m "Address review comments" && git push
601
- \`\`\`
602
-
603
- 6. **Post re-review request** - After pushing, notify the reviewers:
604
- \`\`\`bash
605
- gh pr comment ${prNumber} --body "${reviewerMentions} I've addressed the review comments. Please re-review when you have a chance."
606
- \`\`\`
607
-
608
- **Do not ask the user what to do. Analyze the comments, implement fixes, push, and request re-review.**`);
609
- return parts.join('');
610
- }
611
- extractFailedCiSignature(failedChecks) {
612
- if (failedChecks.length === 0) {
613
- return null;
614
- }
615
- const failedEntries = [];
616
- for (const check of failedChecks) {
617
- const runIdMatch = check.detailsUrl?.match(/\/actions\/runs\/(\d+)/);
618
- const runId = runIdMatch?.[1] ?? 'no-run-id';
619
- failedEntries.push(`${check.name}:${runId}`);
620
- }
621
- if (failedEntries.length === 0) {
622
- return null;
623
- }
624
- return failedEntries.sort().join('|');
625
- }
626
412
  }
627
413
  export const ratchetService = new RatchetService();
628
414
  //# sourceMappingURL=ratchet.service.js.map