@overdeck/desktop 0.45.6 → 0.45.8

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 (304) hide show
  1. package/drizzle/overdeck/0000_overdeck_init.sql +483 -0
  2. package/package.json +16 -4
  3. package/server/{acceptance-criteria-DYffaKI9.js → acceptance-criteria-l0DSvFFS.js} +2 -2
  4. package/server/{activity-logger-DO27GsPa.js → activity-logger-DvYvFhwZ.js} +1 -1
  5. package/server/{activity-logger-Dm95Ua07.js → activity-logger-pcbf-e30.js} +3 -2
  6. package/server/{advancing-selfheal-n8tAeFwE.js → advancing-selfheal-CMlGznKv.js} +11 -66
  7. package/server/{agent-gc-CIFaa2vJ.js → agent-gc-BtAzj8QN.js} +3 -3
  8. package/server/{agent-state-service-BqVDA9b8.js → agent-state-service-5ge9xxhx.js} +5 -5
  9. package/server/{agent-state-service-CLifyinO.js → agent-state-service-C1iUF9Ft.js} +1 -1
  10. package/server/agent-state-xk_G8t90.js +3 -0
  11. package/server/{agents-KaEsWZ8D.js → agents-BIggLvi_.js} +1 -1
  12. package/server/{agents-D_x5BSZM.js → agents-DHvsjsuP.js} +129 -61
  13. package/server/{archive-planning-CFxmeFKh.js → archive-planning-B4Qi02bk.js} +1 -1
  14. package/server/{archive-planning-DVUXlRBs.js → archive-planning-zTvWWHG_.js} +4 -4
  15. package/server/{artifact-index-jobs-ChUgzZah.js → artifact-index-jobs-BrByqVkB.js} +2 -2
  16. package/server/{auto-commit-2KiBFh-K.js → auto-commit-DoIPFoEs.js} +1 -1
  17. package/server/{backlog-auto-trigger-DoTEMZMl.js → backlog-auto-trigger-COm_R96V.js} +3 -3
  18. package/server/{bd-mutex-CE6P_MlD.js → bd-mutex-BItGvLQ8.js} +2 -2
  19. package/server/{bd-process-lock-Ch3WNHS9.js → bd-process-lock-CJkoG7hW.js} +2 -2
  20. package/server/{beads-B43pgBIy.js → beads-AmCXEv_E.js} +1 -1
  21. package/server/{beads-BugPvtWp.js → beads-DlZm-vrG.js} +5 -5
  22. package/server/{beads-query-CtqWakL6.js → beads-query-BrVNWoSL.js} +2 -2
  23. package/server/{beads-restore-BqTMSQi-.js → beads-restore-CMbDSB5R.js} +1 -1
  24. package/server/{behavior-vk1sixby.js → behavior-By-2Wipv.js} +3 -3
  25. package/server/{briefing-freshness-B3YxHQ-L.js → briefing-freshness-CXhZdnB8.js} +4 -4
  26. package/server/{checkpoint-manager-CdrwLsQh.js → checkpoint-manager-CPw51H2n.js} +1 -1
  27. package/server/{checkpoint-manager-Dg6cWZz3.js → checkpoint-manager-CfNpHOp4.js} +11 -2
  28. package/server/checkpoint-worker.js +1 -1
  29. package/server/{checkpoints-DDd-0doa.js → checkpoints-BbfH1EIy.js} +2 -2
  30. package/server/{checkpoints-dBCJr0dC.js → checkpoints-BjlBWOA8.js} +1 -1
  31. package/server/{claude-permissions-BpwIcIR7.js → claude-permissions-DrRAs_0F.js} +3 -3
  32. package/server/{claude-settings-overlay-DnraWcz6.js → claude-settings-overlay-BSeS7Ki3.js} +2 -2
  33. package/server/{claude-settings-overlay-xD_Vu420.js → claude-settings-overlay-CEWlIFL-.js} +1 -1
  34. package/server/cli-CJDWXE_Y.js +3 -0
  35. package/server/{cli-BmzYZZKi.js → cli-CvK9xuSS.js} +9 -9
  36. package/server/{cliproxy-DYWdJKZ1.js → cliproxy-BOcmOK6l.js} +1 -1
  37. package/server/{cliproxy-CE2GDY7x.js → cliproxy-J-_1iIXe.js} +2 -2
  38. package/server/{close-issue-CpJd4SOL.js → close-issue-BnpErnD1.js} +5 -5
  39. package/server/{closed-issue-reaper-QpcvCDeE.js → closed-issue-reaper-BLCQwTpF.js} +1 -1
  40. package/server/{closed-issue-reaper-DubXY9Zg.js → closed-issue-reaper-DRqK5k39.js} +10 -10
  41. package/server/{codex-j8aVgRou.js → codex-BUZjrnqH.js} +1 -1
  42. package/server/{codex-B3J1TXo7.js → codex-DcInrhok.js} +5 -5
  43. package/server/{compact-beads-CqhLqG-k.js → compact-beads-RFwdZFPA.js} +4 -4
  44. package/server/{compact-beads-BeilHCdj.js → compact-beads-omhUgj5b.js} +1 -1
  45. package/server/{config-DHU0j_pS.js → config-CzcWQ24p.js} +1 -1
  46. package/server/{config-DkEhJM0h.js → config-oWoKf5jO.js} +4 -4
  47. package/server/{config-yaml-DbdN9Fuq.js → config-yaml-DPAieL_G.js} +3 -2
  48. package/server/{conflict-gate-CgOtMo8i.js → conflict-gate-BhKvrPxn.js} +4 -4
  49. package/server/{conflict-gate-D00zFjeu.js → conflict-gate-JdFuhKuF.js} +1 -1
  50. package/server/{context-layers-BHEjT8Cn.js → context-layers-CTjQwcEQ.js} +3 -3
  51. package/server/{context-layers-0Lgq-SE_.js → context-layers-DxKsseHI.js} +2 -2
  52. package/server/{control-settings-CYv732Gs.js → control-settings-BMqUkXmR.js} +4 -4
  53. package/server/{conversation-compaction-Dbw03b-X.js → conversation-compaction-Ba5aZdrb.js} +1 -1
  54. package/server/{conversation-compaction-DKXvmX50.js → conversation-compaction-C5o_eKEm.js} +8 -8
  55. package/server/{conversation-service-BwKUeEvn.js → conversation-service-DvG8vZSV.js} +5 -5
  56. package/server/{conversation-service-kYYeRp9B.js → conversation-service-WKl-sw58.js} +1 -1
  57. package/server/{conversations-Dwr1jHrO.js → conversations-DL_BAWVk.js} +4 -4
  58. package/server/{conversations-D-uOnA8T.js → conversations-Dcx6LeIh.js} +1 -1
  59. package/server/{cost-DiSDkYe7.js → cost-C2CuA66z.js} +2 -2
  60. package/server/{cost-DNIyZH1X.js → cost-DaOG8sUB.js} +3 -3
  61. package/server/{cost-sync-CfXu-3TF.js → cost-sync-8lkDeL9g.js} +3 -3
  62. package/server/{dag-DZBowTd2.js → dag-jH8ZkewR.js} +3 -3
  63. package/server/{dangerous-git-ops-Pongxg2d.js → dangerous-git-ops-Dcw7PbYo.js} +1 -1
  64. package/server/dashboard-db-worker.js +6 -6
  65. package/server/{deacon-DT0BsVyE.js → deacon-Cv2RMfHs.js} +3 -3
  66. package/server/{deacon-f0yvsG5S.js → deacon-j3qSZ7--.js} +222 -110
  67. package/server/{deacon-nudge-log-Cmcch2Av.js → deacon-nudge-log-CJGA6aSQ.js} +1 -1
  68. package/server/deacon-swarm-D1iAUX-P.js +2 -0
  69. package/server/{deacon-swarm-BBGnhvD2.js → deacon-swarm-DadWNi5J.js} +88 -43
  70. package/server/deacon.js +8 -8
  71. package/server/{devcontainer-renderer-Cpz7XBj0.js → devcontainer-renderer-DUJYYRQB.js} +3 -3
  72. package/server/{dist-DypOkJv9.js → dist-BIC8spJ0.js} +1 -1
  73. package/server/dist-BUplB3Od.js +3 -0
  74. package/server/{docker-DARVx0OZ.js → docker-Q4bphryk.js} +2 -2
  75. package/server/{ensure-devcontainer-Dmdw4BxF.js → ensure-devcontainer-BCB6fHp9.js} +1 -1
  76. package/server/{ensure-devcontainer-BJssuBG6.js → ensure-devcontainer-XLL0vtgV.js} +4 -4
  77. package/server/{esm-shims-Crmvo9Ln.js → esm-shims-DiV9jHa_.js} +1 -1
  78. package/server/{event-store-BeEE8pW5.js → event-store-DIk9wvnS.js} +1 -1
  79. package/server/{event-store-DrfTJZ1_.js → event-store-DTJXZjCl.js} +4 -4
  80. package/server/events-BlzVUyTx.js +3 -0
  81. package/server/{events-BbClwoM-.js → events-DGWZzye2.js} +4 -4
  82. package/server/{factory-DVv9cpG5.js → factory-rG4T40su.js} +4 -4
  83. package/server/{feature-registry-population-C6eVdq4J.js → feature-registry-population-Dwyj9gEM.js} +4 -4
  84. package/server/{feature-registry-storage-ByBosRId.js → feature-registry-storage-CnGyNgAq.js} +2 -2
  85. package/server/{features-EZfSwuqq.js → features-CYY2_Eeh.js} +2 -2
  86. package/server/{feedback-target-DENaINE6.js → feedback-target-C4DaDSZ8.js} +1 -1
  87. package/server/{feedback-target-Dv4VnbQl.js → feedback-target-oE4-Esxl.js} +48 -17
  88. package/server/{feedback-writer-Dxg8qM8i.js → feedback-writer-DMaO0XXa.js} +4 -4
  89. package/server/{feedback-writer-BvHE1I-3.js → feedback-writer-thrdxYpK.js} +1 -1
  90. package/server/{flywheel-Akbd9VNM.js → flywheel-BqDdGvrQ.js} +1 -1
  91. package/server/{flywheel-B4KN9BmW.js → flywheel-ClMjGW_u.js} +11 -11
  92. package/server/{flywheel-ByZyAv3P.js → flywheel-DefHRzY4.js} +13 -13
  93. package/server/{flywheel-merge-order-DPFZbt-w.js → flywheel-merge-order-B6YDSElh.js} +1 -1
  94. package/server/{flywheel-merge-order-BYUPxqgx.js → flywheel-merge-order-CuDcqTRJ.js} +7 -7
  95. package/server/forge-BfP7OJwK.js +2 -0
  96. package/server/{forge-BnTExkbK.js → forge-BixzckB0.js} +2 -2
  97. package/server/{from-B2i_NgIH.js → from-D4xmArTA.js} +1 -1
  98. package/server/{fts-db-dnCj-PD3.js → fts-db-DPtxOAjp.js} +2 -2
  99. package/server/{fts-operations-CAAofsTQ.js → fts-operations-VrGjsT0w.js} +2 -2
  100. package/server/{git-utils-CB3gDSM-.js → git-utils-D_cax3fD.js} +2 -2
  101. package/server/{git-utils-Bk7sJZru.js → git-utils-RAmTwjFB.js} +1 -1
  102. package/server/{github-app-CIhMNI4C.js → github-app-B5PDHMyn.js} +1 -1
  103. package/server/{github-app-BIU8a93o.js → github-app-FMXgo3vK.js} +2 -2
  104. package/server/{github-client-DmZgsnYP.js → github-client-VRiB6N-4.js} +1 -1
  105. package/server/{github-client-zREpj5HA.js → github-client-yjbXaqpR.js} +2 -2
  106. package/server/{github-pr-lookup-CPri6JR1.js → github-pr-lookup-t8X8R0c0.js} +2 -2
  107. package/server/{harness-resolve-TzYAiXzZ.js → harness-resolve-DKeSVsJL.js} +3 -3
  108. package/server/{health-events-CDWk8Oz4.js → health-events-CD6q47ub.js} +1 -1
  109. package/server/{health-events-Dd0FuKrE.js → health-events-DaLX4-0a.js} +2 -2
  110. package/server/{hooks-C6HBXlVm.js → hooks-CmHFSj_Z.js} +2 -2
  111. package/server/{hooks-DRLzoFof.js → hooks-D-cbMUzQ.js} +1 -1
  112. package/server/{hume-Bb91r_2I.js → hume-DkVOs1Qi.js} +2 -2
  113. package/server/hume-x9voULey.js +3 -0
  114. package/server/{idle-stack-reaper-BPHnItVj.js → idle-stack-reaper-DBKQ9SKu.js} +3 -3
  115. package/server/{idle-stack-reaper-D5bwmuwX.js → idle-stack-reaper-DdnERp3G.js} +1 -1
  116. package/server/{infra-CCTzpcuJ.js → infra-CpKlYZA9.js} +3 -3
  117. package/server/{injection-D6L7D_w0.js → injection-CszhePD2.js} +7 -7
  118. package/server/{injection-CBrN8UxB.js → injection-DKzL2Axk.js} +1 -1
  119. package/server/{inspect-agent-CSYyFWqP.js → inspect-agent-BKKc0XnB.js} +9 -9
  120. package/server/inspect-agent-vm88mLYr.js +2 -0
  121. package/server/{internal-token-DWhBqgIk.js → internal-token-CQUx9YLc.js} +2 -2
  122. package/server/{internal-token-DCrCAG_M.js → internal-token-DrGdpLFo.js} +1 -1
  123. package/server/{io-DtAQ_2hp.js → io-Wy8YpFeP.js} +2 -2
  124. package/server/{issue-closed-0Zx72zXf.js → issue-closed-BO84g03t.js} +4 -4
  125. package/server/{issue-lifecycle-ZTt6kP_K.js → issue-lifecycle-DnhQgddB.js} +22 -22
  126. package/server/{issue-lifecycle-CJ7-D4XX.js → issue-lifecycle-nY4esZn8.js} +1 -1
  127. package/server/{issue-service-singleton-DNh4RRI7.js → issue-service-singleton-Bnqv1uaa.js} +1 -1
  128. package/server/{issue-service-singleton-DRE7S-Zg.js → issue-service-singleton-_AquSBTl.js} +8 -8
  129. package/server/{issues-CGc8Aaxm.js → issues-ChNcfHta.js} +2 -2
  130. package/server/{label-cleanup-CNsPlXy6.js → label-cleanup-bVXCGWBM.js} +3 -3
  131. package/server/{layers-CO_VLcSv.js → layers-vdvlpFki.js} +2 -2
  132. package/server/{lifecycle-B_NFvTj9.js → lifecycle-CGKm7doE.js} +7 -7
  133. package/server/{lifecycle-io-D0FftBLy.js → lifecycle-io-CdqPkCyk.js} +1 -1
  134. package/server/{lifecycle-io-WDGwa1vV.js → lifecycle-io-DSrv9xGh.js} +4 -4
  135. package/server/{linear-client-MvjflCXs.js → linear-client-BxKvL6U8.js} +1 -1
  136. package/server/{linear-client-CSgH24Ym.js → linear-client-E0HdXtWs.js} +2 -2
  137. package/server/memory-fts-worker.js +1 -1
  138. package/server/{merge-DltB-RGV.js → merge-D3wEbmUJ.js} +1 -1
  139. package/server/{merge-Ce9DHBXM.js → merge-UlAwCk80.js} +4 -4
  140. package/server/{merge-agent-Rv0bNQNU.js → merge-agent-BcgAYStl.js} +27 -27
  141. package/server/{merge-agent-DRXwKxmb.js → merge-agent-Dh8Y9PDO.js} +1 -1
  142. package/server/{merge-batch-LLp_cXUR.js → merge-batch-BwhGdlh4.js} +1 -1
  143. package/server/{merge-blockers-BqYUtLBd.js → merge-blockers-DwdQNsYD.js} +2 -2
  144. package/server/merge-ops-QdBiQ8XB.js +2 -0
  145. package/server/{merge-rebase-AiSEs4QB.js → merge-rebase-CH12_ufi.js} +2 -2
  146. package/server/{merge-set-CUY9msG9.js → merge-set-TRxJwR-w.js} +3 -3
  147. package/server/{merge-set-CSJoIpKB.js → merge-set-rXK3ehnB.js} +1 -1
  148. package/server/{merge-sync-CAjbJeTp.js → merge-sync-BKLKu9kz.js} +1 -1
  149. package/server/{merge-sync-CuyWzzZK.js → merge-sync-CaLRt2cB.js} +2 -2
  150. package/server/{merge-train-DndZCAiv.js → merge-train-DmxlYbEo.js} +3 -3
  151. package/server/{merge-train-deps-Bsy90Q7t.js → merge-train-deps-DBHsOWt9.js} +4 -4
  152. package/server/{merge-verification-Kvh4WViS.js → merge-verification-DA9rvqsE.js} +4 -4
  153. package/server/{multipart-parser-BWnfyoyz.js → multipart-parser-DtIEUW2B.js} +2 -2
  154. package/server/{no-resume-mode-CKy2bwZL.js → no-resume-mode-yrPEQ_pC.js} +1 -1
  155. package/server/{orphan-proposed-reconciler-Cg5_uVy1.js → orphan-proposed-reconciler-Db8tUhce.js} +10 -10
  156. package/server/{orphan-proposed-reconciler-CjUuBs6J.js → orphan-proposed-reconciler-mXV--tcB.js} +1 -1
  157. package/server/{pan-dir-Cn3NUnxU.js → pan-dir-BgBeeZDX.js} +3 -3
  158. package/server/{paths-Bo-kA9ta.js → paths-TE1GOZDr.js} +2 -2
  159. package/server/{pickup-DRn-XNXS.js → pickup-KLRUhThD.js} +1 -1
  160. package/server/{pipeline-notifier-BbGQtvKM.js → pipeline-notifier-aX_5EqQO.js} +2 -2
  161. package/server/{pipeline-notifier-DQsOtdjZ.js → pipeline-notifier-lwMa--Gz.js} +1 -1
  162. package/server/{projects-CKTA6Klk.js → projects-BNmVxnNt.js} +1 -1
  163. package/server/{prompts-CVncQg4P.js → prompts-CelsUdrx.js} +2 -2
  164. package/server/{providers-uPI9uU7Q.js → providers-4-xOzHQu.js} +7 -7
  165. package/server/{providers-CapuDkKX.js → providers-BOnRq5XK.js} +1 -1
  166. package/server/public/assets/{chunk-BO2N2NFS-CaAvtgHW.js → chunk-BO2N2NFS-jJsbVwoD.js} +4 -4
  167. package/server/public/assets/{diagram-OG6HWLK6-C4flU2X9.js → diagram-OG6HWLK6-Cp1aNi3v.js} +1 -1
  168. package/server/public/assets/{dist-DXAnG2e9.js → dist-B2-Oc7J1.js} +1 -1
  169. package/server/public/assets/{dist-DygIHsen.js → dist-Dbb8vdyE.js} +3 -3
  170. package/server/public/assets/{ganttDiagram-6RSMTGT7-BJY25etK.js → ganttDiagram-6RSMTGT7-rujV2mSn.js} +1 -1
  171. package/server/public/assets/{highlighted-body-OFNGDK62-DIEQLSG_.js → highlighted-body-OFNGDK62-Df3Exbbt.js} +1 -1
  172. package/server/public/assets/{index-BsKNi2y5.js → index-rQPa7qlV.js} +88 -88
  173. package/server/public/assets/{linear-CRa2o9KP.js → linear-Ctp3LAJ5.js} +1 -1
  174. package/server/public/assets/mermaid-GHXKKRXX-BnC2HrDq.js +1 -0
  175. package/server/public/assets/{pieDiagram-4H26LBE5-Cb6OrK_c.js → pieDiagram-4H26LBE5-K-m6VCum.js} +1 -1
  176. package/server/public/assets/{prod-DWpuiL-y.js → prod-jqZ3zqVg.js} +4 -4
  177. package/server/public/assets/{quadrantDiagram-W4KKPZXB-DhZzzcAO.js → quadrantDiagram-W4KKPZXB-DXcFax_1.js} +1 -1
  178. package/server/public/assets/{sankeyDiagram-5OEKKPKP-CVe6lE5A.js → sankeyDiagram-5OEKKPKP-DnD_J_rB.js} +1 -1
  179. package/server/public/assets/{xychartDiagram-2RQKCTM6-zukUz5pI.js → xychartDiagram-2RQKCTM6-Dx25iKVp.js} +1 -1
  180. package/server/public/index.html +1 -1
  181. package/server/{pull-requests-C3csHJsc.js → pull-requests-CH4iBFLl.js} +3 -3
  182. package/server/{pull-requests-MeAgb3Ax.js → pull-requests-DL_4klIb.js} +1 -1
  183. package/server/{rally-nalS21zz.js → rally-D0mKv2t8.js} +3 -3
  184. package/server/rally-DffLLIdl.js +3 -0
  185. package/server/{rally-api-DzQryQi8.js → rally-api-CcCdecF-.js} +1 -1
  186. package/server/{rally-api-DdY4ebu3.js → rally-api-DgAt6FbN.js} +2 -2
  187. package/server/{rally-client-9duSds1_.js → rally-client-DYjtgTOu.js} +4 -4
  188. package/server/{rally-client-B16-bZk9.js → rally-client-X0bEEN2B.js} +1 -1
  189. package/server/reap-terminal-sessions-BwJb2DLJ.js +3 -0
  190. package/server/{reap-terminal-sessions-C6rD1pDT.js → reap-terminal-sessions-CAmURC2h.js} +12 -62
  191. package/server/{rebuild-stack-D9qBmVcM.js → rebuild-stack-BLG3rlWa.js} +6 -6
  192. package/server/{rebuild-stack-DrWMHxoY.js → rebuild-stack-ByFCMqTK.js} +1 -1
  193. package/server/{reconstruct-cache--H2QBooC.js → reconstruct-cache-_tDZ2D72.js} +6 -6
  194. package/server/{record-fn7uPjsl.js → record-DjPikotp.js} +1 -1
  195. package/server/{remote-BEkHf2HO.js → remote-B1Trmr0N.js} +3 -3
  196. package/server/{remote-Dl6Hn0zz.js → remote-TN0cV8k-.js} +3 -3
  197. package/server/{remote-agents-DNdP4sew.js → remote-agents-CmbIKw7E.js} +5 -5
  198. package/server/{remote-agents-OB4zwVHz.js → remote-agents-DNuaAgU6.js} +1 -1
  199. package/server/{remote-completion-BINc1Y8c.js → remote-completion-Bklh6loJ.js} +12 -12
  200. package/server/resume-DnIsmIgC.js +3 -0
  201. package/server/review-agent-DgySDb-G.js +3 -0
  202. package/server/{review-agent-C-A6IgXc.js → review-agent-phzqNqIs.js} +599 -197
  203. package/server/{review-artifacts-DTTdAYsU.js → review-artifacts-BGc69epg.js} +7 -7
  204. package/server/{review-context-De14xPtc.js → review-context-CCq56O_Y.js} +7 -7
  205. package/server/{review-monitor-BNV3kjLq.js → review-monitor-BKG2ubt5.js} +2 -2
  206. package/server/{review-status-DWAsTqfJ.js → review-status-BQjqQXZG.js} +160 -52
  207. package/server/{review-status-mo3tyc8L.js → review-status-bBkqUj5i.js} +1 -1
  208. package/server/{review-status-enrichment-C6sr9wOI.js → review-status-enrichment-CGlcApSn.js} +3 -3
  209. package/server/{review-status-sync-D-p7TQit.js → review-status-sync-BWHnrq-k.js} +3 -3
  210. package/server/{review-status-sync-MvYGQLDD.js → review-status-sync-BxHBVH8s.js} +1 -1
  211. package/server/{review-verdict-feedback-BbIfN5Vg.js → review-verdict-feedback-cZh9Wi9G.js} +1 -1
  212. package/server/{review-verdict-feedback-Cfc-THvz.js → review-verdict-feedback-wqnikhMK.js} +16 -36
  213. package/server/{rollup-DgWlrSBc.js → rollup-BJE-Vc7H.js} +8 -8
  214. package/server/{rollup-CxR6GMTe.js → rollup-DBNy1yFB.js} +1 -1
  215. package/server/{scanner-6OmIn5XE.js → scanner-CUGpdp4i.js} +7 -7
  216. package/server/{sequence-io-CxiPMMKM.js → sequence-io-B2GmilSI.js} +4 -4
  217. package/server/{sequencer-agent--xPlSfR2.js → sequencer-agent-D8pW2aU_.js} +5 -5
  218. package/server/server.js +166 -162
  219. package/server/{service-CXje28KS.js → service-CILd-uOt.js} +46 -45
  220. package/server/session-fork-DDSDVoIK.js +99 -0
  221. package/server/{settings-ChvoXExM.js → settings-CBrei_kx.js} +2 -2
  222. package/server/{settings-DZq_bi-B.js → settings-D2wt4nku.js} +3 -3
  223. package/server/settings-vLoKyghx.js +2 -0
  224. package/server/{shadow-engineering-BHeyD5bL.js → shadow-engineering-Ba1D0QUN.js} +2 -2
  225. package/server/{shadow-state-p3YTxrJ5.js → shadow-state-BOaq8BrD.js} +1 -1
  226. package/server/{shadow-state-3L0eHQNE.js → shadow-state-DTC7AMHc.js} +2 -2
  227. package/server/{ship-log-B2EEH__n.js → ship-log-CMWH3H5-.js} +1 -1
  228. package/server/{smart-compaction-DRXK5_io.js → smart-compaction-Bgp_gwcA.js} +1 -1
  229. package/server/{smart-compaction-DMB4hv07.js → smart-compaction-CrP90OFE.js} +7 -7
  230. package/server/{spawn-planning-session-BZfVvIi3.js → spawn-planning-session-BmJWHSCu.js} +15 -15
  231. package/server/{spawn-planning-session-BBUzeHJQ.js → spawn-planning-session-D15KbPOy.js} +1 -1
  232. package/server/{specialist-completion-BAZHHbmp.js → specialist-completion-BiEXUHfD.js} +1 -1
  233. package/server/{specialist-context-DgdhI7rm.js → specialist-context-CwKkcXL9.js} +5 -5
  234. package/server/{specialist-handoff-logger-CH1nC8fq.js → specialist-handoff-logger-B_2VsWli.js} +2 -2
  235. package/server/{specialist-logs-DynFhFXg.js → specialist-logs-CvDxquV_.js} +3 -3
  236. package/server/{specialists-LJ9MZMCz.js → specialists-BCjcG4uE.js} +1 -1
  237. package/server/{specialists-BUKBHtmQ.js → specialists-BYi0k8CZ.js} +18 -18
  238. package/server/{specialists-e0Jmecc1.js → specialists-D07ybnam.js} +78 -85
  239. package/server/{specialists-CF02f9p2.js → specialists-F2uMO4QS.js} +1 -1
  240. package/server/specs-DeS98l_p.js +3 -0
  241. package/server/{src-CNLON0co.js → src-BswtmojL.js} +6 -6
  242. package/server/{src-DhJeCV1p.js → src-Dp0WHgDZ.js} +3 -3
  243. package/server/{src-AXK4mjue.js → src-fgbU-jJ-.js} +6 -3
  244. package/server/{stack-health-8jZH0Lgk.js → stack-health-BJVh1TCg.js} +3 -3
  245. package/server/{stack-health-CXYHwv5D.js → stack-health-Deel1mSW.js} +1 -1
  246. package/server/{state-home-XkLSsJCD.js → state-home-Bgj7i-C7.js} +8 -7
  247. package/server/{summary-fork-shfA2XOf.js → summary-fork-DedqguZb.js} +2 -2
  248. package/server/{summary-fork-BWa0ECGL.js → summary-fork-EjvOkEPl.js} +12 -91
  249. package/server/{supervisor-owMkHcx8.js → supervisor-0oXvLwyC.js} +3 -3
  250. package/server/supervisor-D1-XwmZ7.js +2 -0
  251. package/server/{swarm-readiness-BACUsKOx.js → swarm-readiness-OBgamRql.js} +3 -3
  252. package/server/{teardown-workspace-CYt_PBaq.js → teardown-workspace-5LCVbjfq.js} +14 -14
  253. package/server/{test-agent-queue-C1s6mB8C.js → test-agent-queue-qfsq6uaC.js} +6 -6
  254. package/server/{test-verdict-CmxX3KEf.js → test-verdict-BkubHtti.js} +1 -1
  255. package/server/{test-verdict-njEv9ZY2.js → test-verdict-D3Il7cBK.js} +1 -1
  256. package/server/{tldr-daemon-CEUflKr2.js → tldr-daemon-CJW_P4On.js} +2 -2
  257. package/server/{tldr-daemon-HIo0dwDB.js → tldr-daemon-CJqGsDFh.js} +1 -1
  258. package/server/tmux-CeDD14p1.js +3 -0
  259. package/server/{tmux-CBYZ5lKF.js → tmux-ePNhMIMU.js} +2 -2
  260. package/server/{token-CiS3w6Ma.js → token-_qujO3JZ.js} +1 -1
  261. package/server/{tracker-config-CVCoeaaL.js → tracker-config-C3hiPVAM.js} +2 -2
  262. package/server/{tracker-config-Bx50plWp.js → tracker-config-Drt_tx4D.js} +1 -1
  263. package/server/{tracker-utils-C2Lg4RoB.js → tracker-utils-D6B8scEw.js} +1 -1
  264. package/server/{tracker-utils-mI4d-vh8.js → tracker-utils-bpWs7Xyx.js} +2 -2
  265. package/server/{traefik-connect-D21-YEyX.js → traefik-connect-5EP1WS_Z.js} +1 -1
  266. package/server/{tunnel-BK4PVyb0.js → tunnel-3Ve8BS4H.js} +3 -3
  267. package/server/{tunnel-CcHkuRIS.js → tunnel-AporWhoi.js} +1 -1
  268. package/server/{types-DoPMvws2.js → types-B5u3NxMl.js} +1 -1
  269. package/server/{uat-train-BLFPxqLx.js → uat-train-C3hWXtip.js} +1 -1
  270. package/server/{uat-train-CQ_E-2ei.js → uat-train-CtNGgXxj.js} +27 -27
  271. package/server/{validation-Dab3bnSN.js → validation-BmUB-26g.js} +4 -4
  272. package/server/{validation-1QnjDMc0.js → validation-CbqP_dze.js} +1 -1
  273. package/server/{verification-runner-BO8TgZWA.js → verification-runner-BPAhPWR7.js} +11 -11
  274. package/server/{verification-runner-UhAAqOio.js → verification-runner-DuZRHjPU.js} +1 -1
  275. package/server/{vtt-parser-D-q5-8il.js → vtt-parser-CKc-smWM.js} +1 -1
  276. package/server/{work-agent-prompt-D_7T1xw5.js → work-agent-prompt-DCdHsm-V.js} +11 -11
  277. package/server/workflows-Cz8OtiB4.js +2 -0
  278. package/server/{workflows-CB5SWd0B.js → workflows-H-COJ84X.js} +14 -14
  279. package/server/{workspace-C4Avf_Tp.js → workspace-4ZufqeMe.js} +3 -3
  280. package/server/{workspace--XWYPbn1.js → workspace-DYv9kBg6.js} +1 -1
  281. package/server/{workspace-config-BwJB-bLH.js → workspace-config-DA8U97k9.js} +1 -1
  282. package/server/{workspace-manager-_6zbrhNF.js → workspace-manager-B3PqQQSM.js} +1 -1
  283. package/server/{workspace-manager-BE3OznLY.js → workspace-manager-CEWK-OXd.js} +12 -12
  284. package/server/{workspace-metadata-BCgODi1j.js → workspace-metadata-1eu1RvAT.js} +2 -2
  285. package/server/{workspace-metadata-wKPgY8PN.js → workspace-metadata-C0I-nIDL.js} +1 -1
  286. package/server/{workspaces-DpMiZ9BP.js → workspaces-CRU9_vRn.js} +154 -106
  287. package/server/agent-state-DTZCqWx5.js +0 -3
  288. package/server/cli-wyiCmp7b.js +0 -3
  289. package/server/deacon-swarm-jDiQ0kKk.js +0 -2
  290. package/server/dist-CnkaBMG-.js +0 -3
  291. package/server/forge-D2QLGWK9.js +0 -2
  292. package/server/hume-sCsuupWb.js +0 -3
  293. package/server/inspect-agent-DnspoIls.js +0 -2
  294. package/server/merge-ops-B6xc_Irj.js +0 -2
  295. package/server/public/assets/mermaid-GHXKKRXX-uIkd-n0c.js +0 -1
  296. package/server/rally-BJiyvz3w.js +0 -3
  297. package/server/reap-terminal-sessions-mW7SPDtP.js +0 -2
  298. package/server/resume-Pur3Z2e8.js +0 -3
  299. package/server/review-agent-BRSSFv7e.js +0 -3
  300. package/server/settings-D0XXIUQ0.js +0 -2
  301. package/server/specs-COn3zZ2Q.js +0 -3
  302. package/server/supervisor-DwGIhpXk.js +0 -2
  303. package/server/tmux-DNmHGMEv.js +0 -3
  304. package/server/workflows-Plo_VxeO.js +0 -2
@@ -1,18 +1,18 @@
1
1
  import { n as __esmMin } from "./rolldown-runtime-DNCzzKnI.js";
2
- import { Ft as resolveProjectForIssue, Nt as readIssueRecordSync, Ot as init_record, Ur as packageRoot, Vr as init_paths, X as resolveModel, f as loadConfigSync, t as init_config_yaml, yr as AGENTS_DIR } from "./config-yaml-DbdN9Fuq.js";
3
- import { a as init_activity_logger, n as emitActivityEntrySync } from "./activity-logger-Dm95Ua07.js";
4
- import { C as isPaneDead, O as listSessionNames, w as killSession, x as init_tmux } from "./tmux-CBYZ5lKF.js";
5
- import { c as init_review_status, y as setReviewStatusSync } from "./review-status-DWAsTqfJ.js";
6
- import { d as init_agents, f as listAgentIdsByPrefixSync, m as removeAgentSync } from "./briefing-freshness-B3YxHQ-L.js";
7
- import { Pn as getAgentStateSync, t as init_agents$1 } from "./agents-D_x5BSZM.js";
2
+ import { Ft as resolveProjectForIssue, Gr as sessionFilePath, Nt as readIssueRecordSync, Ot as init_record, Ur as packageRoot, Vr as init_paths, X as resolveModel, f as loadConfigSync, t as init_config_yaml, yr as AGENTS_DIR } from "./config-yaml-DPAieL_G.js";
3
+ import { a as init_activity_logger, n as emitActivityEntrySync } from "./activity-logger-pcbf-e30.js";
4
+ import { C as isPaneDead, O as listSessionNames, w as killSession, x as init_tmux } from "./tmux-ePNhMIMU.js";
5
+ import { c as init_review_status, s as getReviewStatusSync, y as setReviewStatusSync } from "./review-status-BQjqQXZG.js";
6
+ import { d as init_agents, f as listAgentIdsByPrefixSync, m as removeAgentSync } from "./briefing-freshness-CXhZdnB8.js";
7
+ import { Pn as getAgentStateSync, t as init_agents$1 } from "./agents-DHvsjsuP.js";
8
8
  import { a as PAN_DIRNAME, p as init_types } from "./types-CE1m_daD.js";
9
- import { n as init_review_monitor, t as REVIEW_SUB_ROLES } from "./review-monitor-BNV3kjLq.js";
10
- import { n as shouldSkipDispatchAsMerged, t as init_merge_verification } from "./merge-verification-Kvh4WViS.js";
11
- import { n as formatTier1Summary, o as init_review_context, t as buildReviewContext } from "./review-context-De14xPtc.js";
12
- import { a as resolveConflictGate, i as init_conflict_gate, r as getCachedConflictGateMergeability, t as buildRealConflictGateDeps } from "./conflict-gate-CgOtMo8i.js";
9
+ import { n as init_review_monitor, t as REVIEW_SUB_ROLES } from "./review-monitor-BKG2ubt5.js";
10
+ import { n as shouldSkipDispatchAsMerged, t as init_merge_verification } from "./merge-verification-DA9rvqsE.js";
11
+ import { n as formatTier1Summary, o as init_review_context, t as buildReviewContext } from "./review-context-CCq56O_Y.js";
12
+ import { a as resolveConflictGate, i as init_conflict_gate, r as getCachedConflictGateMergeability, t as buildRealConflictGateDeps } from "./conflict-gate-BhKvrPxn.js";
13
13
  import { Effect } from "effect";
14
14
  import { dirname, join } from "path";
15
- import { mkdir, readFile, rm } from "fs/promises";
15
+ import { mkdir, readFile, rm, writeFile } from "fs/promises";
16
16
  import { exec } from "child_process";
17
17
  import { promisify } from "util";
18
18
  //#region ../../lib/cloister/review-resume-decision.ts
@@ -34,43 +34,56 @@ function reviewResumeDecision(params) {
34
34
  }
35
35
  var init_review_resume_decision = __esmMin((() => {}));
36
36
  //#endregion
37
- //#region ../../lib/cloister/review-agent.ts
37
+ //#region ../../lib/cloister/review-rerun-scope.ts
38
+ function domainTouched(subRole, changedFiles) {
39
+ if (changedFiles.length === 0) return false;
40
+ switch (subRole) {
41
+ case "correctness":
42
+ case "requirements": return true;
43
+ case "security": return changedFiles.some((f) => SECURITY_SENSITIVE.test(f));
44
+ case "performance": return changedFiles.some((f) => PERFORMANCE_SENSITIVE.test(f));
45
+ default: return true;
46
+ }
47
+ }
48
+ function reviewersToRerun(input) {
49
+ const all = [...REVIEW_SUB_ROLES];
50
+ if (input.scope === "all") return all;
51
+ const verdicts = input.priorVerdicts ?? {};
52
+ const unproven = all.filter((r) => !verdicts[r] || !verdicts[r].atCommit);
53
+ const blocked = all.filter((r) => verdicts[r]?.status === "blocked");
54
+ if (input.scope === "blockers") return dedupe([...blocked, ...unproven]);
55
+ if (input.changedFiles === void 0) return all;
56
+ const touched = all.filter((r) => verdicts[r]?.status === "passed" && verdicts[r].atCommit && domainTouched(r, input.changedFiles));
57
+ return dedupe([
58
+ ...blocked,
59
+ ...unproven,
60
+ ...touched
61
+ ]);
62
+ }
63
+ function dedupe(roles) {
64
+ const set = new Set(roles);
65
+ return REVIEW_SUB_ROLES.filter((r) => set.has(r));
66
+ }
67
+ var SECURITY_SENSITIVE, PERFORMANCE_SENSITIVE;
68
+ var init_review_rerun_scope = __esmMin((() => {
69
+ init_review_monitor();
70
+ SECURITY_SENSITIVE = /auth|crypt|token|secret|credential|password|session|login|permission|sandbox|escape|inject|input|parse|network|http|request|fetch|socket|proxy|exec|spawn|shell|env|\.env|package(-lock)?\.json|bun\.lock|yarn\.lock|Dockerfile|docker-compose/i;
71
+ PERFORMANCE_SENSITIVE = /query|sql|db|database|cache|index|loop|batch|stream|worker|pool|queue|schedul|poll|interval|timer|migration|perf|bench|concurren|parallel/i;
72
+ }));
73
+ //#endregion
74
+ //#region ../../lib/cloister/review-convoy.ts
38
75
  /**
39
- * Review role entry point.
76
+ * PAN-1862: the review CONVOY — sub-reviewer prompts and spawning, selective
77
+ * re-review scope, warm-parent fork, and the discovery-ready orchestration.
40
78
  *
41
- * PAN-1048 review feedback 007: every legacy convoy helper has been retired.
42
- * The bash/tmux coordinator path (dispatchParallelReview /
43
- * spawnReviewCoordinatorSession / runParallelReview) was deleted in R6, and
44
- * the round-7 cleanup additionally removed the supporting cast that the
45
- * coordinator used to drive — spawnSingleReviewer, waitForReviewer,
46
- * archiveReviewerRound, parseReviewSynthesis, parseAgentOutput,
47
- * selectCompletedReviewers, getReviewAgents, getFilesChangedFromPR,
48
- * buildReviewFeedbackBody, parseReviewerTemplate, resolvePromptTemplatePath
49
- * (and the resolveTemplatePath alias), resolveReviewerModel,
50
- * reviewResultToReviewStatus, reviewerRetryBackoffMs,
51
- * isRetryableReviewerFailure, the ReviewContext / ReviewResult /
52
- * ReviewerTemplate / ReviewerRoundArtifact / ReviewerOutcome /
53
- * ReviewerWaitResult / ReviewerFailureReason / ReviewHistoryEntry types,
54
- * and DEFAULT_REVIEW_AGENTS / REVIEW_TIMEOUT_MS / MAX_REVIEWER_TIMEOUT_RETRIES
55
- * / REVIEWER_TIMEOUT_RETRY_BACKOFF_MS / REVIEW_HISTORY_DIR / REVIEW_HISTORY_FILE
56
- * / SPECIALISTS_DIR constants. None of these had any production caller after R6;
57
- * their tests went with them.
58
- *
59
- * Every active review surface — POST /api/review/:issueId/trigger, the
60
- * reactive scheduler review branch, and the dashboard kanban "Review again"
61
- * button — flows through
62
- * spawnReviewRoleForIssue → spawnRun(issueId, 'review'). The review role
63
- * launches four isolated review sub-role sessions via `pan review spawn-reviewer`,
64
- * then writes the report and signals the verdict via Overdeck's CLI inside
65
- * the role itself (see roles/review.md).
79
+ * Split out of review-agent.ts (which keeps the review entry point, the
80
+ * synthesis/self-review prompts, mode resolution, and session teardown).
81
+ * This module must NEVER import review-agent.ts — review-agent imports (and
82
+ * re-exports) from here, and a reverse edge would close a cycle.
66
83
  *
67
- * Surface area kept:
68
- * - spawnReviewRoleForIssue — the only review entry point
69
- * - killAllReviewerSessions — kill the canonical reviewer sessions
70
- * for one issue (merge-agent +
71
- * dashboard cancel/abort routes)
72
- * - killAllReviewSessions — kill ALL review sessions on shutdown
73
- * (pan down)
84
+ * The four convoy sub-roles are security, correctness, performance, and
85
+ * requirements (REVIEW_SUB_ROLES, review-monitor.ts); the synthesis parent is
86
+ * the fifth review role. See docs/REVIEW-AGENT-ARCHITECTURE.md.
74
87
  */
75
88
  /**
76
89
  * Read a convoy sub-role prompt template from the overdeck install.
@@ -135,116 +148,9 @@ async function buildConvoyPromptPromise(opts) {
135
148
  console.log(`[review-agent] Convoy prompt for ${opts.issueId}/${opts.subRole}: ${sizeBytes} bytes`);
136
149
  return prompt;
137
150
  }
138
- function buildReviewRolePrompt(opts) {
139
- const subRoleFiles = REVIEW_SUB_ROLES.map((r) => ` ${join(opts.reviewDir, `${r}.md`)}`).join("\n");
140
- const expectedSignals = REVIEW_SUB_ROLES.map((r) => ` REVIEWER_READY ${r} <outputPath> or REVIEWER_FAILED ${r} <reason> or REVIEWER_TIMEOUT ${r} <reason>`).join("\n");
141
- const synthesisPath = join(opts.reviewDir, "synthesis.md");
142
- const prompt = [
143
- `STANDBY — REVIEW SYNTHESIS for ${opts.issueId}`,
144
- "",
145
- "Do NOT do anything yet. The Overdeck server has already spawned the four",
146
- "convoy reviewers (security, correctness, performance, requirements) and they",
147
- "are running in parallel right now. Your work begins only once they finish.",
148
- "",
149
- "You will receive exactly one `pan tell` signal per sub-role as each reviewer",
150
- "finishes — these are delivered to you as user messages:",
151
- expectedSignals,
152
- "",
153
- "Until all four terminal signals have arrived: do nothing. Do not read the",
154
- "reviewer output files, do not run git, do not inspect tmux sessions, do not",
155
- "poll anything. Just wait — the reviewers notify you when they finish, and",
156
- "Deacon is the failsafe if one never starts or never completes. Acting early",
157
- "wastes tokens reviewing nothing.",
158
- "",
159
- "Once you have all four terminal signals, follow roles/review.md exactly to",
160
- "read the reports, synthesize the verdict, write the synthesis report, and",
161
- "signal the status.",
162
- "",
163
- "── Review context ──",
164
- `Issue: ${opts.issueId}`,
165
- `Branch: ${opts.branch}`,
166
- `Workspace: ${opts.workspace}`,
167
- opts.prUrl ? `PR: ${opts.prUrl}` : `PR: (resolve via: gh pr view ${opts.branch})`,
168
- `Run ID: ${opts.runId}`,
169
- `Review directory: ${opts.reviewDir}`,
170
- `Synthesis output file: ${synthesisPath}`,
171
- "",
172
- opts.tier1Summary ? [
173
- "Shared review context:",
174
- "─────────────────────────────────────────────────────────────",
175
- opts.tier1Summary,
176
- "─────────────────────────────────────────────────────────────",
177
- "",
178
- opts.contextManifestPath ? `Full manifest: ${opts.contextManifestPath}` : ""
179
- ].join("\n") : opts.contextManifestPath ? `Context manifest: ${opts.contextManifestPath}` : "Context manifest: (missing — block review per roles/review.md)",
180
- "",
181
- "Convoy reviewer output files (read each one ONLY after its REVIEWER_READY signal):",
182
- subRoleFiles,
183
- "",
184
- "After writing the synthesis report, signal the verdict with Overdeck CLI:",
185
- ` pan admin specialists done review ${opts.issueId} --status passed --notes "<one-line summary>"`,
186
- ` pan admin specialists done review ${opts.issueId} --status blocked --notes "<one-line top blocker>"`,
187
- "",
188
- "After running the signal command above, STOP and wait — do not exit, do not run",
189
- "any further commands. The session stays open for the next review cycle.",
190
- "",
191
- "Reactive Cloister dispatches the test role after review passes. Never queue tests yourself and never edit code."
192
- ].filter(Boolean).join("\n");
193
- const sizeBytes = Buffer.byteLength(prompt, "utf-8");
194
- console.log(`[review-agent] Synthesis prompt for ${opts.issueId}: ${sizeBytes} bytes`);
195
- return prompt;
196
- }
197
- function buildSelfReviewPrompt(opts) {
198
- const reviewReportPath = join(opts.reviewDir, "review.md");
199
- const prompt = [
200
- `CODE REVIEW for ${opts.issueId} — you are the sole reviewer; review the change yourself.`,
201
- "",
202
- "Review the diff for this branch yourself, across ALL dimensions in one pass:",
203
- "correctness/logic, security, requirements/acceptance-criteria, and performance.",
204
- "Do NOT spawn or wait for any sub-reviewers — there is no convoy; you do the",
205
- "whole review yourself and emit the verdict.",
206
- "",
207
- "── Review context ──",
208
- `Issue: ${opts.issueId}`,
209
- `Branch: ${opts.branch}`,
210
- `Workspace: ${opts.workspace}`,
211
- opts.prUrl ? `PR: ${opts.prUrl}` : `PR: (resolve via: gh pr view ${opts.branch})`,
212
- `Run ID: ${opts.runId}`,
213
- `Review directory: ${opts.reviewDir}`,
214
- `Review output file: ${reviewReportPath}`,
215
- "",
216
- opts.tier1Summary ? [
217
- "Shared review context (risk-ranked changed files + acceptance criteria):",
218
- "─────────────────────────────────────────────────────────────",
219
- opts.tier1Summary,
220
- "─────────────────────────────────────────────────────────────",
221
- "",
222
- opts.contextManifestPath ? `Full manifest: ${opts.contextManifestPath}` : ""
223
- ].join("\n") : opts.contextManifestPath ? `Context manifest: ${opts.contextManifestPath}` : "Context manifest: (missing — inspect the diff directly: git diff origin/main...HEAD)",
224
- "",
225
- "How to review:",
226
- "1. Read the diff — use the manifest risk ranking, `git diff` the high-risk files,",
227
- " and read the surrounding code as needed.",
228
- "2. Evaluate correctness, security, requirements/AC, and performance. Use the",
229
- " severity + verdict vocabulary in roles/review.md.",
230
- `3. Write your findings to ${reviewReportPath}.`,
231
- "",
232
- "Then signal the verdict with the Overdeck CLI (exactly one):",
233
- ` pan admin specialists done review ${opts.issueId} --status passed --notes "<one-line summary>"`,
234
- ` pan admin specialists done review ${opts.issueId} --status blocked --notes "<one-line top blocker>"`,
235
- "",
236
- "After running the signal command above, STOP and wait — do not exit, do not run",
237
- "any further commands. The session stays open for the next review cycle.",
238
- "",
239
- "Reactive Cloister dispatches the test role after review passes. Never queue tests yourself and never edit code."
240
- ].filter(Boolean).join("\n");
241
- const sizeBytes = Buffer.byteLength(prompt, "utf-8");
242
- console.log(`[review-agent] Self-review prompt for ${opts.issueId}: ${sizeBytes} bytes`);
243
- return prompt;
244
- }
245
151
  async function spawnReviewSubRoleForIssuePromise(opts) {
246
152
  try {
247
- const { saveAgentState, spawnRun, getAgentStateSync, getLatestSessionIdSync, resumeAgent } = await import("./agents-KaEsWZ8D.js");
153
+ const { saveAgentState, spawnRun, getAgentStateSync, getLatestSessionIdSync, resumeAgent } = await import("./agents-BIggLvi_.js");
248
154
  const cfg = loadConfigSync().config;
249
155
  const outputPath = opts.outputPath ?? reviewerAgentOutputPath(opts.workspace, opts.runId, opts.subRole);
250
156
  const synthesisAgentId = opts.synthesisAgentId ?? `agent-${opts.issueId.toLowerCase()}-review`;
@@ -270,8 +176,8 @@ async function spawnReviewSubRoleForIssuePromise(opts) {
270
176
  tier1Summary
271
177
  }));
272
178
  const reviewerAgent = reviewerAgentId(opts.issueId, opts.subRole);
273
- const savedReviewer = getAgentStateSync(reviewerAgent);
274
- if (reviewResumeDecision({
179
+ const savedReviewer = opts.forkedSessionId ? null : getAgentStateSync(reviewerAgent);
180
+ if (!opts.forkedSessionId && reviewResumeDecision({
275
181
  requestedModel: opts.model ?? model,
276
182
  requestedHarness: opts.harness,
277
183
  savedModel: savedReviewer?.model,
@@ -301,12 +207,24 @@ async function spawnReviewSubRoleForIssuePromise(opts) {
301
207
  }
302
208
  console.warn(`[review-agent] Convoy sub-reviewer ${opts.subRole} resume failed; falling back to a fresh session: ${resumeResult.error}`);
303
209
  }
210
+ const forkedPreface = opts.forkedSessionId ? [
211
+ "SHARED DISCOVERY CONTEXT (PAN-1862): this session was forked from the review",
212
+ "parent AFTER it completed a shared discovery pass — the diff, the high-risk",
213
+ "changed files, and their surrounding code are already in your history above.",
214
+ "That pass exists for cost (forked reviewers reuse the warm prompt cache instead",
215
+ "of four full-price re-reads) and for consistency (every reviewer sees the same",
216
+ "curated context). BUILD ON IT: do not re-run a broad git diff and do not",
217
+ "re-read the files already shown above; read further code only where your",
218
+ "sub-role needs deeper detail.",
219
+ ""
220
+ ].join("\n") : "";
304
221
  const run = await spawnRun(opts.issueId, "review", {
305
222
  workspace: opts.workspace,
306
223
  subRole: opts.subRole,
307
- prompt,
224
+ prompt: forkedPreface + prompt,
308
225
  model,
309
226
  harness: opts.harness,
227
+ ...opts.forkedSessionId ? { resumeSessionId: opts.forkedSessionId } : {},
310
228
  reviewSynthesisAgentId: synthesisAgentId,
311
229
  reviewOutputPath: outputPath,
312
230
  allowHost: opts.allowHost ?? false
@@ -316,9 +234,10 @@ async function spawnReviewSubRoleForIssuePromise(opts) {
316
234
  run.reviewOutputPath = outputPath;
317
235
  run.reviewSynthesisAgentId = synthesisAgentId;
318
236
  run.reviewDeadlineAt = new Date(Date.now() + REVIEWER_TIMEOUT_MS).toISOString();
237
+ if (opts.forkedSessionId) run.reviewForkedFromParent = true;
319
238
  await Effect.runPromise(saveAgentState(run));
320
239
  try {
321
- const { notifyPipelineSync } = await import("./pipeline-notifier-DQsOtdjZ.js");
240
+ const { notifyPipelineSync } = await import("./pipeline-notifier-lwMa--Gz.js");
322
241
  notifyPipelineSync({
323
242
  type: "reviewer_started",
324
243
  issueId: opts.issueId,
@@ -339,6 +258,442 @@ async function spawnReviewSubRoleForIssuePromise(opts) {
339
258
  };
340
259
  }
341
260
  }
261
+ /**
262
+ * PAN-1862: selective re-review scope for one dispatch — which convoy reviewers
263
+ * run this cycle and which carry their prior passed verdict forward. Shared by
264
+ * the inline dispatch path and the discovery-ready fork handler.
265
+ */
266
+ async function computeConvoyScope(issueId, workspace) {
267
+ let inScope = [...REVIEW_SUB_ROLES];
268
+ let carried = [];
269
+ let scope = "changed";
270
+ try {
271
+ const { getReviewStatusSync } = await import("./review-status-bBkqUj5i.js");
272
+ scope = resolveReReviewScope(issueId);
273
+ const priorVerdicts = getReviewStatusSync(issueId)?.reviewerVerdicts;
274
+ let changedFiles;
275
+ const anchors = new Set(Object.values(priorVerdicts ?? {}).map((v) => v?.atCommit).filter((c) => !!c));
276
+ if (anchors.size === 1) try {
277
+ const { stdout } = await execAsync$1(`git diff --name-only ${[...anchors][0]}..HEAD`, {
278
+ cwd: workspace,
279
+ encoding: "utf-8",
280
+ timeout: 15e3
281
+ });
282
+ changedFiles = stdout.split("\n").map((l) => l.trim()).filter(Boolean);
283
+ } catch {}
284
+ inScope = reviewersToRerun({
285
+ scope,
286
+ priorVerdicts,
287
+ changedFiles
288
+ });
289
+ carried = REVIEW_SUB_ROLES.filter((r) => !inScope.includes(r)).map((r) => ({
290
+ subRole: r,
291
+ atCommit: priorVerdicts?.[r]?.atCommit
292
+ }));
293
+ if (carried.length > 0) console.log(`[review-agent] Selective re-review for ${issueId} (scope=${scope}): re-running [${inScope.join(", ")}], carrying forward [${carried.map((c) => c.subRole).join(", ")}]`);
294
+ } catch (scopeErr) {
295
+ console.warn(`[review-agent] Selective re-review scope resolution failed for ${issueId} — running the full convoy:`, scopeErr);
296
+ inScope = [...REVIEW_SUB_ROLES];
297
+ carried = [];
298
+ }
299
+ return {
300
+ inScope,
301
+ carried,
302
+ scope
303
+ };
304
+ }
305
+ /**
306
+ * PAN-1862 Phase A: fork the synthesis parent's Claude session JSONL to a fresh
307
+ * session id so a convoy reviewer can `--resume` it and inherit the discovery
308
+ * context (and its warm, content-addressed prompt cache). Returns null when the
309
+ * fork is not possible — caller degrades to a fresh independent spawn (NFR-2).
310
+ * The source JSONL is copied, never modified.
311
+ */
312
+ async function forkParentSessionForReviewer(parentAgentId, workspace) {
313
+ try {
314
+ const { getLatestSessionIdSync } = await import("./agents-BIggLvi_.js");
315
+ const parentSessionId = getLatestSessionIdSync(parentAgentId);
316
+ if (!parentSessionId) return null;
317
+ const src = sessionFilePath(workspace, parentSessionId);
318
+ const { existsSync } = await import("fs");
319
+ if (!existsSync(src)) return null;
320
+ const { reserveForkSession, copySessionForFork } = await import("./session-fork-DDSDVoIK.js");
321
+ const reserved = await reserveForkSession(workspace);
322
+ await copySessionForFork(src, reserved.sessionFile, { fullHistory: true });
323
+ return reserved.sessionId;
324
+ } catch (err) {
325
+ console.warn(`[review-agent] Fork from ${parentAgentId} failed (degrading to independent spawn): ${err instanceof Error ? err.message : String(err)}`);
326
+ return null;
327
+ }
328
+ }
329
+ /**
330
+ * Launch the review convoy for one run: write carried-forward stub reports, then
331
+ * spawn (or fork-resume) each in-scope sub-reviewer. Shared by the inline
332
+ * dispatch path (no fork) and the discovery-ready handler (fork).
333
+ */
334
+ async function launchConvoyReviewersPromise(params) {
335
+ const reviewDir = join(params.workspace, PAN_DIRNAME, "review", params.runId);
336
+ if (params.carried.length > 0) {
337
+ await mkdir(reviewDir, { recursive: true });
338
+ for (const c of params.carried) {
339
+ const stubPath = reviewerAgentOutputPath(params.workspace, params.runId, c.subRole);
340
+ const anchorNote = c.atCommit ? ` at commit ${c.atCommit.slice(0, 8)}` : "";
341
+ await writeFile(stubPath, [
342
+ `# ${c.subRole} review — VERDICT CARRIED FORWARD`,
343
+ "",
344
+ "## Verdict: APPROVED (carried forward — reviewer not re-run this cycle)",
345
+ "",
346
+ `This reviewer passed the prior cycle${anchorNote} and no files in its domain`,
347
+ `changed since (reReviewScope=${params.scope}, PAN-1862 selective re-review).`,
348
+ "Its prior findings report remains the report of record for that verdict.",
349
+ "",
350
+ "## Findings",
351
+ "",
352
+ "None.",
353
+ ""
354
+ ].join("\n"), "utf-8");
355
+ }
356
+ }
357
+ const cfg = loadConfigSync().config;
358
+ const { getAgentStateSync } = await import("./agents-BIggLvi_.js");
359
+ const parentState = getAgentStateSync(params.synthesisAgentId);
360
+ const reviewerResults = await Promise.all(params.inScope.map(async (subRole) => {
361
+ const outputPath = reviewerAgentOutputPath(params.workspace, params.runId, subRole);
362
+ let forkedSessionId;
363
+ if (params.forkFromParent && parentState?.harness === "claude-code" && !params.harness) try {
364
+ const { getLatestSessionIdSync } = await import("./agents-BIggLvi_.js");
365
+ const reviewerModel = params.model ?? resolveModel("review", subRole, cfg);
366
+ if (!!!getLatestSessionIdSync(reviewerAgentId(params.issueId, subRole)) && reviewerModel === parentState.model) {
367
+ forkedSessionId = await forkParentSessionForReviewer(params.synthesisAgentId, params.workspace) ?? void 0;
368
+ if (forkedSessionId) console.log(`[review-agent] Forked ${subRole} reviewer for ${params.issueId} from ${params.synthesisAgentId}'s discovery session (PAN-1862)`);
369
+ }
370
+ } catch {}
371
+ const result = await Effect.runPromise(spawnReviewSubRoleForIssue({
372
+ issueId: params.issueId,
373
+ workspace: params.workspace,
374
+ subRole,
375
+ runId: params.runId,
376
+ outputPath,
377
+ contextManifestPath: params.contextManifestPath,
378
+ synthesisAgentId: params.synthesisAgentId,
379
+ ...params.model ? { model: params.model } : {},
380
+ ...params.harness ? { harness: params.harness } : {},
381
+ ...forkedSessionId ? { forkedSessionId } : {},
382
+ allowHost: params.allowHost ?? false
383
+ }));
384
+ if (!result.success) try {
385
+ const { messageAgent } = await import("./agents-BIggLvi_.js");
386
+ await messageAgent(params.synthesisAgentId, `REVIEWER_FAILED ${subRole} ${result.error ?? result.message}`);
387
+ } catch (signalErr) {
388
+ console.warn(`[review-agent] Failed to signal ${subRole} spawn failure to ${params.synthesisAgentId}:`, signalErr);
389
+ }
390
+ return result;
391
+ }));
392
+ const failedReviewers = reviewerResults.filter((r) => !r.success);
393
+ if (failedReviewers.length > 0) console.warn(`[review-agent] Convoy launched for ${params.issueId}, but ${failedReviewers.length} reviewer(s) failed to spawn`);
394
+ return reviewerResults;
395
+ }
396
+ /**
397
+ * Effect variant of {@link spawnReviewRoleForIssue}. The Promise version
398
+ * returns a structured result instead of throwing, so the Effect form lifts
399
+ * via `Effect.promise`.
400
+ */
401
+ /**
402
+ * PAN-1862 Phase A (FR-2/FR-3/FR-4, NFR-5): handle the parent's discovery-ready
403
+ * signal — fork the parent's session into the convoy reviewers and launch them.
404
+ * Idempotent: a repeat signal (or a signal after the convoy already launched)
405
+ * is a no-op. The parent survives unmodified and resumes its synthesis role;
406
+ * the CLI (`pan admin specialists discovery-ready review <id>`) and the deacon
407
+ * stalled-discovery backstop both land here.
408
+ */
409
+ async function handleReviewDiscoveryReady(issueId, opts = {}) {
410
+ const normalized = issueId.toUpperCase();
411
+ const parentId = `agent-${normalized.toLowerCase()}-review`;
412
+ const { saveAgentState, getAgentStateSync } = await import("./agents-BIggLvi_.js");
413
+ const parent = getAgentStateSync(parentId);
414
+ if (!parent) return {
415
+ success: false,
416
+ message: `No review parent state for ${normalized} — nothing to fork`
417
+ };
418
+ const workspace = parent.workspace;
419
+ const runId = parent.reviewRunId;
420
+ if (!workspace || !runId) return {
421
+ success: false,
422
+ message: `Review parent for ${normalized} is missing workspace/runId state — cannot launch the convoy`
423
+ };
424
+ try {
425
+ const sessions = await Effect.runPromise(listSessionNames());
426
+ const reviewerPrefix = `agent-${normalized.toLowerCase()}-review-`;
427
+ if (sessions.some((name) => name.startsWith(reviewerPrefix))) {
428
+ parent.reviewDiscoveryPending = false;
429
+ await Effect.runPromise(saveAgentState(parent));
430
+ return {
431
+ success: true,
432
+ message: `Convoy already launched for ${normalized} — no-op`
433
+ };
434
+ }
435
+ } catch {}
436
+ try {
437
+ const { existsSync } = await import("node:fs");
438
+ if (REVIEW_SUB_ROLES.some((subRole) => existsSync(reviewerAgentOutputPath(workspace, runId, subRole)))) {
439
+ parent.reviewDiscoveryPending = false;
440
+ await Effect.runPromise(saveAgentState(parent));
441
+ return {
442
+ success: true,
443
+ message: `Convoy for ${normalized} run ${runId} already produced reviewer output — no-op`
444
+ };
445
+ }
446
+ } catch {}
447
+ parent.reviewDiscoveryPending = false;
448
+ parent.reviewDiscoveryReadyAt = (/* @__PURE__ */ new Date()).toISOString();
449
+ await Effect.runPromise(saveAgentState(parent));
450
+ const { inScope, carried, scope } = await computeConvoyScope(normalized, workspace);
451
+ const results = await launchConvoyReviewersPromise({
452
+ issueId: normalized,
453
+ workspace,
454
+ runId,
455
+ synthesisAgentId: parentId,
456
+ inScope,
457
+ carried,
458
+ scope,
459
+ contextManifestPath: parent.reviewContextManifestPath,
460
+ allowHost: parent.hostOverride ?? false,
461
+ forkFromParent: true
462
+ });
463
+ const refreshed = getAgentStateSync(parentId);
464
+ if (refreshed) {
465
+ refreshed.reviewConvoyForkedAt = (/* @__PURE__ */ new Date()).toISOString();
466
+ await Effect.runPromise(saveAgentState(refreshed));
467
+ }
468
+ const launched = results.filter((r) => r.success).length;
469
+ const message = `Discovery-ready for ${normalized}${opts.source ? ` (${opts.source})` : ""}: launched ${launched}/${inScope.length} convoy reviewer(s)${carried.length ? `, carried [${carried.map((c) => c.subRole).join(", ")}]` : ""}`;
470
+ console.log(`[review-agent] ${message}`);
471
+ emitActivityEntrySync({
472
+ source: "review",
473
+ level: "info",
474
+ message,
475
+ issueId: normalized
476
+ });
477
+ return {
478
+ success: launched > 0 || inScope.length === 0,
479
+ message,
480
+ launched
481
+ };
482
+ }
483
+ /** PAN-1862 (FR-7): resolved re-review scope — merged config, default 'changed'. */
484
+ function resolveReReviewScope(issueId) {
485
+ if (issueId) try {
486
+ const project = resolveProjectForIssue(issueId);
487
+ const issueScope = project ? readIssueRecordSync(project, issueId)?.reReviewScope : void 0;
488
+ if (issueScope === "all" || issueScope === "changed" || issueScope === "blockers") return issueScope;
489
+ } catch {}
490
+ const scope = loadConfigSync().config.roles?.review?.reReviewScope;
491
+ return scope === "all" || scope === "blockers" ? scope : "changed";
492
+ }
493
+ var execAsync$1, REVIEWER_TIMEOUT_MS, buildConvoyPrompt, spawnReviewSubRoleForIssue;
494
+ var init_review_convoy = __esmMin((() => {
495
+ init_tmux();
496
+ init_activity_logger();
497
+ init_config_yaml();
498
+ init_review_context();
499
+ init_review_monitor();
500
+ init_review_resume_decision();
501
+ init_review_rerun_scope();
502
+ init_record();
503
+ init_types();
504
+ init_paths();
505
+ execAsync$1 = promisify(exec);
506
+ REVIEWER_TIMEOUT_MS = 1200 * 1e3;
507
+ buildConvoyPrompt = (opts) => Effect.promise(() => buildConvoyPromptPromise(opts));
508
+ spawnReviewSubRoleForIssue = (opts) => Effect.promise(() => spawnReviewSubRoleForIssuePromise(opts));
509
+ }));
510
+ //#endregion
511
+ //#region ../../lib/cloister/review-agent.ts
512
+ /**
513
+ * Review role entry point.
514
+ *
515
+ * PAN-1048 review feedback 007: every legacy convoy helper has been retired.
516
+ * The bash/tmux coordinator path (dispatchParallelReview /
517
+ * spawnReviewCoordinatorSession / runParallelReview) was deleted in R6, and
518
+ * the round-7 cleanup additionally removed the supporting cast that the
519
+ * coordinator used to drive — spawnSingleReviewer, waitForReviewer,
520
+ * archiveReviewerRound, parseReviewSynthesis, parseAgentOutput,
521
+ * selectCompletedReviewers, getReviewAgents, getFilesChangedFromPR,
522
+ * buildReviewFeedbackBody, parseReviewerTemplate, resolvePromptTemplatePath
523
+ * (and the resolveTemplatePath alias), resolveReviewerModel,
524
+ * reviewResultToReviewStatus, reviewerRetryBackoffMs,
525
+ * isRetryableReviewerFailure, the ReviewContext / ReviewResult /
526
+ * ReviewerTemplate / ReviewerRoundArtifact / ReviewerOutcome /
527
+ * ReviewerWaitResult / ReviewerFailureReason / ReviewHistoryEntry types,
528
+ * and DEFAULT_REVIEW_AGENTS / REVIEW_TIMEOUT_MS / MAX_REVIEWER_TIMEOUT_RETRIES
529
+ * / REVIEWER_TIMEOUT_RETRY_BACKOFF_MS / REVIEW_HISTORY_DIR / REVIEW_HISTORY_FILE
530
+ * / SPECIALISTS_DIR constants. None of these had any production caller after R6;
531
+ * their tests went with them.
532
+ *
533
+ * Every active review surface — POST /api/review/:issueId/trigger, the
534
+ * reactive scheduler review branch, and the dashboard kanban "Review again"
535
+ * button — flows through
536
+ * spawnReviewRoleForIssue → spawnRun(issueId, 'review'). The review role
537
+ * launches four isolated review sub-role sessions via `pan review spawn-reviewer`,
538
+ * then writes the report and signals the verdict via Overdeck's CLI inside
539
+ * the role itself (see roles/review.md).
540
+ *
541
+ * Surface area kept:
542
+ * - spawnReviewRoleForIssue — the only review entry point
543
+ * - killAllReviewerSessions — kill the canonical reviewer sessions
544
+ * for one issue (merge-agent +
545
+ * dashboard cancel/abort routes)
546
+ * - killAllReviewSessions — kill ALL review sessions on shutdown
547
+ * (pan down)
548
+ */
549
+ function buildReviewRolePrompt(opts) {
550
+ const inScope = opts.inScopeSubRoles && opts.inScopeSubRoles.length > 0 ? opts.inScopeSubRoles : [...REVIEW_SUB_ROLES];
551
+ const carried = opts.carriedSubRoles ?? [];
552
+ const subRoleFiles = REVIEW_SUB_ROLES.map((r) => ` ${join(opts.reviewDir, `${r}.md`)}`).join("\n");
553
+ const expectedSignals = inScope.map((r) => ` REVIEWER_READY ${r} <outputPath> or REVIEWER_FAILED ${r} <reason> or REVIEWER_TIMEOUT ${r} <reason>`).join("\n");
554
+ const synthesisPath = join(opts.reviewDir, "synthesis.md");
555
+ const runningDesc = inScope.length === REVIEW_SUB_ROLES.length ? "the four convoy reviewers (security, correctness, performance, requirements)" : `${inScope.length} convoy reviewer(s) this cycle (${inScope.join(", ")})`;
556
+ const carriedSection = carried.length > 0 ? [
557
+ "",
558
+ `CARRIED-FORWARD VERDICTS (PAN-1862 selective re-review): ${carried.map((c) => c.subRole).join(", ")}.`,
559
+ "These reviewers PASSED the prior cycle and none of their domain files changed",
560
+ "since, so they were NOT re-run. Their stub reports are already written in the",
561
+ "review directory — treat each as a passed verdict. Do NOT wait for signals",
562
+ "from them; they will never arrive."
563
+ ].join("\n") : "";
564
+ const prompt = [
565
+ ...opts.discovery ? [
566
+ `DISCOVERY + SYNTHESIS — REVIEW for ${opts.issueId}`,
567
+ "",
568
+ "PHASE 1 — SHARED DISCOVERY (do this FIRST):",
569
+ "Read the code the whole review convoy will need so it lives in THIS",
570
+ "session's history. WHY: after you signal readiness the server FORKS this",
571
+ "session into the convoy reviewers, and because the prompt cache is",
572
+ "content-addressed, everything you read here becomes a ~90%-discounted",
573
+ "cache read for every forked reviewer instead of four independent",
574
+ "full-price re-reads. Reviewers also review better when they all see the",
575
+ "same curated context and understand the change as a whole.",
576
+ "",
577
+ "1. Read the context manifest (path below): risk ranking + acceptance criteria.",
578
+ "2. Read the committed diff for the branch (git diff against the merge base).",
579
+ "3. Read the FULL contents of the HIGH-risk changed files and the immediately",
580
+ " surrounding code they depend on. Stay within the manifest scope — this is",
581
+ " curation for the convoy, not an open-ended crawl.",
582
+ "",
583
+ "Then signal readiness EXACTLY ONCE (repeat signals are a server-side no-op):",
584
+ ` pan admin specialists discovery-ready review ${opts.issueId}`,
585
+ "",
586
+ "PHASE 2 — STANDBY (after the signal):",
587
+ `The server forks this session into ${runningDesc}.`,
588
+ "Your work resumes only once they finish.",
589
+ ""
590
+ ] : [
591
+ `STANDBY — REVIEW SYNTHESIS for ${opts.issueId}`,
592
+ "",
593
+ `Do NOT do anything yet. The Overdeck server has already spawned ${runningDesc}`,
594
+ "and they are running in parallel right now. Your work begins only once they finish.",
595
+ ""
596
+ ],
597
+ `You will receive exactly one \`pan tell\` signal per RUNNING sub-role as each`,
598
+ "reviewer finishes — these are delivered to you as user messages:",
599
+ expectedSignals,
600
+ carriedSection,
601
+ "",
602
+ `Until all ${inScope.length} terminal signal(s) have arrived: do nothing. Do not read the`,
603
+ "reviewer output files, do not run git, do not inspect tmux sessions, do not",
604
+ "poll anything. Just wait — the reviewers notify you when they finish, and",
605
+ "Deacon is the failsafe if one never starts or never completes. Acting early",
606
+ "wastes tokens reviewing nothing.",
607
+ "",
608
+ `Once you have all ${inScope.length} terminal signal(s), follow roles/review.md exactly to`,
609
+ "read the reports (including any carried-forward stubs), synthesize the verdict,",
610
+ "write the synthesis report, and signal the status.",
611
+ "",
612
+ "── Review context ──",
613
+ `Issue: ${opts.issueId}`,
614
+ `Branch: ${opts.branch}`,
615
+ `Workspace: ${opts.workspace}`,
616
+ opts.prUrl ? `PR: ${opts.prUrl}` : `PR: (resolve via: gh pr view ${opts.branch})`,
617
+ `Run ID: ${opts.runId}`,
618
+ `Review directory: ${opts.reviewDir}`,
619
+ `Synthesis output file: ${synthesisPath}`,
620
+ "",
621
+ opts.tier1Summary ? [
622
+ "Shared review context:",
623
+ "─────────────────────────────────────────────────────────────",
624
+ opts.tier1Summary,
625
+ "─────────────────────────────────────────────────────────────",
626
+ "",
627
+ opts.contextManifestPath ? `Full manifest: ${opts.contextManifestPath}` : ""
628
+ ].join("\n") : opts.contextManifestPath ? `Context manifest: ${opts.contextManifestPath}` : "Context manifest: (missing — block review per roles/review.md)",
629
+ "",
630
+ "Convoy reviewer output files (read each one ONLY after its REVIEWER_READY signal):",
631
+ subRoleFiles,
632
+ "",
633
+ "After writing the synthesis report, signal the verdict with Overdeck CLI,",
634
+ "including a per-reviewer verdict for each sub-role that RAN this cycle",
635
+ "(PAN-1862 — this is what lets the next re-review skip provably-clean reviewers;",
636
+ "do NOT list carried-forward sub-roles, their verdicts are already recorded):",
637
+ ` pan admin specialists done review ${opts.issueId} --status passed --notes "<one-line summary>" --reviewers "${inScope.map((r) => `${r}=passed`).join(",")}"`,
638
+ ` pan admin specialists done review ${opts.issueId} --status blocked --notes "<one-line top blocker>" --reviewers "<subRole>=passed|blocked for each of: ${inScope.join(", ")}>"`,
639
+ "",
640
+ "After running the signal command above, STOP and wait — do not exit, do not run",
641
+ "any further commands. The session stays open for the next review cycle.",
642
+ "",
643
+ "Reactive Cloister dispatches the test role after review passes. Never queue tests yourself and never edit code."
644
+ ].filter(Boolean).join("\n");
645
+ const sizeBytes = Buffer.byteLength(prompt, "utf-8");
646
+ console.log(`[review-agent] Synthesis prompt for ${opts.issueId}: ${sizeBytes} bytes`);
647
+ return prompt;
648
+ }
649
+ function buildSelfReviewPrompt(opts) {
650
+ const reviewReportPath = join(opts.reviewDir, "review.md");
651
+ const prompt = [
652
+ `CODE REVIEW for ${opts.issueId} — you are the sole reviewer; review the change yourself.`,
653
+ "",
654
+ "Review the diff for this branch yourself, across ALL dimensions in one pass:",
655
+ "correctness/logic, security, requirements/acceptance-criteria, and performance.",
656
+ "Do NOT spawn or wait for any sub-reviewers — there is no convoy; you do the",
657
+ "whole review yourself and emit the verdict.",
658
+ "",
659
+ "── Review context ──",
660
+ `Issue: ${opts.issueId}`,
661
+ `Branch: ${opts.branch}`,
662
+ `Workspace: ${opts.workspace}`,
663
+ opts.prUrl ? `PR: ${opts.prUrl}` : `PR: (resolve via: gh pr view ${opts.branch})`,
664
+ `Run ID: ${opts.runId}`,
665
+ `Review directory: ${opts.reviewDir}`,
666
+ `Review output file: ${reviewReportPath}`,
667
+ "",
668
+ opts.tier1Summary ? [
669
+ "Shared review context (risk-ranked changed files + acceptance criteria):",
670
+ "─────────────────────────────────────────────────────────────",
671
+ opts.tier1Summary,
672
+ "─────────────────────────────────────────────────────────────",
673
+ "",
674
+ opts.contextManifestPath ? `Full manifest: ${opts.contextManifestPath}` : ""
675
+ ].join("\n") : opts.contextManifestPath ? `Context manifest: ${opts.contextManifestPath}` : "Context manifest: (missing — inspect the diff directly: git diff origin/main...HEAD)",
676
+ "",
677
+ "How to review:",
678
+ "1. Read the diff — use the manifest risk ranking, `git diff` the high-risk files,",
679
+ " and read the surrounding code as needed.",
680
+ "2. Evaluate correctness, security, requirements/AC, and performance. Use the",
681
+ " severity + verdict vocabulary in roles/review.md.",
682
+ `3. Write your findings to ${reviewReportPath}.`,
683
+ "",
684
+ "Then signal the verdict with the Overdeck CLI (exactly one):",
685
+ ` pan admin specialists done review ${opts.issueId} --status passed --notes "<one-line summary>"`,
686
+ ` pan admin specialists done review ${opts.issueId} --status blocked --notes "<one-line top blocker>"`,
687
+ "",
688
+ "After running the signal command above, STOP and wait — do not exit, do not run",
689
+ "any further commands. The session stays open for the next review cycle.",
690
+ "",
691
+ "Reactive Cloister dispatches the test role after review passes. Never queue tests yourself and never edit code."
692
+ ].filter(Boolean).join("\n");
693
+ const sizeBytes = Buffer.byteLength(prompt, "utf-8");
694
+ console.log(`[review-agent] Self-review prompt for ${opts.issueId}: ${sizeBytes} bytes`);
695
+ return prompt;
696
+ }
342
697
  async function spawnReviewRoleForIssuePromise(opts) {
343
698
  const reviewSessionName = `agent-${opts.issueId.toLowerCase()}-review`;
344
699
  const mergedGuard = await shouldSkipDispatchAsMerged(opts.issueId);
@@ -356,6 +711,25 @@ async function spawnReviewRoleForIssuePromise(opts) {
356
711
  message
357
712
  };
358
713
  }
714
+ if (resolveReviewMode(opts.issueId) === "none") {
715
+ setReviewStatusSync(opts.issueId, {
716
+ reviewStatus: "skipped",
717
+ reviewNotes: "Review mode: none — AI review skipped by configuration; verification gate still enforced",
718
+ reviewSpawnedAt: (/* @__PURE__ */ new Date()).toISOString()
719
+ });
720
+ const message = `Review skipped for ${opts.issueId} (mode=none) — advancing to test`;
721
+ console.log(`[review-agent] ${message}`);
722
+ emitActivityEntrySync({
723
+ source: "review",
724
+ level: "info",
725
+ message,
726
+ issueId: opts.issueId
727
+ });
728
+ return {
729
+ success: true,
730
+ message
731
+ };
732
+ }
359
733
  try {
360
734
  if ((await Effect.runPromise(listSessionNames())).includes(reviewSessionName)) {
361
735
  const paneDead = await Effect.runPromise(isPaneDead(reviewSessionName));
@@ -375,14 +749,25 @@ async function spawnReviewRoleForIssuePromise(opts) {
375
749
  } catch (probeErr) {
376
750
  console.warn(`[review-agent] Could not probe ${reviewSessionName} runId, falling back to pane-alive idempotency:`, probeErr);
377
751
  }
378
- if (!paneDead && !opts.force && !staleRunId) {
752
+ let finishedIdle = false;
753
+ if (!paneDead && !opts.force && !staleRunId) try {
754
+ const status = getReviewStatusSync(opts.issueId);
755
+ const terminal = status?.reviewStatus === "passed" || status?.reviewStatus === "blocked" || status?.reviewStatus === "failed";
756
+ const newerRequest = !!status?.reviewRequestedAt && (!status.reviewSpawnedAt || status.reviewRequestedAt > status.reviewSpawnedAt);
757
+ finishedIdle = terminal && newerRequest;
758
+ if (finishedIdle) console.log(`[review-agent] ${reviewSessionName} is finished-idle (verdict ${status?.reviewStatus}, newer request pending) — warm-reusing for the new review cycle`);
759
+ else if (terminal) console.log(`[review-agent] ${reviewSessionName} has a terminal verdict (${status?.reviewStatus}) and no newer request — treating this dispatch as a stale duplicate; leaving the verdict intact`);
760
+ } catch (statusErr) {
761
+ console.warn(`[review-agent] Could not probe review status for finished-idle check on ${opts.issueId}:`, statusErr);
762
+ }
763
+ if (!paneDead && !opts.force && !staleRunId && !finishedIdle) {
379
764
  console.log(`[review-agent] Idempotency guard: ${reviewSessionName} already running for ${opts.issueId} — skipping spawn`);
380
765
  return {
381
766
  success: true,
382
767
  message: `Review already in progress: ${reviewSessionName}`
383
768
  };
384
769
  }
385
- const reason = opts.force ? "force-killed for re-review" : paneDead ? "pane is dead" : "stale runId";
770
+ const reason = opts.force ? "force-killed for re-review" : paneDead ? "pane is dead" : staleRunId ? "stale runId" : "finished-idle (warm reuse for new cycle)";
386
771
  console.log(`[review-agent] ${reviewSessionName} ${reason} — respawning convoy`);
387
772
  await Effect.runPromise(killAllReviewerSessions(void 0, opts.issueId).pipe(Effect.catch(() => Effect.succeed({
388
773
  killed: [],
@@ -420,7 +805,7 @@ async function spawnReviewRoleForIssuePromise(opts) {
420
805
  };
421
806
  }
422
807
  try {
423
- const { archiveFeedbackFiles } = await import("./feedback-writer-BvHE1I-3.js");
808
+ const { archiveFeedbackFiles } = await import("./feedback-writer-thrdxYpK.js");
424
809
  await Effect.runPromise(archiveFeedbackFiles(opts.workspace));
425
810
  } catch {}
426
811
  try {
@@ -437,7 +822,7 @@ async function spawnReviewRoleForIssuePromise(opts) {
437
822
  };
438
823
  }
439
824
  try {
440
- const { notifyPipelineSync } = await import("./pipeline-notifier-DQsOtdjZ.js");
825
+ const { notifyPipelineSync } = await import("./pipeline-notifier-lwMa--Gz.js");
441
826
  notifyPipelineSync({
442
827
  type: "task_queued",
443
828
  specialist: "review-agent",
@@ -445,7 +830,7 @@ async function spawnReviewRoleForIssuePromise(opts) {
445
830
  });
446
831
  } catch {}
447
832
  try {
448
- const { spawnRun, saveAgentState, getAgentState, getAgentStateSync, getLatestSessionIdSync, resumeAgent, wipeAgentStateDirs } = await import("./agents-KaEsWZ8D.js");
833
+ const { spawnRun, saveAgentState, getAgentState, getAgentStateSync, getLatestSessionIdSync, resumeAgent, wipeAgentStateDirs } = await import("./agents-BIggLvi_.js");
449
834
  const workAgentState = await Effect.runPromise(getAgentState(`agent-${opts.issueId.toLowerCase()}`));
450
835
  const allowHost = opts.allowHost === true || workAgentState?.hostOverride === true;
451
836
  let headSha = "unknown";
@@ -475,12 +860,23 @@ async function spawnReviewRoleForIssuePromise(opts) {
475
860
  console.warn(`[review-agent] Context manifest build failed for ${opts.issueId} — reviewers will block on missing shared context:`, ctxErr);
476
861
  }
477
862
  const fullReview = isExtendedReviewEnabled(opts.issueId);
863
+ const { inScope: inScopeSubRoles, carried: carriedSubRoles, scope: reReviewScope } = fullReview ? await computeConvoyScope(opts.issueId, opts.workspace) : {
864
+ inScope: [...REVIEW_SUB_ROLES],
865
+ carried: [],
866
+ scope: "changed"
867
+ };
868
+ const cfgReviewHarness = loadConfigSync().config.roles?.review?.harness;
869
+ const savedReviewHarness = getAgentStateSync(`agent-${opts.issueId.toLowerCase()}-review`)?.harness;
870
+ const discoveryForkMode = fullReview && (opts.harness ?? savedReviewHarness ?? cfgReviewHarness ?? "claude-code") === "claude-code";
478
871
  const prompt = fullReview ? buildReviewRolePrompt({
479
872
  ...opts,
480
873
  runId,
481
874
  reviewDir,
482
875
  contextManifestPath,
483
- tier1Summary
876
+ tier1Summary,
877
+ inScopeSubRoles,
878
+ carriedSubRoles,
879
+ discovery: discoveryForkMode
484
880
  }) : buildSelfReviewPrompt({
485
881
  ...opts,
486
882
  runId,
@@ -488,32 +884,40 @@ async function spawnReviewRoleForIssuePromise(opts) {
488
884
  contextManifestPath,
489
885
  tier1Summary
490
886
  });
491
- const spawnConvoyReviewers = async (synthesisAgentId) => {
492
- const reviewerResults = await Promise.all(REVIEW_SUB_ROLES.map(async (subRole) => {
493
- const outputPath = reviewerAgentOutputPath(opts.workspace, runId, subRole);
494
- const result = await Effect.runPromise(spawnReviewSubRoleForIssue({
495
- issueId: opts.issueId,
496
- workspace: opts.workspace,
497
- subRole,
498
- runId,
499
- outputPath,
500
- contextManifestPath,
501
- synthesisAgentId,
502
- ...opts.model ? { model: opts.model } : {},
503
- ...opts.harness ? { harness: opts.harness } : {},
504
- allowHost
505
- }));
506
- if (!result.success) try {
507
- const { messageAgent } = await import("./agents-KaEsWZ8D.js");
508
- await messageAgent(synthesisAgentId, `REVIEWER_FAILED ${subRole} ${result.error ?? result.message}`);
509
- } catch (signalErr) {
510
- console.warn(`[review-agent] Failed to signal ${subRole} spawn failure to ${synthesisAgentId}:`, signalErr);
887
+ const markDiscoveryPending = async (synthesisAgentId) => {
888
+ try {
889
+ const parent = getAgentStateSync(synthesisAgentId);
890
+ if (parent) {
891
+ parent.reviewDiscoveryPending = true;
892
+ parent.reviewContextManifestPath = contextManifestPath;
893
+ parent.reviewDiscoveryReadyAt = void 0;
894
+ parent.reviewConvoyForkedAt = void 0;
895
+ parent.reviewForkCacheChecked = void 0;
896
+ await Effect.runPromise(saveAgentState(parent));
511
897
  }
512
- return result;
513
- }));
514
- const failedReviewers = reviewerResults.filter((r) => !r.success);
515
- if (failedReviewers.length > 0) console.warn(`[review-agent] Review role spawned for ${opts.issueId}, but ${failedReviewers.length} reviewer(s) failed to spawn`);
516
- return reviewerResults;
898
+ } catch (stateErr) {
899
+ console.warn(`[review-agent] Could not mark discovery pending on ${synthesisAgentId}:`, stateErr);
900
+ }
901
+ };
902
+ const spawnConvoyReviewers = async (synthesisAgentId) => {
903
+ if (discoveryForkMode) {
904
+ await markDiscoveryPending(synthesisAgentId);
905
+ console.log(`[review-agent] ${opts.issueId}: parent spawned in discovery mode — convoy defers to the discovery-ready signal (PAN-1862)`);
906
+ return [];
907
+ }
908
+ return launchConvoyReviewersPromise({
909
+ issueId: opts.issueId,
910
+ workspace: opts.workspace,
911
+ runId,
912
+ synthesisAgentId,
913
+ inScope: inScopeSubRoles,
914
+ carried: carriedSubRoles,
915
+ scope: reReviewScope,
916
+ contextManifestPath,
917
+ ...opts.model ? { model: opts.model } : {},
918
+ ...opts.harness ? { harness: opts.harness } : {},
919
+ allowHost
920
+ });
517
921
  };
518
922
  const reviewAgentId = `agent-${opts.issueId.toLowerCase()}-review`;
519
923
  const savedReview = getAgentStateSync(reviewAgentId);
@@ -715,9 +1119,10 @@ function resolveReviewMode(issueId) {
715
1119
  if (issueId) {
716
1120
  const project = resolveProjectForIssue(issueId);
717
1121
  const issueMode = project ? readIssueRecordSync(project, issueId)?.reviewMode : void 0;
718
- if (issueMode === "quick" || issueMode === "full") return issueMode;
1122
+ if (issueMode === "quick" || issueMode === "full" || issueMode === "none") return issueMode;
719
1123
  }
720
- return loadConfigSync().config.roles?.review?.mode === "full" ? "full" : "quick";
1124
+ const configMode = loadConfigSync().config.roles?.review?.mode;
1125
+ return configMode === "full" || configMode === "none" ? configMode : "quick";
721
1126
  }
722
1127
  /**
723
1128
  * Is EXTENDED (convoy) review enabled for this issue?
@@ -747,7 +1152,7 @@ async function purgeReviewAgentsForIssue(projectKey, issueId) {
747
1152
  removed
748
1153
  };
749
1154
  }
750
- var execAsync, REVIEWER_TIMEOUT_MS, buildConvoyPrompt, spawnReviewSubRoleForIssue, spawnReviewRoleForIssue, killAllReviewerSessions, killAllReviewSessions;
1155
+ var execAsync, spawnReviewRoleForIssue, killAllReviewerSessions, killAllReviewSessions;
751
1156
  var init_review_agent = __esmMin((() => {
752
1157
  init_tmux();
753
1158
  init_activity_logger();
@@ -758,20 +1163,17 @@ var init_review_agent = __esmMin((() => {
758
1163
  init_conflict_gate();
759
1164
  init_review_monitor();
760
1165
  init_review_resume_decision();
1166
+ init_review_convoy();
761
1167
  init_merge_verification();
762
1168
  init_record();
763
1169
  init_types();
764
- init_paths();
765
1170
  init_agents$1();
766
1171
  execAsync = promisify(exec);
767
- REVIEWER_TIMEOUT_MS = 1200 * 1e3;
768
- buildConvoyPrompt = (opts) => Effect.promise(() => buildConvoyPromptPromise(opts));
769
- spawnReviewSubRoleForIssue = (opts) => Effect.promise(() => spawnReviewSubRoleForIssuePromise(opts));
770
1172
  spawnReviewRoleForIssue = (opts) => Effect.promise(() => spawnReviewRoleForIssuePromise(opts));
771
1173
  killAllReviewerSessions = (projectKey, issueId) => Effect.promise(() => killAllReviewerSessionsPromise(projectKey, issueId));
772
1174
  killAllReviewSessions = () => Effect.promise(() => killAllReviewSessionsPromise());
773
1175
  }));
774
1176
  //#endregion
775
- export { isReviewStaleSync as a, purgeReviewAgentsForIssue as c, spawnReviewSubRoleForIssue as d, reviewResumeDecision as f, isReviewSessionForIssue as i, resolveReviewMode as l, init_review_agent as n, killAllReviewSessions as o, isExtendedReviewEnabled as r, killAllReviewerSessions as s, buildConvoyPrompt as t, spawnReviewRoleForIssue as u };
1177
+ export { killAllReviewSessions as a, resolveReviewMode as c, handleReviewDiscoveryReady as d, resolveReReviewScope as f, isReviewStaleSync as i, spawnReviewRoleForIssue as l, reviewResumeDecision as m, isExtendedReviewEnabled as n, killAllReviewerSessions as o, spawnReviewSubRoleForIssue as p, isReviewSessionForIssue as r, purgeReviewAgentsForIssue as s, init_review_agent as t, buildConvoyPrompt as u };
776
1178
 
777
- //# sourceMappingURL=review-agent-C-A6IgXc.js.map
1179
+ //# sourceMappingURL=review-agent-phzqNqIs.js.map