reviewflow 3.12.0 → 3.13.0

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 (271) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/frameworks/claude/claudeInvoker.d.ts +29 -0
  3. package/dist/frameworks/claude/claudeInvoker.d.ts.map +1 -1
  4. package/dist/frameworks/claude/claudeInvoker.js +201 -268
  5. package/dist/frameworks/claude/claudeInvoker.js.map +1 -1
  6. package/dist/frameworks/claude/streamJsonParser.d.ts +1 -38
  7. package/dist/frameworks/claude/streamJsonParser.d.ts.map +1 -1
  8. package/dist/frameworks/claude/streamJsonParser.js +16 -88
  9. package/dist/frameworks/claude/streamJsonParser.js.map +1 -1
  10. package/dist/frameworks/claude/timers/claudeInvocationTimers.d.ts +14 -0
  11. package/dist/frameworks/claude/timers/claudeInvocationTimers.d.ts.map +1 -0
  12. package/dist/frameworks/claude/timers/claudeInvocationTimers.js +23 -0
  13. package/dist/frameworks/claude/timers/claudeInvocationTimers.js.map +1 -0
  14. package/dist/main/dependencies.d.ts +2 -0
  15. package/dist/main/dependencies.d.ts.map +1 -1
  16. package/dist/main/dependencies.js +2 -0
  17. package/dist/main/dependencies.js.map +1 -1
  18. package/dist/main/routes.d.ts.map +1 -1
  19. package/dist/main/routes.js +3 -0
  20. package/dist/main/routes.js.map +1 -1
  21. package/dist/main/server.d.ts.map +1 -1
  22. package/dist/main/server.js +16 -0
  23. package/dist/main/server.js.map +1 -1
  24. package/dist/mcp/mcpServerStdio.d.ts.map +1 -1
  25. package/dist/mcp/mcpServerStdio.js +10 -1
  26. package/dist/mcp/mcpServerStdio.js.map +1 -1
  27. package/dist/modules/claude-invocation/entities/billingState/billingState.gateway.d.ts +8 -0
  28. package/dist/modules/claude-invocation/entities/billingState/billingState.gateway.d.ts.map +1 -0
  29. package/dist/modules/claude-invocation/entities/billingState/billingState.gateway.js +2 -0
  30. package/dist/modules/claude-invocation/entities/billingState/billingState.gateway.js.map +1 -0
  31. package/dist/modules/claude-invocation/entities/billingState/billingState.schema.d.ts +8 -0
  32. package/dist/modules/claude-invocation/entities/billingState/billingState.schema.d.ts.map +1 -0
  33. package/dist/modules/claude-invocation/entities/billingState/billingState.schema.js +7 -0
  34. package/dist/modules/claude-invocation/entities/billingState/billingState.schema.js.map +1 -0
  35. package/dist/modules/claude-invocation/entities/billingState/environment.gateway.d.ts +4 -0
  36. package/dist/modules/claude-invocation/entities/billingState/environment.gateway.d.ts.map +1 -0
  37. package/dist/modules/claude-invocation/entities/billingState/environment.gateway.js +2 -0
  38. package/dist/modules/claude-invocation/entities/billingState/environment.gateway.js.map +1 -0
  39. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.d.ts +16 -0
  40. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.d.ts.map +1 -0
  41. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts +52 -0
  42. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts.map +1 -0
  43. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.js +2 -0
  44. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.js.map +1 -0
  45. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.d.ts +11 -0
  46. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.d.ts.map +1 -0
  47. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.js +4 -0
  48. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.js.map +1 -0
  49. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.js +29 -0
  50. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.js.map +1 -0
  51. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts +38 -0
  52. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts.map +1 -0
  53. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js +27 -0
  54. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js.map +1 -0
  55. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.schema.d.ts +10 -0
  56. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.schema.d.ts.map +1 -0
  57. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.schema.js +14 -0
  58. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.schema.js.map +1 -0
  59. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.valueObject.d.ts +10 -0
  60. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.valueObject.d.ts.map +1 -0
  61. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.valueObject.js +11 -0
  62. package/dist/modules/claude-invocation/entities/retrySchedule/retrySchedule.valueObject.js.map +1 -0
  63. package/dist/modules/claude-invocation/entities/sessionCompletion/mcpCompletion.gateway.d.ts +8 -0
  64. package/dist/modules/claude-invocation/entities/sessionCompletion/mcpCompletion.gateway.d.ts.map +1 -0
  65. package/dist/modules/claude-invocation/entities/sessionCompletion/mcpCompletion.gateway.js +2 -0
  66. package/dist/modules/claude-invocation/entities/sessionCompletion/mcpCompletion.gateway.js.map +1 -0
  67. package/dist/modules/claude-invocation/entities/sessionCompletion/reviewReport.gateway.d.ts +16 -0
  68. package/dist/modules/claude-invocation/entities/sessionCompletion/reviewReport.gateway.d.ts.map +1 -0
  69. package/dist/modules/claude-invocation/entities/sessionCompletion/reviewReport.gateway.js +2 -0
  70. package/dist/modules/claude-invocation/entities/sessionCompletion/reviewReport.gateway.js.map +1 -0
  71. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.guard.d.ts +8 -0
  72. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.guard.d.ts.map +1 -0
  73. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.guard.js +7 -0
  74. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.guard.js.map +1 -0
  75. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.schema.d.ts +28 -0
  76. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.schema.d.ts.map +1 -0
  77. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.schema.js +9 -0
  78. package/dist/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.schema.js.map +1 -0
  79. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.gateway.d.ts +6 -0
  80. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.gateway.d.ts.map +1 -0
  81. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.gateway.js +2 -0
  82. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.gateway.js.map +1 -0
  83. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.schema.d.ts +16 -0
  84. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.schema.d.ts.map +1 -0
  85. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.schema.js +8 -0
  86. package/dist/modules/claude-invocation/entities/supervisorHealth/supervisorHealth.schema.js.map +1 -0
  87. package/dist/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.d.ts +10 -0
  88. package/dist/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.d.ts.map +1 -0
  89. package/dist/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.js +32 -0
  90. package/dist/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.js.map +1 -0
  91. package/dist/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.d.ts +25 -0
  92. package/dist/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.d.ts.map +1 -0
  93. package/dist/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.js +102 -0
  94. package/dist/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.js.map +1 -0
  95. package/dist/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.d.ts +8 -0
  96. package/dist/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.d.ts.map +1 -0
  97. package/dist/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.js +11 -0
  98. package/dist/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.js.map +1 -0
  99. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.d.ts +34 -0
  100. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.d.ts.map +1 -0
  101. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.js +131 -0
  102. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.js.map +1 -0
  103. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.d.ts +10 -0
  104. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.d.ts.map +1 -0
  105. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.js +24 -0
  106. package/dist/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.js.map +1 -0
  107. package/dist/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.d.ts +12 -0
  108. package/dist/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.d.ts.map +1 -0
  109. package/dist/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.js +25 -0
  110. package/dist/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.js.map +1 -0
  111. package/dist/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.d.ts +8 -0
  112. package/dist/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.d.ts.map +1 -0
  113. package/dist/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.js +18 -0
  114. package/dist/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.js.map +1 -0
  115. package/dist/modules/claude-invocation/usecases/auditBilling.usecase.d.ts +15 -0
  116. package/dist/modules/claude-invocation/usecases/auditBilling.usecase.d.ts.map +1 -0
  117. package/dist/modules/claude-invocation/usecases/auditBilling.usecase.js +12 -0
  118. package/dist/modules/claude-invocation/usecases/auditBilling.usecase.js.map +1 -0
  119. package/dist/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.d.ts +16 -0
  120. package/dist/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.d.ts.map +1 -0
  121. package/dist/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.js +64 -0
  122. package/dist/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.js.map +1 -0
  123. package/dist/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.d.ts +10 -0
  124. package/dist/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.d.ts.map +1 -0
  125. package/dist/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.js +12 -0
  126. package/dist/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.js.map +1 -0
  127. package/dist/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.d.ts +15 -0
  128. package/dist/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.d.ts.map +1 -0
  129. package/dist/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.js +25 -0
  130. package/dist/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.js.map +1 -0
  131. package/dist/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.d.ts +34 -0
  132. package/dist/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.d.ts.map +1 -0
  133. package/dist/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.js +32 -0
  134. package/dist/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.js.map +1 -0
  135. package/dist/modules/claude-invocation/usecases/retrieveReviewReport.usecase.d.ts +20 -0
  136. package/dist/modules/claude-invocation/usecases/retrieveReviewReport.usecase.d.ts.map +1 -0
  137. package/dist/modules/claude-invocation/usecases/retrieveReviewReport.usecase.js +17 -0
  138. package/dist/modules/claude-invocation/usecases/retrieveReviewReport.usecase.js.map +1 -0
  139. package/dist/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.d.ts +41 -0
  140. package/dist/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.d.ts.map +1 -0
  141. package/dist/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.js +88 -0
  142. package/dist/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.js.map +1 -0
  143. package/dist/modules/review-execution/usecases/mcp/setPhase.usecase.d.ts +2 -0
  144. package/dist/modules/review-execution/usecases/mcp/setPhase.usecase.d.ts.map +1 -1
  145. package/dist/modules/review-execution/usecases/mcp/setPhase.usecase.js +4 -1
  146. package/dist/modules/review-execution/usecases/mcp/setPhase.usecase.js.map +1 -1
  147. package/dist/tests/acceptance/169-migrate-claude-invocation-to-bg-mode.acceptance.test.d.ts +2 -0
  148. package/dist/tests/acceptance/169-migrate-claude-invocation-to-bg-mode.acceptance.test.d.ts.map +1 -0
  149. package/dist/tests/acceptance/169-migrate-claude-invocation-to-bg-mode.acceptance.test.js +238 -0
  150. package/dist/tests/acceptance/169-migrate-claude-invocation-to-bg-mode.acceptance.test.js.map +1 -0
  151. package/dist/tests/factories/claudeSession.factory.d.ts +5 -0
  152. package/dist/tests/factories/claudeSession.factory.d.ts.map +1 -0
  153. package/dist/tests/factories/claudeSession.factory.js +17 -0
  154. package/dist/tests/factories/claudeSession.factory.js.map +1 -0
  155. package/dist/tests/factories/sessionCompletion.factory.d.ts +5 -0
  156. package/dist/tests/factories/sessionCompletion.factory.d.ts.map +1 -0
  157. package/dist/tests/factories/sessionCompletion.factory.js +11 -0
  158. package/dist/tests/factories/sessionCompletion.factory.js.map +1 -0
  159. package/dist/tests/integration/claudeInvocation.integration.test.d.ts +2 -0
  160. package/dist/tests/integration/claudeInvocation.integration.test.d.ts.map +1 -0
  161. package/dist/tests/integration/claudeInvocation.integration.test.js +147 -0
  162. package/dist/tests/integration/claudeInvocation.integration.test.js.map +1 -0
  163. package/dist/tests/stubs/billingState.stub.d.ts +10 -0
  164. package/dist/tests/stubs/billingState.stub.d.ts.map +1 -0
  165. package/dist/tests/stubs/billingState.stub.js +32 -0
  166. package/dist/tests/stubs/billingState.stub.js.map +1 -0
  167. package/dist/tests/stubs/claudeSession.stub.d.ts +23 -0
  168. package/dist/tests/stubs/claudeSession.stub.d.ts.map +1 -0
  169. package/dist/tests/stubs/claudeSession.stub.js +55 -0
  170. package/dist/tests/stubs/claudeSession.stub.js.map +1 -0
  171. package/dist/tests/stubs/environment.stub.d.ts +7 -0
  172. package/dist/tests/stubs/environment.stub.d.ts.map +1 -0
  173. package/dist/tests/stubs/environment.stub.js +10 -0
  174. package/dist/tests/stubs/environment.stub.js.map +1 -0
  175. package/dist/tests/stubs/mcpCompletion.stub.d.ts +13 -0
  176. package/dist/tests/stubs/mcpCompletion.stub.d.ts.map +1 -0
  177. package/dist/tests/stubs/mcpCompletion.stub.js +29 -0
  178. package/dist/tests/stubs/mcpCompletion.stub.js.map +1 -0
  179. package/dist/tests/stubs/reviewReport.stub.d.ts +11 -0
  180. package/dist/tests/stubs/reviewReport.stub.d.ts.map +1 -0
  181. package/dist/tests/stubs/reviewReport.stub.js +21 -0
  182. package/dist/tests/stubs/reviewReport.stub.js.map +1 -0
  183. package/dist/tests/stubs/supervisorHealth.stub.d.ts +8 -0
  184. package/dist/tests/stubs/supervisorHealth.stub.d.ts.map +1 -0
  185. package/dist/tests/stubs/supervisorHealth.stub.js +18 -0
  186. package/dist/tests/stubs/supervisorHealth.stub.js.map +1 -0
  187. package/dist/tests/units/architecture/noClaudePInProduction.test.d.ts +2 -0
  188. package/dist/tests/units/architecture/noClaudePInProduction.test.d.ts.map +1 -0
  189. package/dist/tests/units/architecture/noClaudePInProduction.test.js +89 -0
  190. package/dist/tests/units/architecture/noClaudePInProduction.test.js.map +1 -0
  191. package/dist/tests/units/frameworks/claude/buildSpawnEnv.test.d.ts +2 -0
  192. package/dist/tests/units/frameworks/claude/buildSpawnEnv.test.d.ts.map +1 -0
  193. package/dist/tests/units/frameworks/claude/buildSpawnEnv.test.js +30 -0
  194. package/dist/tests/units/frameworks/claude/buildSpawnEnv.test.js.map +1 -0
  195. package/dist/tests/units/frameworks/claude/streamJsonParser.test.js +15 -72
  196. package/dist/tests/units/frameworks/claude/streamJsonParser.test.js.map +1 -1
  197. package/dist/tests/units/frameworks/claude/timers/claudeInvocationTimers.test.d.ts +2 -0
  198. package/dist/tests/units/frameworks/claude/timers/claudeInvocationTimers.test.d.ts.map +1 -0
  199. package/dist/tests/units/frameworks/claude/timers/claudeInvocationTimers.test.js +66 -0
  200. package/dist/tests/units/frameworks/claude/timers/claudeInvocationTimers.test.js.map +1 -0
  201. package/dist/tests/units/modules/claude-invocation/entities/claudeSession/claudeSession.test.d.ts +2 -0
  202. package/dist/tests/units/modules/claude-invocation/entities/claudeSession/claudeSession.test.d.ts.map +1 -0
  203. package/dist/tests/units/modules/claude-invocation/entities/claudeSession/claudeSession.test.js +51 -0
  204. package/dist/tests/units/modules/claude-invocation/entities/claudeSession/claudeSession.test.js.map +1 -0
  205. package/dist/tests/units/modules/claude-invocation/entities/retrySchedule/retrySchedule.test.d.ts +2 -0
  206. package/dist/tests/units/modules/claude-invocation/entities/retrySchedule/retrySchedule.test.d.ts.map +1 -0
  207. package/dist/tests/units/modules/claude-invocation/entities/retrySchedule/retrySchedule.test.js +28 -0
  208. package/dist/tests/units/modules/claude-invocation/entities/retrySchedule/retrySchedule.test.js.map +1 -0
  209. package/dist/tests/units/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.test.d.ts +2 -0
  210. package/dist/tests/units/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.test.d.ts.map +1 -0
  211. package/dist/tests/units/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.test.js +27 -0
  212. package/dist/tests/units/modules/claude-invocation/entities/sessionCompletion/sessionCompletion.test.js.map +1 -0
  213. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.test.d.ts +2 -0
  214. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.test.d.ts.map +1 -0
  215. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.test.js +40 -0
  216. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.test.js.map +1 -0
  217. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.test.d.ts +2 -0
  218. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.test.d.ts.map +1 -0
  219. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.test.js +188 -0
  220. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.test.js.map +1 -0
  221. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.test.d.ts +2 -0
  222. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.test.d.ts.map +1 -0
  223. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.test.js +17 -0
  224. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.test.js.map +1 -0
  225. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.test.d.ts +2 -0
  226. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.test.d.ts.map +1 -0
  227. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.test.js +119 -0
  228. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.test.js.map +1 -0
  229. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.test.d.ts +2 -0
  230. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.test.d.ts.map +1 -0
  231. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.test.js +39 -0
  232. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/mcpCompletion.memory.gateway.test.js.map +1 -0
  233. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.test.d.ts +2 -0
  234. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.test.d.ts.map +1 -0
  235. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.test.js +64 -0
  236. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.test.js.map +1 -0
  237. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.test.d.ts +2 -0
  238. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.test.d.ts.map +1 -0
  239. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.test.js +32 -0
  240. package/dist/tests/units/modules/claude-invocation/interface-adapters/gateways/supervisorHealth.memory.gateway.test.js.map +1 -0
  241. package/dist/tests/units/modules/claude-invocation/usecases/auditBilling.usecase.test.d.ts +2 -0
  242. package/dist/tests/units/modules/claude-invocation/usecases/auditBilling.usecase.test.d.ts.map +1 -0
  243. package/dist/tests/units/modules/claude-invocation/usecases/auditBilling.usecase.test.js +33 -0
  244. package/dist/tests/units/modules/claude-invocation/usecases/auditBilling.usecase.test.js.map +1 -0
  245. package/dist/tests/units/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.test.d.ts +2 -0
  246. package/dist/tests/units/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.test.d.ts.map +1 -0
  247. package/dist/tests/units/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.test.js +53 -0
  248. package/dist/tests/units/modules/claude-invocation/usecases/awaitSessionCompletion.usecase.test.js.map +1 -0
  249. package/dist/tests/units/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.test.d.ts +2 -0
  250. package/dist/tests/units/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.test.d.ts.map +1 -0
  251. package/dist/tests/units/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.test.js +31 -0
  252. package/dist/tests/units/modules/claude-invocation/usecases/checkSupervisorHealth.usecase.test.js.map +1 -0
  253. package/dist/tests/units/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.test.d.ts +2 -0
  254. package/dist/tests/units/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.test.d.ts.map +1 -0
  255. package/dist/tests/units/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.test.js +17 -0
  256. package/dist/tests/units/modules/claude-invocation/usecases/cleanupClaudeSession.usecase.test.js.map +1 -0
  257. package/dist/tests/units/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.test.d.ts +2 -0
  258. package/dist/tests/units/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.test.d.ts.map +1 -0
  259. package/dist/tests/units/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.test.js +97 -0
  260. package/dist/tests/units/modules/claude-invocation/usecases/dispatchClaudeSession.usecase.test.js.map +1 -0
  261. package/dist/tests/units/modules/claude-invocation/usecases/retrieveReviewReport.usecase.test.d.ts +2 -0
  262. package/dist/tests/units/modules/claude-invocation/usecases/retrieveReviewReport.usecase.test.d.ts.map +1 -0
  263. package/dist/tests/units/modules/claude-invocation/usecases/retrieveReviewReport.usecase.test.js +49 -0
  264. package/dist/tests/units/modules/claude-invocation/usecases/retrieveReviewReport.usecase.test.js.map +1 -0
  265. package/dist/tests/units/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.test.d.ts +2 -0
  266. package/dist/tests/units/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.test.d.ts.map +1 -0
  267. package/dist/tests/units/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.test.js +171 -0
  268. package/dist/tests/units/modules/claude-invocation/usecases/runClaudeReviewJob.usecase.test.js.map +1 -0
  269. package/dist/tests/units/usecases/mcp/setPhase.usecase.test.js +21 -0
  270. package/dist/tests/units/usecases/mcp/setPhase.usecase.test.js.map +1 -1
  271. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.13.0](https://github.com/DGouron/review-flow/compare/reviewflow-v3.12.0...reviewflow-v3.13.0) (2026-05-22)
9
+
10
+
11
+ ### Added
12
+
13
+ * **claude-invocation:** implement spec-169 migrate claude -p to --bg mode ([#170](https://github.com/DGouron/review-flow/issues/170)) ([f3e408a](https://github.com/DGouron/review-flow/commit/f3e408af03056bb23017b29b62d811a25e62fb67))
14
+
8
15
  ## [3.12.0](https://github.com/DGouron/review-flow/compare/reviewflow-v3.11.0...reviewflow-v3.12.0) (2026-05-20)
9
16
 
10
17
 
@@ -11,6 +11,25 @@ import { ProjectConfigRoutingPolicyGateway } from '../../modules/review-executio
11
11
  import { TrackTokenUsageUseCase } from '../../modules/token-accounting/usecases/trackTokenUsage/trackTokenUsage.usecase.js';
12
12
  import { GetBudgetStatusUseCase } from '../../modules/token-accounting/usecases/getBudgetStatus/getBudgetStatus.usecase.js';
13
13
  import { BudgetStatusPresenter, type BudgetStatusViewModel } from '../../modules/token-accounting/interface-adapters/presenters/budgetStatus.presenter.js';
14
+ import type { ClaudeSessionGateway } from '../../modules/claude-invocation/entities/claudeSession/claudeSession.gateway.js';
15
+ import type { McpCompletionBridge } from '../../modules/claude-invocation/entities/sessionCompletion/mcpCompletion.gateway.js';
16
+ import type { ReviewReportGateway } from '../../modules/claude-invocation/entities/sessionCompletion/reviewReport.gateway.js';
17
+ import type { BillingStateGateway } from '../../modules/claude-invocation/entities/billingState/billingState.gateway.js';
18
+ import type { EnvironmentGateway } from '../../modules/claude-invocation/entities/billingState/environment.gateway.js';
19
+ /**
20
+ * Bundle of gateways needed by runClaudeReviewJob. Built in the composition
21
+ * root so the Fastify process, the supervisor/billing timers, and the MCP
22
+ * completion bridge can share the same instances.
23
+ */
24
+ export interface ClaudeInvocationDeps {
25
+ sessionGateway: ClaudeSessionGateway;
26
+ completionBridge: McpCompletionBridge;
27
+ reportGateway: ReviewReportGateway;
28
+ billingState: BillingStateGateway;
29
+ environment: EnvironmentGateway;
30
+ timeoutMs: number;
31
+ pollIntervalMs: number;
32
+ }
14
33
  /**
15
34
  * Gateways and use cases required by invokeClaudeReview. Extracted from the
16
35
  * function body so production wiring stays in the composition root and tests
@@ -26,6 +45,7 @@ export interface ClaudeInvokerDependencies {
26
45
  budgetStatusPresenter: BudgetStatusPresenter;
27
46
  broadcastBudgetStatus: (viewModel: BudgetStatusViewModel) => void;
28
47
  getEnabledLocalPaths?: () => string[];
48
+ invocation: ClaudeInvocationDeps;
29
49
  }
30
50
  /**
31
51
  * Default wiring used when invokeClaudeReview is called without explicit deps.
@@ -36,6 +56,15 @@ export interface ClaudeInvokerDependencies {
36
56
  * The no-op `broadcastBudgetStatus` here is intentional for tests and CLI
37
57
  * one-shots where there is no WebSocket fanout to perform.
38
58
  */
59
+ /**
60
+ * Build the environment for spawning a Claude child process.
61
+ *
62
+ * Strips CLAUDECODE so a Claude-launched ReviewFlow does not leak its parent
63
+ * session marker into the child, and forces TERM=dumb + CI=true to keep the
64
+ * child in non-interactive mode.
65
+ */
66
+ export declare function buildSpawnEnv(processEnv: NodeJS.ProcessEnv, override?: Record<string, string>): NodeJS.ProcessEnv;
67
+ export declare function createDefaultClaudeInvocationDeps(): ClaudeInvocationDeps;
39
68
  export declare function createDefaultClaudeInvokerDependencies(): ClaudeInvokerDependencies;
40
69
  export declare function resolveMcpServerPath(): string;
41
70
  export declare function writeMcpContext(job: ReviewJob): void;
@@ -1 +1 @@
1
- {"version":3,"file":"claudeInvoker.d.ts","sourceRoot":"","sources":["../../../src/frameworks/claude/claudeInvoker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claudeInvoker.d.ts","sourceRoot":"","sources":["../../../src/frameworks/claude/claudeInvoker.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,6 @@ import { spawn } from 'node:child_process';
2
2
  import { writeFileSync, mkdirSync, existsSync, unlinkSync } from 'node:fs';
3
3
  import { join, dirname } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { ProgressParser } from '../../frameworks/claude/progressParser.js';
6
5
  import { logInfo, logWarn, logError } from '../../frameworks/logging/logBuffer.js';
7
6
  import { getModel } from '../../frameworks/settings/runtimeSettings.js';
8
7
  import { getProjectAgents, getFollowupAgents, loadProjectConfig } from '../../config/projectConfig.js';
@@ -23,8 +22,12 @@ import { FilesystemTokenUsageGateway } from '../../modules/token-accounting/inte
23
22
  import { GetBudgetStatusUseCase } from '../../modules/token-accounting/usecases/getBudgetStatus/getBudgetStatus.usecase.js';
24
23
  import { FilesystemBudgetGateway } from '../../modules/token-accounting/interface-adapters/gateways/budget/budget.filesystem.gateway.js';
25
24
  import { BudgetStatusPresenter } from '../../modules/token-accounting/interface-adapters/presenters/budgetStatus.presenter.js';
26
- import { broadcastBudgetAfterUsage } from '../../frameworks/claude/broadcastBudgetAfterUsage.js';
27
- import { StreamJsonParser } from '../../frameworks/claude/streamJsonParser.js';
25
+ import { ClaudeSessionCliGateway, } from '../../modules/claude-invocation/interface-adapters/gateways/claudeSession.cli.gateway.js';
26
+ import { FileSystemMcpCompletionBridge } from '../../modules/claude-invocation/interface-adapters/gateways/mcpCompletion.fileSystem.gateway.js';
27
+ import { ReviewReportFileSystemGateway } from '../../modules/claude-invocation/interface-adapters/gateways/reviewReport.fileSystem.gateway.js';
28
+ import { InMemoryBillingStateGateway } from '../../modules/claude-invocation/interface-adapters/gateways/billingState.memory.gateway.js';
29
+ import { ProcessEnvironmentGateway } from '../../modules/claude-invocation/interface-adapters/gateways/environment.process.gateway.js';
30
+ import { runClaudeReviewJob } from '../../modules/claude-invocation/usecases/runClaudeReviewJob.usecase.js';
28
31
  /**
29
32
  * Default wiring used when invokeClaudeReview is called without explicit deps.
30
33
  *
@@ -34,6 +37,62 @@ import { StreamJsonParser } from '../../frameworks/claude/streamJsonParser.js';
34
37
  * The no-op `broadcastBudgetStatus` here is intentional for tests and CLI
35
38
  * one-shots where there is no WebSocket fanout to perform.
36
39
  */
40
+ /**
41
+ * Build the environment for spawning a Claude child process.
42
+ *
43
+ * Strips CLAUDECODE so a Claude-launched ReviewFlow does not leak its parent
44
+ * session marker into the child, and forces TERM=dumb + CI=true to keep the
45
+ * child in non-interactive mode.
46
+ */
47
+ export function buildSpawnEnv(processEnv, override) {
48
+ const { CLAUDECODE: _claudeCode, ...rest } = processEnv;
49
+ return {
50
+ ...rest,
51
+ TERM: 'dumb',
52
+ CI: 'true',
53
+ ...(override ?? {}),
54
+ };
55
+ }
56
+ /**
57
+ * Default process runner used by createDefaultClaudeInvocationDeps when the
58
+ * composition root does not provide one. Wraps node:child_process.spawn so
59
+ * tests can inject a fake runner instead.
60
+ */
61
+ function defaultProcessRunner() {
62
+ return async ({ args, cwd, env }) => new Promise((resolve, reject) => {
63
+ const child = spawn(resolveClaudePath(), args, {
64
+ cwd,
65
+ env: buildSpawnEnv(process.env, env),
66
+ stdio: ['ignore', 'pipe', 'pipe'],
67
+ });
68
+ let stdout = '';
69
+ let stderr = '';
70
+ child.stdout?.on('data', chunk => {
71
+ stdout += chunk.toString();
72
+ });
73
+ child.stderr?.on('data', chunk => {
74
+ stderr += chunk.toString();
75
+ });
76
+ child.on('error', reject);
77
+ child.on('close', code => {
78
+ resolve({ stdout, stderr, exitCode: code ?? -1 });
79
+ });
80
+ });
81
+ }
82
+ export function createDefaultClaudeInvocationDeps() {
83
+ return {
84
+ sessionGateway: new ClaudeSessionCliGateway(defaultProcessRunner()),
85
+ // FileSystem-backed because the MCP server runs in a sub-process spawned
86
+ // by `claude --bg`, so an in-memory bridge cannot reach the Fastify host.
87
+ // See FileSystemMcpCompletionBridge for the wire format.
88
+ completionBridge: new FileSystemMcpCompletionBridge(),
89
+ reportGateway: new ReviewReportFileSystemGateway(),
90
+ billingState: new InMemoryBillingStateGateway(),
91
+ environment: new ProcessEnvironmentGateway(),
92
+ timeoutMs: 15 * 60 * 1000,
93
+ pollIntervalMs: 30 * 1000,
94
+ };
95
+ }
37
96
  export function createDefaultClaudeInvokerDependencies() {
38
97
  const tokenUsageGateway = new FilesystemTokenUsageGateway();
39
98
  const budgetGateway = new FilesystemBudgetGateway();
@@ -48,6 +107,7 @@ export function createDefaultClaudeInvokerDependencies() {
48
107
  getBudgetStatus: new GetBudgetStatusUseCase({ budgetGateway, tokenUsageGateway }),
49
108
  budgetStatusPresenter: new BudgetStatusPresenter(),
50
109
  broadcastBudgetStatus: () => { },
110
+ invocation: createDefaultClaudeInvocationDeps(),
51
111
  };
52
112
  }
53
113
  const currentDir = dirname(fileURLToPath(import.meta.url));
@@ -116,10 +176,6 @@ export function cleanupMcpContext(jobId) {
116
176
  // Ignore cleanup errors
117
177
  }
118
178
  }
119
- // Memory guard configuration
120
- const MEMORY_LIMIT_GB = 4; // Kill process if RSS exceeds 4GB
121
- const MEMORY_CHECK_INTERVAL_MS = 5000; // Check every 5 seconds
122
- const MEMORY_LIMIT_BYTES = MEMORY_LIMIT_GB * 1024 * 1024 * 1024;
123
179
  function fetchDiffStatsSafely(job, deps, logger) {
124
180
  try {
125
181
  const gateway = deps.diffStatsFetchFactory(job.platform);
@@ -281,13 +337,11 @@ export async function invokeClaudeReview(job, logger, onProgress, signal, deps =
281
337
  // Build MCP config: isolated from project .mcp.json to avoid
282
338
  // third-party MCP servers (e.g. gitnexus) causing initialization timeouts
283
339
  const mcpConfigJson = buildMcpConfigJson();
284
- // Build arguments
285
- // --permission-mode bypassPermissions: automated review, no user to approve
286
- // --allowedTools / --disallowedTools: belt-and-suspenders to restrict tool scope
287
- // --mcp-config + --strict-mcp-config: use ONLY review-progress MCP server
340
+ // Build arguments for the --bg (background subscription billing) invocation.
341
+ // The session id is captured from stdout; completion is observed through MCP
342
+ // (set_phase) or `claude agents --json` polling. No -p, no --print, no stream-json.
288
343
  const args = [
289
- '--output-format', 'stream-json',
290
- '--verbose',
344
+ '--bg',
291
345
  '--model', model,
292
346
  '--permission-mode', 'bypassPermissions',
293
347
  '--append-system-prompt', mcpSystemPrompt,
@@ -295,7 +349,7 @@ export async function invokeClaudeReview(job, logger, onProgress, signal, deps =
295
349
  '--strict-mcp-config',
296
350
  '--allowedTools', 'Read,Glob,Grep,Bash,Edit,Task,Skill,Write,LSP,mcp__review-progress__*',
297
351
  '--disallowedTools', 'EnterPlanMode,AskUserQuestion',
298
- '-p', prompt,
352
+ prompt,
299
353
  ];
300
354
  // Setup MCP job context file (used by MCP server to identify the review)
301
355
  writeMcpContext(job);
@@ -319,13 +373,6 @@ export async function invokeClaudeReview(job, logger, onProgress, signal, deps =
319
373
  jobType: job.jobType || 'review',
320
374
  customAgents: projectAgents?.length ?? 'default',
321
375
  });
322
- // Initialize progress parser with project agents (or defaults)
323
- const progressParser = new ProgressParser(job.id, (event, progress) => {
324
- logger.debug({ event, progress: progress.overallProgress }, 'Progress update');
325
- onProgress?.(progress, event);
326
- }, projectAgents);
327
- // Emit initial progress
328
- onProgress?.(progressParser.getProgress());
329
376
  // Check if already cancelled
330
377
  if (signal?.aborted) {
331
378
  logWarn('Review annulée avant démarrage', { jobId: job.id });
@@ -335,265 +382,151 @@ export async function invokeClaudeReview(job, logger, onProgress, signal, deps =
335
382
  stdout: '',
336
383
  stderr: 'Review cancelled before start',
337
384
  durationMs: Date.now() - startTime,
338
- finalProgress: progressParser.getProgress(),
339
385
  cancelled: true,
340
386
  };
341
387
  }
342
- return new Promise((resolve) => {
343
- let stdout = '';
344
- let stderr = '';
345
- let cancelled = false;
346
- const streamParser = new StreamJsonParser();
347
- const childEnv = { ...process.env };
348
- // Remove CLAUDECODE to allow spawning Claude from within a Claude session
349
- childEnv.CLAUDECODE = undefined;
350
- const child = spawn(resolveClaudePath(), args, {
351
- cwd: job.localPath,
352
- env: {
353
- ...childEnv,
354
- // Ensure non-interactive mode
355
- TERM: 'dumb',
356
- CI: 'true',
357
- // Note: MCP env vars are now passed via --mcp-config
358
- },
359
- stdio: ['ignore', 'pipe', 'pipe'],
388
+ return invokeViaBackgroundSession({
389
+ job,
390
+ prompt,
391
+ model,
392
+ mcpSystemPrompt,
393
+ mcpConfigJson,
394
+ diffStats,
395
+ startTime,
396
+ signal,
397
+ }, logger, onProgress, deps);
398
+ }
399
+ async function invokeViaBackgroundSession(context, logger, onProgress, deps) {
400
+ const { job, prompt, model, mcpSystemPrompt, mcpConfigJson, diffStats, startTime, signal } = context;
401
+ const invocation = deps.invocation;
402
+ const mergeRequestId = `${job.platform}-${job.projectPath}-${job.mrNumber}`;
403
+ const jobType = job.jobType === 'followup' ? 'followup' : 'review';
404
+ // attempt counter is reserved for the queue layer to re-enqueue with backoff
405
+ // when status === 'retry' is returned. Until that wiring exists, every
406
+ // invocation is treated as attempt 0 and a single retry signal surfaces back
407
+ // to the controller as a soft failure.
408
+ const attempt = 0;
409
+ const flags = {
410
+ model,
411
+ mcpConfigJson,
412
+ systemPrompt: mcpSystemPrompt,
413
+ allowedTools: 'Read,Glob,Grep,Bash,Edit,Task,Skill,Write,LSP,mcp__review-progress__*',
414
+ disallowedTools: 'EnterPlanMode,AskUserQuestion',
415
+ permissionMode: 'bypassPermissions',
416
+ };
417
+ let result;
418
+ try {
419
+ result = await runClaudeReviewJob({
420
+ jobId: job.id,
421
+ jobType,
422
+ prompt,
423
+ flags,
424
+ localPath: job.localPath,
425
+ mergeRequestId,
426
+ mergeRequestNumber: job.mrNumber,
427
+ attempt,
428
+ signal,
429
+ }, {
430
+ sessionGateway: invocation.sessionGateway,
431
+ completionBridge: invocation.completionBridge,
432
+ reportGateway: invocation.reportGateway,
433
+ billingState: invocation.billingState,
434
+ environment: invocation.environment,
435
+ now: () => new Date(),
436
+ timeoutMs: invocation.timeoutMs,
437
+ pollIntervalMs: invocation.pollIntervalMs,
360
438
  });
361
- // Memory guard: monitor RSS and kill if exceeds limit
362
- let memoryExceeded = false;
363
- const memoryCheckInterval = setInterval(() => {
364
- const memUsage = process.memoryUsage();
365
- const rssMB = Math.round(memUsage.rss / 1024 / 1024);
366
- if (memUsage.rss > MEMORY_LIMIT_BYTES) {
367
- memoryExceeded = true;
368
- const errorMessage = `
369
- ╔═══════════════════════════════════════════════════════════════════╗
370
- ║ 🚨 MEMORY LIMIT EXCEEDED - REVIEW KILLED ║
371
- ╠═══════════════════════════════════════════════════════════════════╣
372
- ║ ║
373
- ║ Current RSS: ${rssMB} MB (limit: ${MEMORY_LIMIT_GB * 1024} MB) ║
374
- ║ Job: ${job.id.substring(0, 50).padEnd(50)} ║
375
- ║ ║
376
- ║ The review process consumed too much memory. ║
377
- ║ This usually happens when running too many sub-agents ║
378
- ║ in parallel. Consider using sequential execution. ║
379
- ║ ║
380
- ╚═══════════════════════════════════════════════════════════════════╝
381
- `;
382
- logger.error({ rssMB, limitMB: MEMORY_LIMIT_GB * 1024, jobId: job.id }, 'Memory limit exceeded, killing process');
383
- logError('Memory limit exceeded', {
384
- jobId: job.id,
385
- rssMB,
386
- limitMB: MEMORY_LIMIT_GB * 1024,
387
- message: 'Review killed due to excessive memory consumption',
388
- });
389
- // Output error to stderr for visibility
390
- stderr += errorMessage;
391
- // Kill the child process
392
- child.kill('SIGKILL');
393
- clearInterval(memoryCheckInterval);
394
- }
395
- else if (rssMB > (MEMORY_LIMIT_GB * 1024 * 0.8)) {
396
- // Warn when approaching limit (80%)
397
- logger.warn({ rssMB, limitMB: MEMORY_LIMIT_GB * 1024 }, 'Memory usage high, approaching limit');
398
- }
399
- }, MEMORY_CHECK_INTERVAL_MS);
400
- // Handle cancellation via AbortSignal
401
- const abortHandler = () => {
402
- if (!cancelled) {
403
- cancelled = true;
404
- logger.info({ jobId: job.id }, 'Review annulée par utilisateur');
405
- logWarn('Review annulée', { jobId: job.id });
406
- child.kill('SIGTERM');
407
- // Give it time to cleanup, then force kill
408
- setTimeout(() => {
409
- if (!child.killed) {
410
- child.kill('SIGKILL');
411
- }
412
- }, 5000);
413
- }
439
+ }
440
+ catch (error) {
441
+ cleanupMcpContext(job.id);
442
+ const message = error instanceof Error ? error.message : String(error);
443
+ logger.error({ error: message, jobId: job.id }, 'runClaudeReviewJob threw');
444
+ logError('Review en erreur', { jobId: job.id, message });
445
+ return {
446
+ success: false,
447
+ exitCode: null,
448
+ stdout: '',
449
+ stderr: message,
450
+ durationMs: Date.now() - startTime,
451
+ selectedModel: model,
414
452
  };
415
- if (signal) {
416
- signal.addEventListener('abort', abortHandler, { once: true });
417
- }
418
- child.stdout.on('data', (data) => {
419
- const chunk = data.toString();
420
- stdout += chunk;
421
- streamParser.feed(chunk);
422
- // Progress markers may still appear in assistant text within stream-json events;
423
- // feeding the raw chunk keeps any legacy markers detected without coupling to JSON shape.
424
- progressParser.parseChunk(chunk);
425
- const preview = chunk.length > 200 ? chunk.substring(0, 200) + '...' : chunk;
426
- logger.debug({ preview }, 'Claude stdout');
427
- });
428
- child.stderr.on('data', (data) => {
429
- const chunk = data.toString();
430
- stderr += chunk;
431
- logger.warn({ chunk }, 'Claude stderr');
432
- logWarn('Claude stderr', { jobId: job.id, message: chunk.substring(0, 500) });
433
- });
434
- child.on('error', (error) => {
435
- logger.error({ error }, 'Erreur lors du spawn de Claude');
436
- logError('Erreur spawn Claude', { jobId: job.id, error: error.message });
437
- progressParser.markFailed(error.message);
438
- resolve({
439
- success: false,
440
- exitCode: null,
441
- stdout,
442
- stderr: stderr + `\nSpawn error: ${error.message}`,
443
- durationMs: Date.now() - startTime,
444
- finalProgress: progressParser.getProgress(),
445
- });
453
+ }
454
+ cleanupMcpContext(job.id);
455
+ const durationMs = Date.now() - startTime;
456
+ const durationMin = Math.round(durationMs / 60000);
457
+ if (result.status === 'completed') {
458
+ logInfo('Review terminée', {
459
+ jobId: job.id,
460
+ mrNumber: job.mrNumber,
461
+ duration: `${durationMin} min`,
462
+ outputLength: result.content.length,
463
+ model,
446
464
  });
447
- child.on('close', async (code) => {
448
- // Cleanup interval, abort listener, and MCP context
449
- clearInterval(memoryCheckInterval);
450
- cleanupMcpContext(job.id);
451
- if (signal) {
452
- signal.removeEventListener('abort', abortHandler);
453
- }
454
- const durationMs = Date.now() - startTime;
455
- const success = code === 0 && !cancelled && !memoryExceeded;
456
- const assistantText = streamParser.getAssistantText();
457
- const tokenUsage = streamParser.getUsage();
458
- // Save logs: raw stream-json + reconstructed human text for readability
465
+ // Save review statistics (followups are not counted as reviews)
466
+ if (job.jobType !== 'followup') {
459
467
  try {
460
- const logsDir = join(job.localPath, '.claude', 'reviews', 'logs');
461
- if (!existsSync(logsDir)) {
462
- mkdirSync(logsDir, { recursive: true });
463
- }
464
- const sanitizedJobId = job.id.replace(/[:/\\]/g, '-');
465
- const logPath = join(logsDir, `${sanitizedJobId}-stdout.log`);
466
- writeFileSync(logPath, `=== Claude Review Output ===\nJob: ${job.id}\nMR: ${job.mrNumber}\nSkill: ${job.skill}\nModel: ${model}\nExit code: ${code}\nDuration: ${Math.round(durationMs / 1000)}s\nTimestamp: ${new Date().toISOString()}\n\n--- ASSISTANT TEXT ---\n${assistantText}\n\n--- STDERR ---\n${stderr}\n\n--- RAW STREAM-JSON ---\n${stdout}\n`);
467
- logger.info({ logPath }, 'Review stdout saved to log file');
468
- }
469
- catch {
470
- // Non-critical
471
- }
472
- // Finalize progress
473
- if (memoryExceeded) {
474
- progressParser.markFailed('Memory limit exceeded - review killed');
475
- }
476
- else if (cancelled) {
477
- progressParser.markFailed('Annulée par utilisateur');
478
- }
479
- else if (success) {
480
- progressParser.markAllCompleted();
468
+ const mrId = `${job.platform}-${job.projectPath}-${job.mrNumber}`;
469
+ const mrDetails = deps.trackingGateway.getById(job.localPath, mrId);
470
+ const assignedBy = mrDetails?.assignment?.username;
471
+ const reviewStats = addReviewStats(job.localPath, job.mrNumber, durationMs, result.content, assignedBy, diffStats);
472
+ logger.info({ reviewStats }, 'Stats de review enregistrées');
481
473
  }
482
- else {
483
- progressParser.markFailed(`Exit code: ${code}`);
474
+ catch (statsError) {
475
+ logger.warn({ error: statsError }, 'Erreur lors de l\'enregistrement des stats');
484
476
  }
485
- const finalProgress = progressParser.getProgress();
486
- onProgress?.(finalProgress);
487
- logger.info({
488
- exitCode: code,
489
- durationMs,
490
- stdoutLength: stdout.length,
491
- stderrLength: stderr.length,
492
- finalProgress: finalProgress.overallProgress,
493
- cancelled,
494
- memoryExceeded,
495
- }, memoryExceeded
496
- ? 'Claude killed - memory limit exceeded'
497
- : cancelled
498
- ? 'Claude annulé'
499
- : success
500
- ? 'Claude terminé avec succès'
501
- : 'Claude terminé avec erreur');
502
- // Log to dashboard with summary
503
- const durationMin = Math.round(durationMs / 60000);
504
- if (memoryExceeded) {
505
- logError('Review killed - Memory limit exceeded', {
506
- jobId: job.id,
507
- mrNumber: job.mrNumber,
508
- duration: `${durationMin} min`,
509
- limitGB: MEMORY_LIMIT_GB,
510
- });
511
- }
512
- else if (cancelled) {
513
- logWarn('Review annulée', {
514
- jobId: job.id,
515
- mrNumber: job.mrNumber,
516
- duration: `${durationMin} min`,
517
- });
518
- }
519
- else if (success) {
520
- logInfo('Review terminée', {
521
- jobId: job.id,
522
- mrNumber: job.mrNumber,
523
- duration: `${durationMin} min`,
524
- outputLength: assistantText.length,
525
- model,
526
- });
527
- // Save review statistics (followups are not counted as reviews)
528
- if (job.jobType !== 'followup') {
529
- try {
530
- const mrId = `${job.platform}-${job.projectPath}-${job.mrNumber}`;
531
- const mrDetails = deps.trackingGateway.getById(job.localPath, mrId);
532
- const assignedBy = mrDetails?.assignment?.username;
533
- const reviewStats = addReviewStats(job.localPath, job.mrNumber, durationMs, assistantText, assignedBy, diffStats);
534
- logger.info({ reviewStats }, 'Stats de review enregistrées');
535
- }
536
- catch (statsError) {
537
- logger.warn({ error: statsError }, 'Erreur lors de l\'enregistrement des stats');
538
- }
539
- }
540
- // Persist token usage for cost tracking (non-critical, never blocks the review result)
541
- if (tokenUsage) {
542
- try {
543
- await deps.trackTokenUsage.execute({
544
- jobId: job.id,
545
- mrNumber: job.mrNumber,
546
- platform: job.platform,
547
- projectPath: job.projectPath,
548
- localPath: job.localPath,
549
- model,
550
- recordedAt: new Date().toISOString(),
551
- usage: tokenUsage,
552
- });
553
- logger.info({ jobId: job.id, model, usage: tokenUsage }, 'Token usage recorded');
554
- const broadcastLocalPaths = deps.getEnabledLocalPaths?.() ?? [job.localPath];
555
- await broadcastBudgetAfterUsage({
556
- getBudgetStatus: deps.getBudgetStatus,
557
- broadcastBudgetStatus: deps.broadcastBudgetStatus,
558
- presenter: deps.budgetStatusPresenter,
559
- }, { localPaths: broadcastLocalPaths }, logger);
560
- }
561
- catch (trackError) {
562
- logger.warn({ jobId: job.id, error: trackError }, 'Failed to persist token usage');
563
- }
564
- }
565
- // Log assistant text preview for debugging
566
- if (assistantText.length > 0) {
567
- logInfo('Claude output preview', {
568
- jobId: job.id,
569
- preview: assistantText.substring(0, 1000),
570
- fullLength: assistantText.length,
571
- });
572
- }
573
- }
574
- else {
575
- logError('Review échouée', {
576
- jobId: job.id,
577
- mrNumber: job.mrNumber,
578
- exitCode: code,
579
- duration: `${durationMin} min`,
580
- stderr: stderr.substring(0, 500),
581
- stdoutPreview: (assistantText || stdout).substring(0, 300),
582
- });
583
- }
584
- resolve({
585
- success,
586
- exitCode: memoryExceeded ? null : code,
587
- stdout: assistantText,
588
- stderr,
589
- durationMs,
590
- finalProgress,
591
- cancelled: cancelled || memoryExceeded,
592
- usage: tokenUsage,
593
- selectedModel: model,
477
+ }
478
+ // Token usage tracking is disabled in --bg mode: the legacy stream-json
479
+ // path is gone and `claude --bg` does not emit usage to stdout. Re-enabling
480
+ // requires parsing `claude logs <sessionId>` — tracked in SPEC-171
481
+ // (docs/specs/171-bg-token-usage-tracking.md). Until SPEC-171 ships, the
482
+ // budget dashboard reports zero spending for --bg reviews.
483
+ if (onProgress) {
484
+ onProgress({
485
+ currentPhase: 'completed',
486
+ overallProgress: 100,
487
+ lastUpdate: new Date(),
488
+ agents: [],
594
489
  });
490
+ }
491
+ return {
492
+ success: true,
493
+ exitCode: 0,
494
+ stdout: result.content,
495
+ stderr: '',
496
+ durationMs,
497
+ usage: null,
498
+ selectedModel: model,
499
+ };
500
+ }
501
+ if (result.status === 'retry') {
502
+ logWarn('Rate-limited — backoff demandé', {
503
+ jobId: job.id,
504
+ delayMs: result.delayMs,
505
+ nextAttempt: result.attempt,
595
506
  });
507
+ return {
508
+ success: false,
509
+ exitCode: 1,
510
+ stdout: '',
511
+ stderr: `rate-limited; retry in ${result.delayMs}ms (attempt ${result.attempt})`,
512
+ durationMs,
513
+ selectedModel: model,
514
+ };
515
+ }
516
+ logError('Review échouée', {
517
+ jobId: job.id,
518
+ mrNumber: job.mrNumber,
519
+ duration: `${durationMin} min`,
520
+ reason: result.reason,
596
521
  });
522
+ return {
523
+ success: false,
524
+ exitCode: 1,
525
+ stdout: '',
526
+ stderr: result.reason,
527
+ durationMs,
528
+ selectedModel: model,
529
+ };
597
530
  }
598
531
  /**
599
532
  * Send desktop notification