@qwen-code/qwen-code 0.21.6-preview.0 → 0.21.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/bundled/qc-helper/docs/features/channels/github.md +31 -19
  2. package/bundled/qc-helper/docs/features/code-review.md +3 -1
  3. package/bundled/review/SKILL.md +16 -11
  4. package/chunks/{MaxSizedBox-A3UYJS6B.js → MaxSizedBox-2HFKP4LI.js} +8 -8
  5. package/chunks/{StandaloneSessionPicker-NGLY26I4.js → StandaloneSessionPicker-RBV72M5N.js} +23 -23
  6. package/chunks/{acp-startup-profiler-3RICG2YW.js → acp-startup-profiler-ORIQ2CCQ.js} +2 -2
  7. package/chunks/{acpAgent-V54T2EEL.js → acpAgent-WO6JFCVQ.js} +1059 -118
  8. package/chunks/{agent-2P53VL2L.js → agent-AHGLYNZ4.js} +8 -8
  9. package/chunks/{agent-headless-6X4GCFRD.js → agent-headless-NTXKKGRO.js} +8 -8
  10. package/chunks/{bridge-TCFMLKHR.js → bridge-RPAU64CA.js} +13 -13
  11. package/chunks/{channel-management-service-5XPPTWUQ.js → channel-management-service-IGEUOVRT.js} +1 -1
  12. package/chunks/{channel-settings-store-B4HNMNQV.js → channel-settings-store-ON64MF7G.js} +15 -15
  13. package/chunks/{channel-worker-group-SVGPDH2C.js → channel-worker-group-JWQK224X.js} +5 -5
  14. package/chunks/{channel-worker-manager-72ZK2GTS.js → channel-worker-manager-77E3OXRQ.js} +5 -5
  15. package/chunks/{channel-worker-supervisor-NUEDVHX4.js → channel-worker-supervisor-62YWUGP2.js} +3 -3
  16. package/chunks/{chunk-AFZTZLFB.js → chunk-2POQWYM6.js} +2 -2
  17. package/chunks/{chunk-RTWF7FF7.js → chunk-3LZKY4V4.js} +3 -3
  18. package/chunks/{chunk-T4XY5CT4.js → chunk-3UOLYNTF.js} +5 -5
  19. package/chunks/{chunk-WAOLM6SQ.js → chunk-4JH77A2U.js} +1 -1
  20. package/chunks/{chunk-MISUEWB4.js → chunk-4S4OEQ6U.js} +10 -6
  21. package/chunks/{chunk-URJHXOSO.js → chunk-4WTAQEHV.js} +1 -1
  22. package/chunks/{chunk-BU4BRCPX.js → chunk-536SWZTA.js} +5 -5
  23. package/chunks/{chunk-6KEN3RIC.js → chunk-5MJGUQU5.js} +3 -3
  24. package/chunks/{chunk-Z5S6KH2B.js → chunk-75QMRMO7.js} +4 -4
  25. package/chunks/{chunk-DOA7MCDY.js → chunk-A4VTILZT.js} +898 -847
  26. package/chunks/{chunk-72DZPDH4.js → chunk-ACZRB7AD.js} +8 -3
  27. package/chunks/{chunk-P7LKADIT.js → chunk-BOGOR4HB.js} +5 -5
  28. package/chunks/{chunk-QL4TN4HS.js → chunk-BRVWYMKV.js} +1 -1
  29. package/chunks/{chunk-7FUVSN4D.js → chunk-C4CBJQKY.js} +1 -1
  30. package/chunks/{chunk-X6DV3WKN.js → chunk-CA4UIDFU.js} +1 -1
  31. package/chunks/{chunk-MVLM6PJK.js → chunk-CJ5WLD5Y.js} +6 -2
  32. package/chunks/{chunk-6D6V55ZQ.js → chunk-DIT4V3XH.js} +1 -1
  33. package/chunks/{chunk-DOICUTPO.js → chunk-DVBEGGLG.js} +8 -8
  34. package/chunks/{chunk-DTAPI453.js → chunk-EMYZIABH.js} +1 -1
  35. package/chunks/{chunk-4E5PO6R7.js → chunk-EXCEQD22.js} +3 -3
  36. package/chunks/{chunk-EHMN6SEG.js → chunk-FZFP7RZI.js} +3 -3
  37. package/chunks/{chunk-C4GRKMUL.js → chunk-G5NNWEYE.js} +5 -5
  38. package/chunks/{chunk-QWUYFMAR.js → chunk-GESMMPAK.js} +33 -33
  39. package/chunks/{chunk-WPKIU4PA.js → chunk-GK2H5GRC.js} +4 -4
  40. package/chunks/{chunk-SQ3ZJOYL.js → chunk-GWRHVJY2.js} +11 -11
  41. package/chunks/{chunk-BK2UNYWD.js → chunk-HIBNSEJE.js} +12 -0
  42. package/chunks/{chunk-5CDI4UOY.js → chunk-HY25ULVN.js} +1 -1
  43. package/chunks/{chunk-IISDPZ5X.js → chunk-IMOQO6YL.js} +1 -1
  44. package/chunks/{chunk-ZQL73PPE.js → chunk-JE44IPH6.js} +1 -1
  45. package/chunks/{chunk-NYZAL2W2.js → chunk-K2B3X3E7.js} +3 -3
  46. package/chunks/{chunk-OWAK7LMW.js → chunk-KGJGEEVR.js} +7 -0
  47. package/chunks/{chunk-546CDN6D.js → chunk-KHUA3NQV.js} +2 -2
  48. package/chunks/{chunk-7GYP5COR.js → chunk-LAAFLUQV.js} +1 -1
  49. package/chunks/{chunk-XNZBXQCG.js → chunk-MKVZE4ZJ.js} +1 -1
  50. package/chunks/{chunk-N47ZM2KI.js → chunk-N2GJU6KI.js} +9 -9
  51. package/chunks/{chunk-WIPQR44Y.js → chunk-NGJOAKJY.js} +3 -3
  52. package/chunks/chunk-NKLP3DCK.js +22 -0
  53. package/chunks/{chunk-3ZRS2XNY.js → chunk-NKSF7HYF.js} +1 -1
  54. package/chunks/{chunk-HKNSU4WX.js → chunk-O7V7N4G7.js} +1 -1
  55. package/chunks/{chunk-CJBRIJ7W.js → chunk-ODPXHGLL.js} +2 -2
  56. package/chunks/{chunk-4T6QMNX2.js → chunk-OP2OHZ7K.js} +183 -10
  57. package/chunks/{chunk-CDHNGCJI.js → chunk-OWSW7EYP.js} +5 -5
  58. package/chunks/{chunk-FDV3CXTD.js → chunk-OXX3FG2N.js} +2 -2
  59. package/chunks/{chunk-YUVTZ4UH.js → chunk-PPUOYL77.js} +70 -5
  60. package/chunks/{chunk-O656RSMC.js → chunk-PX5DNLSA.js} +1 -1
  61. package/chunks/{chunk-6KZP75GT.js → chunk-Q5RM32DR.js} +1 -1
  62. package/chunks/{chunk-AU3XNTMV.js → chunk-QZKYZCN3.js} +1 -1
  63. package/chunks/{chunk-UKZEXS6K.js → chunk-R574ATRM.js} +11 -0
  64. package/chunks/{chunk-XKTCA6BW.js → chunk-R5RBXLNC.js} +3 -3
  65. package/chunks/{chunk-NAYPZ72V.js → chunk-RFUHDCNF.js} +1 -1
  66. package/chunks/{chunk-QG2ACINA.js → chunk-RHTTKJTP.js} +1 -1
  67. package/chunks/{chunk-IKXE3AAC.js → chunk-RK2EE3T7.js} +1 -1
  68. package/chunks/{chunk-3DTM3RPU.js → chunk-S7CV4KO6.js} +3 -3
  69. package/chunks/{chunk-ZH7G3A4U.js → chunk-SKNE3KQC.js} +3 -3
  70. package/chunks/{chunk-PQTK2FVO.js → chunk-SLSWFHDF.js} +3 -3
  71. package/chunks/{chunk-2U7GPHA6.js → chunk-SQC6K5HI.js} +1 -1
  72. package/chunks/{chunk-Y5HIDFKZ.js → chunk-SQOMTWQT.js} +4 -4
  73. package/chunks/{chunk-CXYBX4AL.js → chunk-SUKEUUAA.js} +1 -1
  74. package/chunks/{chunk-WXS647W5.js → chunk-T4JSA7KU.js} +2 -2
  75. package/chunks/{chunk-I7JDGNG6.js → chunk-T5U6IM4C.js} +6 -2
  76. package/chunks/{chunk-TVFC3XF5.js → chunk-TGGEZINK.js} +5 -5
  77. package/chunks/{chunk-AVDEBBMI.js → chunk-TOGZTG4X.js} +2 -2
  78. package/chunks/{chunk-A6SX5TAH.js → chunk-TSERKWCX.js} +6 -2
  79. package/chunks/{chunk-XSGQKR37.js → chunk-U4AF3QLU.js} +355 -17
  80. package/chunks/{chunk-WIRAPZ62.js → chunk-UGTWD35F.js} +7 -1
  81. package/chunks/{chunk-DG563ZCS.js → chunk-ULPQQSDN.js} +2 -2
  82. package/chunks/{chunk-DBIEZC7T.js → chunk-VGFPFM4U.js} +3 -3
  83. package/chunks/{chunk-VDLXPEI5.js → chunk-VNQCPBC2.js} +3 -3
  84. package/chunks/{chunk-WVRJKSIG.js → chunk-VSALQLT7.js} +1 -1
  85. package/chunks/{chunk-EKWNNQQD.js → chunk-W5DXUTXD.js} +12 -6
  86. package/chunks/{chunk-M744OFVE.js → chunk-W7U4ESW2.js} +1 -1
  87. package/chunks/{chunk-MFBUJMQ3.js → chunk-WNU7TZTO.js} +4 -4
  88. package/chunks/{chunk-GTM6IHBB.js → chunk-WO2B5E5B.js} +1 -0
  89. package/chunks/{chunk-SPUDIAHX.js → chunk-XA4TMLFN.js} +11 -11
  90. package/chunks/{chunk-XOZ2R6XI.js → chunk-XM2O73NC.js} +1245 -295
  91. package/chunks/{chunk-NKST54XA.js → chunk-YMBOEAF4.js} +1 -1
  92. package/chunks/{chunk-QONSRAEV.js → chunk-YP5KH5Y7.js} +1 -1
  93. package/chunks/{chunk-XZCMQUOF.js → chunk-YZQTA3ID.js} +20 -11
  94. package/chunks/{computer-use-GTOP2CVH.js → computer-use-5HXJ2P4X.js} +8 -8
  95. package/chunks/{config-utils-LIRO7NSU.js → config-utils-VXD4SPVR.js} +2 -2
  96. package/chunks/{contextCommand-K6T6RRF3.js → contextCommand-7BEHRX2H.js} +11 -11
  97. package/chunks/{core-runtime-D2626QQU.js → core-runtime-U4VJ5TIV.js} +8 -8
  98. package/chunks/create-sub-session-QZNQY332.js +772 -0
  99. package/chunks/{daemon-CCIX4BMG.js → daemon-YI5RY62O.js} +115 -3
  100. package/chunks/{daemon-status-provider-2EHRZZVF.js → daemon-status-provider-UJUGTDTL.js} +17 -17
  101. package/chunks/{daemon-trust-policy-B3EPDJDR.js → daemon-trust-policy-ZHDD5VYQ.js} +14 -14
  102. package/chunks/{daemon-trust-policy-monitor-MFM5X26G.js → daemon-trust-policy-monitor-5SHYBDGA.js} +14 -14
  103. package/chunks/{deferred-core-runtime-KXN7HLN7.js → deferred-core-runtime-QWAEBTR5.js} +8 -8
  104. package/chunks/discovery-XLHITE74.js +220 -0
  105. package/chunks/{dist-IKGVITP3.js → dist-KS4O2NKE.js} +99 -6
  106. package/chunks/{earlyInputCapture-WUNYYFOS.js → earlyInputCapture-5BMSGKOI.js} +8 -8
  107. package/chunks/{edit-DMFCBP2D.js → edit-IVQQVYYK.js} +8 -8
  108. package/chunks/{enter-worktree-5SVBCXFC.js → enter-worktree-P3DF2N6O.js} +8 -8
  109. package/chunks/{enterPlanMode-QUIZFQ4M.js → enterPlanMode-KKTDVLAD.js} +8 -8
  110. package/chunks/{environment-U6QP23VJ.js → environment-W5TRDM3G.js} +11 -11
  111. package/chunks/{errors-GZWFA6ON.js → errors-GJJB36IG.js} +11 -11
  112. package/chunks/{exit-worktree-FUB44KAF.js → exit-worktree-LV5RLOCU.js} +8 -8
  113. package/chunks/{exitPlanMode-XSHHYR73.js → exitPlanMode-TUGOB2LL.js} +8 -8
  114. package/chunks/{fast-path-JHQJSIMZ.js → fast-path-2FU23PAQ.js} +2 -2
  115. package/chunks/{gemini-O44ETOKT.js → gemini-KDULDQPP.js} +47 -47
  116. package/chunks/{geminiContentGenerator-TTM4TZJM.js → geminiContentGenerator-LOCFHNVA.js} +1 -1
  117. package/chunks/{glob-YECOWTRW.js → glob-Z4NQFKWS.js} +8 -8
  118. package/chunks/{grep-BZO4LOTA.js → grep-Z67Z7EN6.js} +8 -8
  119. package/chunks/{handleAutoUpdate-TOO52D6H.js → handleAutoUpdate-DFUZE6I6.js} +13 -13
  120. package/chunks/{i18n-ARJYXZQ5.js → i18n-R4FMZ7N2.js} +10 -10
  121. package/chunks/{image-gen-J6Q2YBEU.js → image-gen-4CQJPQP5.js} +1 -1
  122. package/chunks/{initializer-CEZ4RPQV.js → initializer-DK672ZVE.js} +14 -14
  123. package/chunks/{installationInfo-AEGIIQAT.js → installationInfo-PO4Z3ES7.js} +9 -9
  124. package/chunks/{list-7XLPV5GC.js → list-QXQF6C53.js} +17 -17
  125. package/chunks/{loadedSettingsAdapter-YK5SBHOT.js → loadedSettingsAdapter-4D7GUGW6.js} +14 -14
  126. package/chunks/{loggingContentGenerator-I7QDXS43.js → loggingContentGenerator-2P3MNACM.js} +3 -3
  127. package/chunks/{managed-npm-update-YSL7PA7G.js → managed-npm-update-LWVJQTWO.js} +21 -12
  128. package/chunks/{mcp-RKFQZXP6.js → mcp-GHETAR6V.js} +14 -14
  129. package/chunks/{monitor-QHHJIKGL.js → monitor-4T7W4M6Q.js} +8 -8
  130. package/chunks/{nonInteractiveCli-XEBIE7MG.js → nonInteractiveCli-P4UKCJFM.js} +42 -42
  131. package/chunks/{notebook-edit-SG7X2EQA.js → notebook-edit-OC2V7U5D.js} +8 -8
  132. package/chunks/{openaiContentGenerator-63CVR33K.js → openaiContentGenerator-RAJUFWQY.js} +3 -3
  133. package/chunks/{pidfile-I3CXJGQD.js → pidfile-HVPYVRLS.js} +8 -8
  134. package/chunks/{processUtils-LJ3DSANX.js → processUtils-VIQ4JHVX.js} +2 -2
  135. package/chunks/{qwenContentGenerator-JINBVCH6.js → qwenContentGenerator-2QLCUFNZ.js} +9 -9
  136. package/chunks/{qwenOAuth2-SY2O3NRR.js → qwenOAuth2-J2X3EN43.js} +1 -1
  137. package/chunks/{read-file-PGTXF25I.js → read-file-ZNAN2B26.js} +2 -2
  138. package/chunks/{resumeHistoryUtils-FB2NFVZ2.js → resumeHistoryUtils-RCY7AL5Y.js} +12 -12
  139. package/chunks/{ripGrep-IY3KGPM6.js → ripGrep-C3KMLZM5.js} +8 -8
  140. package/chunks/{run-qwen-serve-UYEMGPKA.js → run-qwen-serve-3JN75CIQ.js} +481 -74
  141. package/chunks/{runtime-CG3BKRFE.js → runtime-VUA4WQYD.js} +17 -17
  142. package/chunks/{scheduler-VFUVGDE5.js → scheduler-Z4IBXCOY.js} +8 -8
  143. package/chunks/{serve-ZCCQ2G2L.js → serve-67T3P7XI.js} +14 -14
  144. package/chunks/{server-WS7LWXPP.js → server-46ZO2CLV.js} +7648 -596
  145. package/chunks/{session-IQLCT32T.js → session-B4IFAFC4.js} +45 -45
  146. package/chunks/{settings-NX4EUIE6.js → settings-AI2BTBOZ.js} +13 -13
  147. package/chunks/{shell-THDYM4CS.js → shell-BKII3B6E.js} +8 -8
  148. package/chunks/{skill-OXXZBNQB.js → skill-6CFOWVGA.js} +3 -3
  149. package/chunks/{skill-settings-T3JZ33T2.js → skill-settings-6BFQWMW4.js} +13 -13
  150. package/chunks/{spawnChannel-COLJMSA7.js → spawnChannel-FJXW35U7.js} +10 -10
  151. package/chunks/{standalone-update-ICW7H5IF.js → standalone-update-WVINHRNS.js} +11 -11
  152. package/chunks/{startInteractiveUI-6BDRXSMF.js → startInteractiveUI-YE57CJ57.js} +132 -132
  153. package/chunks/{stdioHelpers-HGIYTWAY.js → stdioHelpers-7A2EE64Z.js} +5 -3
  154. package/chunks/{task-create-2X4UP4F3.js → task-create-Q727MXHJ.js} +2 -2
  155. package/chunks/{task-list-WOLJPZ64.js → task-list-G6KPQ5JT.js} +1 -1
  156. package/chunks/{task-update-VDUSN36E.js → task-update-YB7PXO4R.js} +2 -2
  157. package/chunks/{team-create-BCSMDK4Z.js → team-create-GNC7NFY6.js} +8 -8
  158. package/chunks/{team-delete-D2VMSDOT.js → team-delete-GDO7H2T4.js} +1 -1
  159. package/chunks/{team-plan-approval-B5YRLJFV.js → team-plan-approval-ECALJLIO.js} +8 -8
  160. package/chunks/{terminal-image-renderer-PW6Z6VFY.js → terminal-image-renderer-II74TFVW.js} +8 -8
  161. package/chunks/{theme-manager-CMVKD2JH.js → theme-manager-2MGEDD22.js} +8 -8
  162. package/chunks/{tool-search-SQTUSG6P.js → tool-search-S6LRRACA.js} +2 -2
  163. package/chunks/{total-session-admission-XAXOSE46.js → total-session-admission-7WVAWQPU.js} +13 -13
  164. package/chunks/{trustedFolders-Z2UAEG2V.js → trustedFolders-NFS4KHO4.js} +10 -10
  165. package/chunks/{update-relaunch-JBLI6LJF.js → update-relaunch-Q5HLZ6UW.js} +6 -6
  166. package/chunks/{updateCheck-FDAVGOFT.js → updateCheck-UOVZSTP7.js} +12 -12
  167. package/chunks/{useAutoAcceptIndicator-PDZFIYRM.js → useAutoAcceptIndicator-PC6MOJCO.js} +16 -16
  168. package/chunks/{validateNonInterActiveAuth-Q4763ONQ.js → validateNonInterActiveAuth-YMQP3ZM7.js} +39 -39
  169. package/chunks/{version-C7MPCGWD.js → version-T4AQFZJH.js} +1 -1
  170. package/chunks/{web-fetch-L7RAPOJB.js → web-fetch-JQCJHEEX.js} +2 -2
  171. package/chunks/{web-search-IDOYUOWX.js → web-search-QGZ2KY4G.js} +2 -2
  172. package/chunks/{workflow-HXURUJB5.js → workflow-YIT27YWZ.js} +9 -9
  173. package/chunks/{workspace-providers-status-JZ3GPWNU.js → workspace-providers-status-FIDZQ2PL.js} +17 -17
  174. package/chunks/{workspace-registration-store-SM2PWB6L.js → workspace-registration-store-RCSPE4DU.js} +1 -1
  175. package/chunks/{workspace-registry-6W4ES7BJ.js → workspace-registry-5PEUCY6E.js} +13 -13
  176. package/chunks/{workspace-service-V47ZFJRX.js → workspace-service-LANDVPL7.js} +18 -18
  177. package/chunks/{workspace-skills-status-6ZQ45XKA.js → workspace-skills-status-2IQVJNIN.js} +15 -15
  178. package/chunks/{workspace-trust-reconciler-6V25LMCN.js → workspace-trust-reconciler-CZPZZCZC.js} +22 -22
  179. package/chunks/{write-file-H2QOF25K.js → write-file-G5VNGCOG.js} +8 -8
  180. package/chunks/{zoom-image-JTUSS43N.js → zoom-image-6RBLD7X6.js} +2 -2
  181. package/cli.js +15 -15
  182. package/package.json +3 -3
  183. package/web-shell/assets/{arc-DtI1rZcQ.js → arc-B-Vtkp1W.js} +1 -1
  184. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BPZwSVct.js → architectureDiagram-3BPJPVTR-qmTXIj64.js} +1 -1
  185. package/web-shell/assets/{blockDiagram-GPEHLZMM-BIQ03j4C.js → blockDiagram-GPEHLZMM-ZlnXEtdP.js} +1 -1
  186. package/web-shell/assets/{c4Diagram-AAUBKEIU-CB0RyFGm.js → c4Diagram-AAUBKEIU-Wyoirf6Z.js} +1 -1
  187. package/web-shell/assets/channel-DXaHnfjS.js +1 -0
  188. package/web-shell/assets/{chunk-2J33WTMH-B3WoS-4H.js → chunk-2J33WTMH-WQwbq9d8.js} +1 -1
  189. package/web-shell/assets/{chunk-4BX2VUAB-C98xYZ1X.js → chunk-4BX2VUAB-DQKnAXC4.js} +1 -1
  190. package/web-shell/assets/{chunk-55IACEB6-CbTIWRwQ.js → chunk-55IACEB6-DIdgXNcO.js} +1 -1
  191. package/web-shell/assets/{chunk-727SXJPM-DWGnKTPu.js → chunk-727SXJPM-CUwGOLEd.js} +1 -1
  192. package/web-shell/assets/{chunk-AQP2D5EJ-4__QyCEX.js → chunk-AQP2D5EJ-CCBGZFZ4.js} +1 -1
  193. package/web-shell/assets/{chunk-FMBD7UC4-DFtG1YCW.js → chunk-FMBD7UC4-DMGXProk.js} +1 -1
  194. package/web-shell/assets/{chunk-ND2GUHAM-rvAhW51N.js → chunk-ND2GUHAM-yejcFqsh.js} +1 -1
  195. package/web-shell/assets/{chunk-QZHKN3VN-DfiU9pwZ.js → chunk-QZHKN3VN-DxCyqTf7.js} +1 -1
  196. package/web-shell/assets/classDiagram-4FO5ZUOK-BigU82A0.js +1 -0
  197. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BigU82A0.js +1 -0
  198. package/web-shell/assets/{cose-bilkent-S5V4N54A-Cc4EIdxu.js → cose-bilkent-S5V4N54A-DOrF3cg_.js} +1 -1
  199. package/web-shell/assets/{dagre-BM42HDAG-CZNj4dGW.js → dagre-BM42HDAG-Be6CdYQ_.js} +1 -1
  200. package/web-shell/assets/{diagram-2AECGRRQ-D5tiqQCr.js → diagram-2AECGRRQ-B_Rjsft2.js} +1 -1
  201. package/web-shell/assets/{diagram-5GNKFQAL-pwzw0jVO.js → diagram-5GNKFQAL-BvQbKSm1.js} +1 -1
  202. package/web-shell/assets/{diagram-KO2AKTUF-4CWiM00x.js → diagram-KO2AKTUF-BsdmMdpS.js} +1 -1
  203. package/web-shell/assets/{diagram-LMA3HP47-Dd7rc7Qf.js → diagram-LMA3HP47-CrQlBaNr.js} +1 -1
  204. package/web-shell/assets/{diagram-OG6HWLK6-_vzV52ml.js → diagram-OG6HWLK6-aB1MD_DL.js} +1 -1
  205. package/web-shell/assets/{erDiagram-TEJ5UH35-CqbE2bx_.js → erDiagram-TEJ5UH35-F-eUUn9n.js} +1 -1
  206. package/web-shell/assets/{flowDiagram-I6XJVG4X-CaxNr7w4.js → flowDiagram-I6XJVG4X-DY_d8lUK.js} +1 -1
  207. package/web-shell/assets/{ganttDiagram-6RSMTGT7-AGjrtfUA.js → ganttDiagram-6RSMTGT7-Dqu7KBPg.js} +1 -1
  208. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-ADG2zSkc.js → gitGraphDiagram-PVQCEYII-2IkU_VEj.js} +1 -1
  209. package/web-shell/assets/{index-BOryKCqt.js → index-BuSbqggh.js} +1 -1
  210. package/web-shell/assets/index-DrfC2e9s.js +1768 -0
  211. package/web-shell/assets/index-QQlUCJGg.css +5 -0
  212. package/web-shell/assets/{infoDiagram-5YYISTIA-CE3B_IoZ.js → infoDiagram-5YYISTIA-C4orwzPw.js} +1 -1
  213. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CN-Frhoi.js → ishikawaDiagram-YF4QCWOH-fXUEfef_.js} +1 -1
  214. package/web-shell/assets/{journeyDiagram-JHISSGLW-CGgezS93.js → journeyDiagram-JHISSGLW-Bs0I1_J5.js} +1 -1
  215. package/web-shell/assets/{kanban-definition-UN3LZRKU-BqWijky5.js → kanban-definition-UN3LZRKU-BPRj1dw_.js} +1 -1
  216. package/web-shell/assets/{linear-D8sfpZf6.js → linear-DFS6ZDpW.js} +1 -1
  217. package/web-shell/assets/{mermaid.core-3PA4QrzM.js → mermaid.core-CZxjWMaO.js} +5 -5
  218. package/web-shell/assets/{mindmap-definition-RKZ34NQL-D9QxwiCY.js → mindmap-definition-RKZ34NQL-Dsr3PmNs.js} +1 -1
  219. package/web-shell/assets/{pieDiagram-4H26LBE5-Bioaf6uE.js → pieDiagram-4H26LBE5-D5Ngpz5Y.js} +1 -1
  220. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DBb2AS73.js → quadrantDiagram-W4KKPZXB-WJK9I25z.js} +1 -1
  221. package/web-shell/assets/{requirementDiagram-4Y6WPE33-DXOvZ3KB.js → requirementDiagram-4Y6WPE33-CmrYcwOH.js} +1 -1
  222. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-D9qg09Dm.js → sankeyDiagram-5OEKKPKP-7SjCc4Mv.js} +1 -1
  223. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DSAUIfpw.js → sequenceDiagram-3UESZ5HK-Dl9E0IRM.js} +1 -1
  224. package/web-shell/assets/{stateDiagram-AJRCARHV-BPZkzfQ3.js → stateDiagram-AJRCARHV-CRRio7yV.js} +1 -1
  225. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-1atT7XaU.js +1 -0
  226. package/web-shell/assets/{timeline-definition-PNZ67QCA-UDaQp9sP.js → timeline-definition-PNZ67QCA-DVyXjjfq.js} +1 -1
  227. package/web-shell/assets/{vennDiagram-CIIHVFJN-2ouhAnHO.js → vennDiagram-CIIHVFJN-Nb2Lckzq.js} +1 -1
  228. package/web-shell/assets/{wardley-L42UT6IY-Cq_WEvTK.js → wardley-L42UT6IY-DuL_otIP.js} +1 -1
  229. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Dt24aXOM.js → wardleyDiagram-YWT4CUSO-DVI9Q4Aa.js} +1 -1
  230. package/web-shell/assets/{xychartDiagram-2RQKCTM6-A5Xk2WCH.js → xychartDiagram-2RQKCTM6-BNjAm7KD.js} +1 -1
  231. package/web-shell/index.html +2 -2
  232. package/chunks/create-sub-session-MWUWNBM6.js +0 -401
  233. package/web-shell/assets/channel-vfbVFuM1.js +0 -1
  234. package/web-shell/assets/classDiagram-4FO5ZUOK-Cvr8atq3.js +0 -1
  235. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Cvr8atq3.js +0 -1
  236. package/web-shell/assets/index-Cb1LjsCv.css +0 -5
  237. package/web-shell/assets/index-CvJDaIy8.js +0 -1756
  238. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DInOqnhZ.js +0 -1
@@ -2,13 +2,13 @@
2
2
  "use strict";
3
3
  import {
4
4
  serveCommand
5
- } from "./chunk-WPKIU4PA.js";
5
+ } from "./chunk-GK2H5GRC.js";
6
6
  import {
7
7
  listCommand
8
- } from "./chunk-BU4BRCPX.js";
8
+ } from "./chunk-536SWZTA.js";
9
9
  import {
10
10
  getErrorMessage as getErrorMessage2
11
- } from "./chunk-EHMN6SEG.js";
11
+ } from "./chunk-FZFP7RZI.js";
12
12
  import {
13
13
  ObservedChannelContactStore
14
14
  } from "./chunk-DYA25Y7U.js";
@@ -24,6 +24,11 @@ import {
24
24
  import {
25
25
  isLoopbackBind
26
26
  } from "./chunk-RXFQM6FQ.js";
27
+ import {
28
+ collectProviderModelsForProtocol,
29
+ getAuthTypeFromEnv,
30
+ resolveCliGenerationConfig
31
+ } from "./chunk-5MJGUQU5.js";
27
32
  import {
28
33
  resolvePath
29
34
  } from "./chunk-JELIWHXD.js";
@@ -46,22 +51,17 @@ import {
46
51
  registerToolCallDispatch,
47
52
  selectFirstModel,
48
53
  sessionsPath
49
- } from "./chunk-CDHNGCJI.js";
54
+ } from "./chunk-OWSW7EYP.js";
50
55
  import {
51
56
  getExtensionManager,
52
57
  requestChoicePluginNonInteractive,
53
58
  requestConsentNonInteractive,
54
59
  requestConsentOrFail,
55
60
  resolveExtensionCommandScope
56
- } from "./chunk-C4GRKMUL.js";
57
- import {
58
- collectProviderModelsForProtocol,
59
- getAuthTypeFromEnv,
60
- resolveCliGenerationConfig
61
- } from "./chunk-6KEN3RIC.js";
61
+ } from "./chunk-G5NNWEYE.js";
62
62
  import {
63
63
  parseChannelConfig
64
- } from "./chunk-7GYP5COR.js";
64
+ } from "./chunk-LAAFLUQV.js";
65
65
  import {
66
66
  findCliEntryPath
67
67
  } from "./chunk-V6WHFGST.js";
@@ -88,7 +88,7 @@ import {
88
88
  isChannelDeliveryMessage,
89
89
  isChannelStartupReportAckMessage,
90
90
  isChannelWebhookTaskMessage
91
- } from "./chunk-QONSRAEV.js";
91
+ } from "./chunk-YP5KH5Y7.js";
92
92
  import {
93
93
  normalizeWorkerDiagnostic,
94
94
  sanitizeWorkerDiagnostic
@@ -131,29 +131,29 @@ import {
131
131
  assembleMcpServers,
132
132
  getPendingGatedMcpServers,
133
133
  mcpCommand
134
- } from "./chunk-T4XY5CT4.js";
134
+ } from "./chunk-3UOLYNTF.js";
135
135
  import {
136
136
  loadSettings
137
- } from "./chunk-YUVTZ4UH.js";
137
+ } from "./chunk-PPUOYL77.js";
138
138
  import {
139
139
  detectSystemLanguage,
140
140
  getCurrentLanguage,
141
141
  initializeI18n,
142
142
  resolveLanguageSetting,
143
143
  t
144
- } from "./chunk-546CDN6D.js";
144
+ } from "./chunk-KHUA3NQV.js";
145
145
  import {
146
146
  loadEnvironment
147
- } from "./chunk-IKXE3AAC.js";
147
+ } from "./chunk-RK2EE3T7.js";
148
148
  import {
149
149
  getCliVersion
150
- } from "./chunk-NKST54XA.js";
150
+ } from "./chunk-YMBOEAF4.js";
151
151
  import {
152
152
  getPackageJson
153
153
  } from "./chunk-VJNBRRZG.js";
154
154
  import {
155
155
  isWorkspaceTrusted
156
- } from "./chunk-72DZPDH4.js";
156
+ } from "./chunk-ACZRB7AD.js";
157
157
  import {
158
158
  require_strip_json_comments
159
159
  } from "./chunk-ALGGS7UH.js";
@@ -194,29 +194,30 @@ import {
194
194
  unquoteCStylePath,
195
195
  updateChannelMemoryEntry,
196
196
  updateSetting
197
- } from "./chunk-DOA7MCDY.js";
197
+ } from "./chunk-A4VTILZT.js";
198
198
  import {
199
199
  nextFireTime,
200
200
  parseCron
201
201
  } from "./chunk-IRH27ZC2.js";
202
202
  import {
203
203
  require_dist
204
- } from "./chunk-MISUEWB4.js";
204
+ } from "./chunk-4S4OEQ6U.js";
205
205
  import {
206
206
  parseBooleanEnvFlag,
207
207
  resolveTelemetrySettings
208
208
  } from "./chunk-MGSSJT27.js";
209
209
  import {
210
210
  getAllGeminiMdFilenames,
211
+ parseLineTolerant,
211
212
  setGeminiMdFilename
212
- } from "./chunk-O656RSMC.js";
213
+ } from "./chunk-PX5DNLSA.js";
213
214
  import {
214
215
  SchemaValidator,
215
216
  ToolNames
216
217
  } from "./chunk-D7D7RXIJ.js";
217
218
  import {
218
219
  DEFAULT_QWEN_EMBEDDING_MODEL
219
- } from "./chunk-P7LKADIT.js";
220
+ } from "./chunk-BOGOR4HB.js";
220
221
  import {
221
222
  isTlsVerificationDisabled
222
223
  } from "./chunk-BFHXDAR7.js";
@@ -237,8 +238,9 @@ import {
237
238
  import {
238
239
  writeStderrLine,
239
240
  writeStderrLineSafe,
240
- writeStdoutLine
241
- } from "./chunk-OWAK7LMW.js";
241
+ writeStdoutLine,
242
+ writeStdoutLineSafe
243
+ } from "./chunk-KGJGEEVR.js";
242
244
  import {
243
245
  init_esbuild_shims
244
246
  } from "./chunk-5O2XNYP6.js";
@@ -361,9 +363,9 @@ var require_command_exists = __commonJS({
361
363
  cleanInput = /* @__PURE__ */ __name(function(s) {
362
364
  var isPathName = /[\\]/.test(s);
363
365
  if (isPathName) {
364
- var dirname24 = '"' + path3.dirname(s) + '"';
366
+ var dirname25 = '"' + path3.dirname(s) + '"';
365
367
  var basename6 = '"' + path3.basename(s) + '"';
366
- return dirname24 + ":" + basename6;
368
+ return dirname25 + ":" + basename6;
367
369
  }
368
370
  return '"' + s + '"';
369
371
  }, "cleanInput");
@@ -371,10 +373,10 @@ var require_command_exists = __commonJS({
371
373
  module.exports = /* @__PURE__ */ __name(function commandExists2(commandName, callback) {
372
374
  var cleanedCommandName = cleanInput(commandName);
373
375
  if (!callback && typeof Promise !== "undefined") {
374
- return new Promise(function(resolve24, reject) {
376
+ return new Promise(function(resolve25, reject) {
375
377
  commandExists2(commandName, function(error, output) {
376
378
  if (output) {
377
- resolve24(commandName);
379
+ resolve25(commandName);
378
380
  } else {
379
381
  reject(error);
380
382
  }
@@ -703,6 +705,7 @@ import { join, resolve } from "node:path";
703
705
  var REVIEW_TMP_DIR = join(".qwen", "tmp");
704
706
  var REVIEWS_DIR = join(".qwen", "reviews");
705
707
  var REVIEW_CACHE_DIR = join(".qwen", "review-cache");
708
+ var LEASE_PREFIX = "qwen-review-lease-";
706
709
  var PARSE_ARGS_REPORT = join(
707
710
  REVIEW_TMP_DIR,
708
711
  "qwen-review-parse-args.json"
@@ -738,7 +741,6 @@ function tmpPrefix(target) {
738
741
  __name(tmpPrefix, "tmpPrefix");
739
742
 
740
743
  // packages/cli/src/services/review-worktree-lease.ts
741
- var LEASE_PREFIX = "qwen-review-lease-";
742
744
  var GIT_TIMEOUT_MS = 12e4;
743
745
  var debugLogger = createDebugLogger("REVIEW_WORKTREE_LEASE");
744
746
  function gitOptions(timeout) {
@@ -2258,8 +2260,8 @@ function createBridgeReadinessGate() {
2258
2260
  current: /* @__PURE__ */ __name(() => pending, "current"),
2259
2261
  block: /* @__PURE__ */ __name(() => {
2260
2262
  if (pending) return;
2261
- pending = new Promise((resolve24) => {
2262
- releasePending = resolve24;
2263
+ pending = new Promise((resolve25) => {
2264
+ releasePending = resolve25;
2263
2265
  });
2264
2266
  }, "block"),
2265
2267
  release: /* @__PURE__ */ __name(() => {
@@ -2341,7 +2343,7 @@ function createBridgeRecovery(options) {
2341
2343
  writeStderrLine(
2342
2344
  `[Channel] Bridge crashed (${recentCrashCount}/${MAX_CRASH_RESTARTS} in window). Restarting in ${RESTART_DELAY_MS / 1e3}s...`
2343
2345
  );
2344
- await new Promise((resolve24) => setTimeout(resolve24, RESTART_DELAY_MS));
2346
+ await new Promise((resolve25) => setTimeout(resolve25, RESTART_DELAY_MS));
2345
2347
  const bridge = new AcpBridge(bridgeOpts);
2346
2348
  setBridge(bridge);
2347
2349
  attachDisconnectHandler(bridge);
@@ -2659,7 +2661,7 @@ var stopCommand = {
2659
2661
  if (argv["daemon-url"]) {
2660
2662
  const token = argv.token ?? process.env[QWEN_SERVER_TOKEN_ENV] ?? process.env[QWEN_DAEMON_TOKEN_ENV];
2661
2663
  try {
2662
- const sdk = await import("./daemon-CCIX4BMG.js");
2664
+ const sdk = await import("./daemon-YI5RY62O.js");
2663
2665
  const client = new sdk.DaemonClient({
2664
2666
  baseUrl: argv["daemon-url"],
2665
2667
  ...token ? { token } : {}
@@ -2773,7 +2775,7 @@ function formatChannelStartupFailures(source, fallbackWorkspaceCwd) {
2773
2775
  } catch {
2774
2776
  return [];
2775
2777
  }
2776
- const lines2 = [];
2778
+ const lines = [];
2777
2779
  for (const raw of limitedFailures) {
2778
2780
  try {
2779
2781
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
@@ -2805,16 +2807,16 @@ function formatChannelStartupFailures(source, fallbackWorkspaceCwd) {
2805
2807
  "phase=connect",
2806
2808
  ...code ? [`code=${code}`] : []
2807
2809
  ];
2808
- lines2.push(
2810
+ lines.push(
2809
2811
  `[Channel] Startup failure (${fields.join(", ")}): ${safeMessage}`
2810
2812
  );
2811
2813
  } catch {
2812
2814
  }
2813
2815
  }
2814
2816
  if (rawTruncated === true || rawFailureCount > MAX_CHANNEL_STARTUP_FAILURES) {
2815
- lines2.push("[Channel] Additional startup failures were truncated.");
2817
+ lines.push("[Channel] Additional startup failures were truncated.");
2816
2818
  }
2817
- return lines2;
2819
+ return lines;
2818
2820
  }
2819
2821
  __name(formatChannelStartupFailures, "formatChannelStartupFailures");
2820
2822
 
@@ -2845,7 +2847,7 @@ var statusCommand = {
2845
2847
  if (argv["daemon-url"]) {
2846
2848
  const token = argv.token ?? process.env[QWEN_SERVER_TOKEN_ENV] ?? process.env[QWEN_DAEMON_TOKEN_ENV];
2847
2849
  try {
2848
- const sdk = await import("./daemon-CCIX4BMG.js");
2850
+ const sdk = await import("./daemon-YI5RY62O.js");
2849
2851
  const client = new sdk.DaemonClient({
2850
2852
  baseUrl: argv["daemon-url"],
2851
2853
  ...token ? { token } : {}
@@ -2956,7 +2958,7 @@ var reloadCommand = {
2956
2958
  const token = resolveToken(argv.token);
2957
2959
  let sdk;
2958
2960
  try {
2959
- sdk = await import("./daemon-CCIX4BMG.js");
2961
+ sdk = await import("./daemon-YI5RY62O.js");
2960
2962
  } catch (err) {
2961
2963
  writeStderrLine(
2962
2964
  `[Channel] Failed to load daemon SDK: ${safeChannelCommandErrorMessage(err)}`
@@ -3036,7 +3038,7 @@ var setCommand2 = {
3036
3038
  const selection = names[0] === "all" ? { mode: "all" } : { mode: "names", names };
3037
3039
  let sdk;
3038
3040
  try {
3039
- sdk = await import("./daemon-CCIX4BMG.js");
3041
+ sdk = await import("./daemon-YI5RY62O.js");
3040
3042
  } catch (error) {
3041
3043
  writeStderrLine(
3042
3044
  `[Channel] Failed to load daemon SDK: ${safeChannelCommandErrorMessage(error)}`
@@ -3162,7 +3164,7 @@ function createDaemonChannelBridgeFacade(bridge, opts) {
3162
3164
  }
3163
3165
  __name(createDaemonChannelBridgeFacade, "createDaemonChannelBridgeFacade");
3164
3166
  async function loadDaemonSdk() {
3165
- return await import("./daemon-CCIX4BMG.js");
3167
+ return await import("./daemon-YI5RY62O.js");
3166
3168
  }
3167
3169
  __name(loadDaemonSdk, "loadDaemonSdk");
3168
3170
  function selectedChannelNames(channelsConfig, selection) {
@@ -3209,12 +3211,12 @@ async function abortableStartup(value, signal) {
3209
3211
  const promise = Promise.resolve(value);
3210
3212
  if (!signal) return await promise;
3211
3213
  if (signal.aborted) throw startupAbortError();
3212
- return await new Promise((resolve24, reject) => {
3214
+ return await new Promise((resolve25, reject) => {
3213
3215
  const onAbort = /* @__PURE__ */ __name(() => {
3214
3216
  reject(startupAbortError());
3215
3217
  }, "onAbort");
3216
3218
  signal.addEventListener("abort", onAbort, { once: true });
3217
- promise.then(resolve24, reject).finally(() => {
3219
+ promise.then(resolve25, reject).finally(() => {
3218
3220
  signal.removeEventListener("abort", onAbort);
3219
3221
  });
3220
3222
  });
@@ -3623,7 +3625,7 @@ function reportStartupToSupervisor(message, signal, subscribeMessage = (listener
3623
3625
  if (!send) {
3624
3626
  return Promise.reject(new Error("Channel worker IPC is unavailable."));
3625
3627
  }
3626
- return new Promise((resolve24, reject) => {
3628
+ return new Promise((resolve25, reject) => {
3627
3629
  let settled = false;
3628
3630
  let unsubscribeMessage = /* @__PURE__ */ __name(() => {
3629
3631
  }, "unsubscribeMessage");
@@ -3637,7 +3639,7 @@ function reportStartupToSupervisor(message, signal, subscribeMessage = (listener
3637
3639
  settled = true;
3638
3640
  cleanup();
3639
3641
  if (error) reject(error);
3640
- else resolve24();
3642
+ else resolve25();
3641
3643
  }, "finish");
3642
3644
  const onMessage = /* @__PURE__ */ __name((value) => {
3643
3645
  if (isChannelStartupReportAckMessage(value)) {
@@ -3885,8 +3887,8 @@ var daemonWorkerCommand = {
3885
3887
  let shuttingDown = false;
3886
3888
  let exitCode = 0;
3887
3889
  let finish;
3888
- const finished = new Promise((resolve24) => {
3889
- finish = resolve24;
3890
+ const finished = new Promise((resolve25) => {
3891
+ finish = resolve25;
3890
3892
  });
3891
3893
  const shutdown = /* @__PURE__ */ __name(async (reason) => {
3892
3894
  if (shuttingDown) {
@@ -3914,8 +3916,8 @@ var daemonWorkerCommand = {
3914
3916
  ...activeChannelDeliveries.values(),
3915
3917
  ...activeWebhookTasks.values()
3916
3918
  ]),
3917
- new Promise((resolve24) => {
3918
- const timer = setTimeout(resolve24, WORKER_SHUTDOWN_DRAIN_MS);
3919
+ new Promise((resolve25) => {
3920
+ const timer = setTimeout(resolve25, WORKER_SHUTDOWN_DRAIN_MS);
3919
3921
  timer.unref();
3920
3922
  })
3921
3923
  ]);
@@ -4556,7 +4558,7 @@ import { dirname as dirname4, join as join9 } from "node:path";
4556
4558
 
4557
4559
  // packages/cli/src/commands/review/lib/coverage.ts
4558
4560
  init_esbuild_shims();
4559
- import { readFileSync as readFileSync8, statSync as statSync3 } from "node:fs";
4561
+ import { readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
4560
4562
 
4561
4563
  // packages/cli/src/commands/review/lib/transcripts.ts
4562
4564
  init_esbuild_shims();
@@ -4567,7 +4569,7 @@ var TranscriptsUnavailableError = class extends Error {
4567
4569
  __name(this, "TranscriptsUnavailableError");
4568
4570
  }
4569
4571
  };
4570
- function transcriptDir(env = process.env) {
4572
+ function transcriptPaths(env = process.env) {
4571
4573
  const projectDir = env["QWEN_CODE_PROJECT_DIR"]?.trim();
4572
4574
  const sessionId = env["QWEN_CODE_SESSION_ID"]?.trim();
4573
4575
  if (!projectDir || !sessionId) {
@@ -4575,7 +4577,15 @@ function transcriptDir(env = process.env) {
4575
4577
  "the CLI did not export QWEN_CODE_PROJECT_DIR / QWEN_CODE_SESSION_ID, so this run cannot find the harness's record of what its agents did"
4576
4578
  );
4577
4579
  }
4578
- return join5(projectDir, "subagents", sessionId);
4580
+ return {
4581
+ projectDir,
4582
+ sessionId,
4583
+ dir: join5(projectDir, "subagents", sessionId)
4584
+ };
4585
+ }
4586
+ __name(transcriptPaths, "transcriptPaths");
4587
+ function transcriptDir(env = process.env) {
4588
+ return transcriptPaths(env).dir;
4579
4589
  }
4580
4590
  __name(transcriptDir, "transcriptDir");
4581
4591
  function textOf(rec) {
@@ -4606,8 +4616,8 @@ function parseTranscript(file, diffPath) {
4606
4616
  } catch {
4607
4617
  return null;
4608
4618
  }
4609
- const lines2 = raw.split("\n").filter((l) => l.trim());
4610
- if (lines2.length === 0) return null;
4619
+ const lines = raw.split("\n").filter((l) => l.trim());
4620
+ if (lines.length === 0) return null;
4611
4621
  let agentId = "";
4612
4622
  let agentName = "";
4613
4623
  let launchPrompt = "";
@@ -4618,7 +4628,7 @@ function parseTranscript(file, diffPath) {
4618
4628
  const successfulCallArgs = [];
4619
4629
  const byId = /* @__PURE__ */ new Map();
4620
4630
  const anonymous = [];
4621
- for (const line of lines2) {
4631
+ for (const line of lines) {
4622
4632
  let rec;
4623
4633
  try {
4624
4634
  rec = JSON.parse(line);
@@ -4692,11 +4702,15 @@ function parseTranscript(file, diffPath) {
4692
4702
  };
4693
4703
  }
4694
4704
  __name(parseTranscript, "parseTranscript");
4705
+ function listAgentTranscriptFiles(dir) {
4706
+ return readdirSync2(dir).filter((name) => name.endsWith(".jsonl"));
4707
+ }
4708
+ __name(listAgentTranscriptFiles, "listAgentTranscriptFiles");
4695
4709
  function readTranscripts(since, env = process.env, diffPath) {
4696
4710
  const dir = transcriptDir(env);
4697
4711
  let names;
4698
4712
  try {
4699
- names = readdirSync2(dir);
4713
+ names = listAgentTranscriptFiles(dir);
4700
4714
  } catch (err) {
4701
4715
  throw new TranscriptsUnavailableError(
4702
4716
  `no subagent transcripts at ${dir} (${err.message}). The harness writes one per agent; if there are none, either no agents ran or the harness could not write them.`
@@ -4704,7 +4718,6 @@ function readTranscripts(since, env = process.env, diffPath) {
4704
4718
  }
4705
4719
  const out = [];
4706
4720
  for (const name of names) {
4707
- if (!name.endsWith(".jsonl")) continue;
4708
4721
  const rec = parseTranscript(join5(dir, name), diffPath);
4709
4722
  if (!rec) continue;
4710
4723
  if (since !== void 0 && rec.mtimeMs < since) continue;
@@ -4722,7 +4735,13 @@ __name(wasGivenTheDiff, "wasGivenTheDiff");
4722
4735
 
4723
4736
  // packages/cli/src/commands/review/lib/prompt-record.ts
4724
4737
  init_esbuild_shims();
4725
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
4738
+ import {
4739
+ mkdirSync as mkdirSync3,
4740
+ readFileSync as readFileSync5,
4741
+ readdirSync as readdirSync3,
4742
+ statSync as statSync2,
4743
+ writeFileSync as writeFileSync3
4744
+ } from "node:fs";
4726
4745
  import { dirname as dirname2, join as join6, basename as basename3, resolve as resolve3 } from "node:path";
4727
4746
  function promptRecordDir(planPath) {
4728
4747
  const p = resolve3(planPath);
@@ -4764,7 +4783,7 @@ function recordPrompt(planPath, key, prompt) {
4764
4783
  }
4765
4784
  }
4766
4785
  __name(recordPrompt, "recordPrompt");
4767
- function readRecordedPrompts(planPath) {
4786
+ function readRecordedPrompts(planPath, sinceMs) {
4768
4787
  const out = /* @__PURE__ */ new Map();
4769
4788
  const dir = promptRecordDir(planPath);
4770
4789
  let names;
@@ -4782,7 +4801,9 @@ function readRecordedPrompts(planPath) {
4782
4801
  } catch {
4783
4802
  continue;
4784
4803
  }
4785
- out.set(key, readFileSync5(join6(dir, name), "utf8"));
4804
+ const file = join6(dir, name);
4805
+ if (sinceMs !== void 0 && statSync2(file).mtimeMs < sinceMs) continue;
4806
+ out.set(key, readFileSync5(file, "utf8"));
4786
4807
  } catch {
4787
4808
  }
4788
4809
  }
@@ -4790,25 +4811,33 @@ function readRecordedPrompts(planPath) {
4790
4811
  }
4791
4812
  __name(readRecordedPrompts, "readRecordedPrompts");
4792
4813
  function wasDeliveredVerbatim(launchPrompt, built) {
4814
+ return deliveredVerbatim(flattenPrompt(launchPrompt), built);
4815
+ }
4816
+ __name(wasDeliveredVerbatim, "wasDeliveredVerbatim");
4817
+ function deliveredVerbatim(flattenedLaunch, built) {
4793
4818
  if (built.trim().length === 0) return false;
4794
- const delivered = flatten(launchPrompt);
4819
+ return deliveredVerbatimLines(flattenedLaunch, promptLines(built));
4820
+ }
4821
+ __name(deliveredVerbatim, "deliveredVerbatim");
4822
+ function deliveredVerbatimLines(flattenedLaunch, builtLines) {
4823
+ if (builtLines.length === 0) return false;
4795
4824
  let at = 0;
4796
- for (const line of lines(built)) {
4797
- const i = delivered.indexOf(line, at);
4825
+ for (const line of builtLines) {
4826
+ const i = flattenedLaunch.indexOf(line, at);
4798
4827
  if (i === -1) return false;
4799
4828
  at = i + line.length;
4800
4829
  }
4801
4830
  return true;
4802
4831
  }
4803
- __name(wasDeliveredVerbatim, "wasDeliveredVerbatim");
4804
- function flatten(s) {
4832
+ __name(deliveredVerbatimLines, "deliveredVerbatimLines");
4833
+ function flattenPrompt(s) {
4805
4834
  return s.replace(/\s+/g, " ").trim();
4806
4835
  }
4807
- __name(flatten, "flatten");
4808
- function lines(built) {
4809
- return built.split("\n").map((l) => flatten(l)).filter((l) => l.length > 0);
4836
+ __name(flattenPrompt, "flattenPrompt");
4837
+ function promptLines(built) {
4838
+ return built.split("\n").map((l) => flattenPrompt(l)).filter((l) => l.length > 0);
4810
4839
  }
4811
- __name(lines, "lines");
4840
+ __name(promptLines, "promptLines");
4812
4841
 
4813
4842
  // packages/cli/src/commands/review/lib/roster.ts
4814
4843
  init_esbuild_shims();
@@ -4912,9 +4941,9 @@ function splitHeaderPaths(rest) {
4912
4941
  }
4913
4942
  __name(splitHeaderPaths, "splitHeaderPaths");
4914
4943
  function parseDiff(diffText) {
4915
- const lines2 = diffText.split("\n");
4916
- if (lines2.length > 0 && lines2[lines2.length - 1] === "") lines2.pop();
4917
- const total = lines2.length;
4944
+ const lines = diffText.split("\n");
4945
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
4946
+ const total = lines.length;
4918
4947
  const files = [];
4919
4948
  let cur = null;
4920
4949
  let curHunk = null;
@@ -4941,7 +4970,7 @@ function parseDiff(diffText) {
4941
4970
  }
4942
4971
  }, "closeFile");
4943
4972
  for (let i = 0; i < total; i++) {
4944
- const line = lines2[i];
4973
+ const line = lines[i];
4945
4974
  const n = i + 1;
4946
4975
  if (line.startsWith("diff --git ")) {
4947
4976
  closeFile(n - 1);
@@ -5020,9 +5049,9 @@ function parseDiff(diffText) {
5020
5049
  }
5021
5050
  __name(parseDiff, "parseDiff");
5022
5051
  var MIN_SPLIT_SEGMENT = 40;
5023
- function isSafeSplitPoint(lines2, n) {
5024
- const cur = lines2[n - 1];
5025
- const prev = lines2[n - 2];
5052
+ function isSafeSplitPoint(lines, n) {
5053
+ const cur = lines[n - 1];
5054
+ const prev = lines[n - 2];
5026
5055
  if (cur === void 0 || prev === void 0) return false;
5027
5056
  const isNewSide = /* @__PURE__ */ __name((l) => l === "" || /^[+ ]/.test(l), "isNewSide");
5028
5057
  if (!isNewSide(cur) || !isNewSide(prev)) return false;
@@ -5032,9 +5061,9 @@ function isSafeSplitPoint(lines2, n) {
5032
5061
  return prev === "" || /^\s*$/.test(prev.slice(1));
5033
5062
  }
5034
5063
  __name(isSafeSplitPoint, "isSafeSplitPoint");
5035
- function charPrefix(lines2) {
5036
- const p = new Array(lines2.length + 1).fill(0);
5037
- for (let i = 0; i < lines2.length; i++) p[i + 1] = p[i] + lines2[i].length + 1;
5064
+ function charPrefix(lines) {
5065
+ const p = new Array(lines.length + 1).fill(0);
5066
+ for (let i = 0; i < lines.length; i++) p[i + 1] = p[i] + lines[i].length + 1;
5038
5067
  return p;
5039
5068
  }
5040
5069
  __name(charPrefix, "charPrefix");
@@ -5042,14 +5071,14 @@ function charsIn(prefix, s, e) {
5042
5071
  return prefix[e] - prefix[s - 1];
5043
5072
  }
5044
5073
  __name(charsIn, "charsIn");
5045
- function splitUnit(unit, lines2, prefix, maxChunkLines, bodyStart) {
5074
+ function splitUnit(unit, lines, prefix, maxChunkLines, bodyStart) {
5046
5075
  const over = /* @__PURE__ */ __name((s, e) => e - s + 1 > maxChunkLines || charsIn(prefix, s, e) > MAX_CHUNK_CHARS, "over");
5047
5076
  const bigEnough = /* @__PURE__ */ __name((s, e) => e - s + 1 >= MIN_SPLIT_SEGMENT || charsIn(prefix, s, e) >= MAX_CHUNK_CHARS / 2, "bigEnough");
5048
5077
  if (!over(unit.start, unit.end)) return [unit];
5049
5078
  const newLineOf = /* @__PURE__ */ new Map();
5050
5079
  let newLine = unit.newStart;
5051
5080
  for (let n = bodyStart; n <= unit.end; n++) {
5052
- const c = lines2[n - 1]?.[0];
5081
+ const c = lines[n - 1]?.[0];
5053
5082
  if (c === " " || c === "+") newLineOf.set(n, newLine++);
5054
5083
  }
5055
5084
  const out = [];
@@ -5058,7 +5087,7 @@ function splitUnit(unit, lines2, prefix, maxChunkLines, bodyStart) {
5058
5087
  const upper = Math.min(unit.end, segStart + maxChunkLines - 1);
5059
5088
  let cut = -1;
5060
5089
  for (let n = upper; n > bodyStart; n--) {
5061
- if (!isSafeSplitPoint(lines2, n)) continue;
5090
+ if (!isSafeSplitPoint(lines, n)) continue;
5062
5091
  if (over(segStart, n - 1)) continue;
5063
5092
  if (!bigEnough(segStart, n - 1)) continue;
5064
5093
  cut = n;
@@ -5066,7 +5095,7 @@ function splitUnit(unit, lines2, prefix, maxChunkLines, bodyStart) {
5066
5095
  }
5067
5096
  if (cut < 0) {
5068
5097
  for (let n = upper + 1; n <= unit.end; n++) {
5069
- if (isSafeSplitPoint(lines2, n) && bigEnough(segStart, n - 1)) {
5098
+ if (isSafeSplitPoint(lines, n) && bigEnough(segStart, n - 1)) {
5070
5099
  cut = n;
5071
5100
  break;
5072
5101
  }
@@ -5092,10 +5121,10 @@ function splitUnit(unit, lines2, prefix, maxChunkLines, bodyStart) {
5092
5121
  return out;
5093
5122
  }
5094
5123
  __name(splitUnit, "splitUnit");
5095
- function planChunks(files, lines2, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5096
- const diffLines = lines2.length;
5124
+ function planChunks(files, lines, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5125
+ const diffLines = lines.length;
5097
5126
  if (diffLines === 0) return [];
5098
- const prefix = charPrefix(lines2);
5127
+ const prefix = charPrefix(lines);
5099
5128
  const units = [];
5100
5129
  for (const f of files) {
5101
5130
  if (f.hunks.length === 0) {
@@ -5119,7 +5148,7 @@ function planChunks(files, lines2, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5119
5148
  newEnd: h.newEnd
5120
5149
  };
5121
5150
  units.push(
5122
- ...splitUnit(unit, lines2, prefix, maxChunkLines, h.diffStart + 1)
5151
+ ...splitUnit(unit, lines, prefix, maxChunkLines, h.diffStart + 1)
5123
5152
  );
5124
5153
  });
5125
5154
  }
@@ -5131,7 +5160,7 @@ function planChunks(files, lines2, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5131
5160
  cur.chars = charsIn(prefix, cur.startLine, cur.endLine);
5132
5161
  let widest = 0;
5133
5162
  for (let n = cur.startLine; n <= cur.endLine; n++) {
5134
- if (lines2[n - 1].length > widest) widest = lines2[n - 1].length;
5163
+ if (lines[n - 1].length > widest) widest = lines[n - 1].length;
5135
5164
  }
5136
5165
  cur.maxLineChars = widest;
5137
5166
  chunks.push(cur);
@@ -5174,10 +5203,10 @@ function planChunks(files, lines2, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5174
5203
  __name(planChunks, "planChunks");
5175
5204
  function buildDiffPlan(diffText, maxChunkLines = DEFAULT_MAX_CHUNK_LINES) {
5176
5205
  const { files, diffLines } = parseDiff(diffText);
5177
- const lines2 = diffText.split("\n");
5178
- if (lines2.length > 0 && lines2[lines2.length - 1] === "") lines2.pop();
5206
+ const lines = diffText.split("\n");
5207
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
5179
5208
  const linesOf = /* @__PURE__ */ __name((kind) => files.filter((f) => f.kind === kind).reduce((n, f) => n + (f.diffEnd - f.diffStart + 1), 0), "linesOf");
5180
- const chunks = planChunks(files, lines2, maxChunkLines);
5209
+ const chunks = planChunks(files, lines, maxChunkLines);
5181
5210
  if (!chunksCoverDiff(chunks, diffLines)) {
5182
5211
  throw new Error(
5183
5212
  `diff-plan: chunks do not tile the diff (${chunks.length} chunks over ${diffLines} lines). Refusing to plan a review with a coverage hole.`
@@ -5696,6 +5725,7 @@ __name(requiredAgents, "requiredAgents");
5696
5725
 
5697
5726
  // packages/cli/src/commands/review/lib/agent-briefs.ts
5698
5727
  init_esbuild_shims();
5728
+ var REVERSE_AUDIT_EXAMPLE_RECEIPT = "No issues found \u2014 re-walked the reconnect state machine and the two changed exports' call sites; every gap I checked was already in the list";
5699
5729
  var BRIEFS = {
5700
5730
  "0": {
5701
5731
  label: "Agent 0: Issue fidelity & root-cause ownership",
@@ -5994,11 +6024,11 @@ You are undirected on purpose. Do not restrict yourself to the list.`
5994
6024
  readsDiff: false,
5995
6025
  brief: `You are **Agent 7: Build & Test Verification**. You do not review the diff \u2014 you run the project's own deterministic checks and report what they say. Your evidence is **the commands you ran and their output**; a return that names no command has not done this job.
5996
6026
 
5997
- **Run \`qwen review build-test\` (the exact command, with its \`--plan\` and \`--worktree\`, is below).** It installs if needed, then builds only the workspaces the diff changes plus everything they compile against, and tests the changed ones \u2014 reading the plan for what changed and the root \`package.json\` for the workspace layout. Do **not** substitute \`npm run build\` / \`npm test\` by hand. The old brief did, with a 120-second deadline, and this repo's cold full build is 125 seconds: measured across the harness's own transcripts, that command timed out **71 times** and verified nothing. \`build-test\` scopes the build, gives it a deadline it can meet, and \u2014 this is the part a hand-run command gets wrong \u2014 reports a timeout as **infrastructure, not a finding**. A build that runs out of time is never a Critical against someone's pull request.
6027
+ **Run \`qwen review build-test\` (the exact command, with its \`--plan\` and \`--worktree\`, is below).** It installs if needed, then builds only the workspaces the diff changes plus everything they compile against, and tests the changed ones plus every workspace that depends on them \u2014 reading the plan for what changed and the root \`package.json\` for the workspace layout. Do **not** substitute \`npm run build\` / \`npm test\` by hand. The old brief did, with a 120-second deadline, and this repo's cold full build is 125 seconds: measured across the harness's own transcripts, that command timed out **71 times** and verified nothing. \`build-test\` scopes the build, gives it a deadline it can meet, and \u2014 this is the part a hand-run command gets wrong \u2014 reports a timeout as **infrastructure, not a finding**. A build that runs out of time is never a Critical against someone's pull request.
5998
6028
 
5999
6029
  Read the JSON it prints:
6000
6030
 
6001
- - \`toolchain: "npm"\` \u2192 use its \`build[]\` / \`test[]\` results. A failure in a file **the diff changed** is a **Critical** (\`Source: [build]\` or \`[test]\`); a failure in a file it did **not** touch is pre-existing \u2014 say so, do not file it against this PR. A non-empty \`timedOut\`, or a failed \`install\`, is environment/infrastructure \u2014 informational, never a Critical. On \`ok: true\`, name the workspaces built and the commands run; a return that names no command is a whiff.
6031
+ - \`toolchain: "npm"\` \u2192 use its \`build[]\` / \`test[]\` results. A failure in a file **the diff changed** is a **Critical** (\`Source: [build]\` or \`[test]\`); a failure in a file it did **not** touch is pre-existing \u2014 say so, do not file it against this PR. A non-empty \`timedOut\`, or a failed \`install\`, is environment/infrastructure \u2014 informational, never a Critical. On \`ok: true\`, name the workspaces built and the commands run; a return that names no command is a whiff. Report the TEST coverage from \`testScope\`, never from assumption. \`testScope.workspaces\` lists exactly the suites that ran \u2014 say "tests scoped to <list> \u2014 the changed workspaces and their declared dependents that define a test script". \`testScope.notRun\`, when present, names suites the whole-call budget stopped before they ran \u2014 say they did not run, never fold them into the coverage. When \`testScope.caveat\` is present, the scope may be incomplete \u2014 quote the caveat and say exactly that. A green run is a claim about those suites only \u2014 do not phrase it as the whole suite passing.
6002
6032
  - **When any \`test[]\` command failed (exit non-zero, not a timeout), MEASURE which failures are the PR's before ruling by path.** The path rule above misclassifies in both directions \u2014 an environment-flaky test in a touched file gets filed as a Critical it did not cause, and a PR that breaks a test in an UNTOUCHED file gets waved through as pre-existing. The measurement is two commands: \`qwen review base-tree --plan <plan> --worktree <worktree> --out <plan dir>/qwen-review-pr-<n>-base-tree.json\` (builds the merge base beside the worktree). **Read \`available\` before using \`path\`** \u2014 a tree that was created but did NOT build populates \`path\` too, and a base that failed to build says nothing whatsoever about the PR, so measuring against it turns an infrastructure failure into a list of Criticals. \`available: false\` (local/lightweight review, no merge base, a base that would not compile) means the path rule stands \u2014 say so and stop here, and \`qwen review test-delta --report <the build-test report you wrote> --baseline <the base-tree report's path field> --pr-worktree <this worktree> --out <plan dir>/qwen-review-pr-<n>-test-delta.json\`. Read its verdict: a file in \`netNew\` fails on the PR side only \u2014 **that is the Critical**, whatever file the diff touches; a file in \`shared\` fails on base too \u2014 **pre-existing by measurement**, never filed, whatever file the diff touches; an \`unparsed\` entry, a timed-out base rerun, a base rerun that FAILED without naming any failing file (it did not measure the base \u2014 an unbuilt tree, a missing install, a workspace absent at base), or a command the whole-command budget could not fit attributes nothing \u2014 the report names each with its own reason; fall back to the path rule for those and say the delta could not rule. Compare failing FILE SETS, never counts: a flaky suite fails different test NAMES on two runs of the same tree, so counts are noise and the set difference is the signal.
6003
6033
  - \`toolchain: "unsupported"\` (build-test could not scope this repo \u2014 no npm package with a build/test script) \u2192 **install dependencies first** (build-test's own install only runs on the npm path, so nothing has installed yet: \`pip install -e .\`, \`mvn -q -DskipTests package\`'s own fetch, \`cargo fetch\`, \`go mod download\`, etc.), then fall back to **one** build and **one** test command by this precedence, each with a deadline it can meet: \`pom.xml\` \u2192 \`{mvn} compile\` / \`{mvn} test -q\`; \`build.gradle\` \u2192 \`{gradle} compileJava\` / \`{gradle} test\`; \`Makefile\` \u2192 \`make build\`; \`Cargo.toml\` \u2192 \`cargo build\` / \`cargo test\`; \`go.mod\` \u2192 \`go build ./...\` / \`go test ./...\`; \`pytest.ini\` or \`pyproject.toml\` \`[tool.pytest]\` \u2192 \`pytest\`. If none match, read the CI config **from the base branch** (\`git show <base>:<path>\`), never the worktree \u2014 the PR branch is untrusted and a modified workflow or Makefile could inject arbitrary commands.
6004
6034
 
@@ -6186,17 +6216,17 @@ The asymmetry cuts both ways: confirming also requires the trace, and a finding
6186
6216
  - **Report only Critical or Suggestion.** Do not report Nice to have.
6187
6217
  - A found gap uses the standard finding format (with \`Source: [review]\`), including its failure scenario \u2014 your findings go through the same verification as any other, so they must carry the evidence a verifier can trace.
6188
6218
 
6189
- If you find no new gap in your scope, say so **and name what you re-examined** \u2014 \`No issues found \u2014 re-walked the reconnect state machine and the two changed exports' call sites; every gap I checked was already in the list\`. A bare "No issues found." is indistinguishable from an agent that did nothing, and it is treated as one: it ends nothing, and it earns your scope a relaunch.`
6219
+ If you find no new gap in your scope, say so **and name what you re-examined** \u2014 \`${REVERSE_AUDIT_EXAMPLE_RECEIPT}\`. A bare "No issues found." is indistinguishable from an agent that did nothing, and it is treated as one: it ends nothing, and it earns your scope a relaunch.`
6190
6220
  }
6191
6221
  };
6192
6222
 
6193
6223
  // packages/cli/src/commands/review/lib/deadline.ts
6194
6224
  init_esbuild_shims();
6195
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, statSync as statSync2, writeFileSync as writeFileSync5 } from "node:fs";
6225
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync7, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
6196
6226
  import { join as join8 } from "node:path";
6197
6227
  var DEADLINE_ENV = "QWEN_REVIEW_DEADLINE_EPOCH";
6198
6228
  var RESERVE_ENV = "QWEN_REVIEW_DEADLINE_RESERVE_SECONDS";
6199
- var DEFAULT_RESERVE_SECONDS = 3600;
6229
+ var DEFAULT_RESERVE_SECONDS = 4800;
6200
6230
  var DEFAULT_ROUND_SECONDS = 1800;
6201
6231
  var MIN_OBSERVED_ROUND_SECONDS = 600;
6202
6232
  var STAMPS_FILE = "budget-rounds.json";
@@ -6204,7 +6234,7 @@ var STOP_FILE = "budget-stop.json";
6204
6234
  var RUN_EPOCH_SLACK_MS = 2e3;
6205
6235
  function runEpochMs(planPath) {
6206
6236
  try {
6207
- return statSync2(planPath).mtimeMs - RUN_EPOCH_SLACK_MS;
6237
+ return statSync3(planPath).mtimeMs - RUN_EPOCH_SLACK_MS;
6208
6238
  } catch {
6209
6239
  return Number.NEGATIVE_INFINITY;
6210
6240
  }
@@ -6240,14 +6270,19 @@ function stampRound(planPath, round, nowMs = Date.now()) {
6240
6270
  }
6241
6271
  __name(stampRound, "stampRound");
6242
6272
  function expectedRoundSeconds(planPath, round, nowMs = Date.now()) {
6243
- const stamps = readRoundStamps(planPath);
6244
- for (let i = stamps.length - 1; i >= 0; i--) {
6245
- const s = stamps[i];
6246
- if (round !== void 0 && s.round === round) continue;
6247
- const observed = Math.round((nowMs - s.atMs) / 1e3);
6248
- return Math.max(MIN_OBSERVED_ROUND_SECONDS, observed);
6273
+ const stamps = readRoundStamps(planPath).filter(
6274
+ (s) => round === void 0 || s.round !== round
6275
+ );
6276
+ if (stamps.length === 0) return DEFAULT_ROUND_SECONDS;
6277
+ let maxSeconds = 0;
6278
+ for (let i = 0; i < stamps.length; i++) {
6279
+ const end = i + 1 < stamps.length ? stamps[i + 1].atMs : nowMs;
6280
+ maxSeconds = Math.max(
6281
+ maxSeconds,
6282
+ Math.round((end - stamps[i].atMs) / 1e3)
6283
+ );
6249
6284
  }
6250
- return DEFAULT_ROUND_SECONDS;
6285
+ return Math.max(MIN_OBSERVED_ROUND_SECONDS, maxSeconds);
6251
6286
  }
6252
6287
  __name(expectedRoundSeconds, "expectedRoundSeconds");
6253
6288
  function reverseAuditBudgetExhausted(env, roundCostSeconds, nowMs = Date.now()) {
@@ -6354,7 +6389,7 @@ function readPlan(path3) {
6354
6389
  if (problem) {
6355
6390
  throw new Error(`coverage: ${path3} has ${problem}`);
6356
6391
  }
6357
- return { plan, mtimeMs: statSync3(path3).mtimeMs };
6392
+ return { plan, mtimeMs: statSync4(path3).mtimeMs };
6358
6393
  }
6359
6394
  __name(readPlan, "readPlan");
6360
6395
  var CHUNK_RE = /\bchunk\s+(\d+)\s+of\s+\d+\b/i;
@@ -7146,6 +7181,7 @@ __name(footerVersion, "footerVersion");
7146
7181
 
7147
7182
  // packages/cli/src/commands/review/compose-review.ts
7148
7183
  var LOW_SIGNAL_SRC_DIFF_LINES = 100;
7184
+ var UNVERIFIED_FINDING_TAG_RE = /—\s*\[unverified\]/gi;
7149
7185
  function withMarker(line) {
7150
7186
  return line.startsWith(CRITICAL_PREFIX) ? line : `${CRITICAL_PREFIX} ${line}`;
7151
7187
  }
@@ -7393,6 +7429,33 @@ function composeReviewBody(input, cliVersion) {
7393
7429
  criticalsUnverified = criticalsNeedingVerify >= 1;
7394
7430
  }
7395
7431
  }
7432
+ let findingsUnverifiedAtCompose = false;
7433
+ let findingsFileUnreadable = false;
7434
+ let unverifiedTagCount = 0;
7435
+ const findingsPath = input.findingsPath;
7436
+ if (findingsPath !== void 0 && findingsPath !== null) {
7437
+ if (typeof findingsPath !== "string" || findingsPath.trim() === "") {
7438
+ throw new TypeError(
7439
+ `compose-review: findingsPath must be a non-empty string, got ${JSON.stringify(findingsPath)}`
7440
+ );
7441
+ }
7442
+ try {
7443
+ const findingsContent = readFileSync9(findingsPath, "utf8");
7444
+ unverifiedTagCount = (findingsContent.match(UNVERIFIED_FINDING_TAG_RE) ?? []).length;
7445
+ findingsUnverifiedAtCompose = unverifiedTagCount > 0;
7446
+ if (findingsUnverifiedAtCompose) {
7447
+ remediation.push(
7448
+ "findings still tagged `\u2014 [unverified]`: relaunch the verifier for each tagged entry (Step 4, `--role verify` with that entry), apply its verdict in the cumulative findings file, and run compose-review again with the updated file"
7449
+ );
7450
+ }
7451
+ } catch {
7452
+ findingsFileUnreadable = true;
7453
+ findingsUnverifiedAtCompose = true;
7454
+ remediation.push(
7455
+ "findings file not readable: pass the cumulative reverse-audit findings file \u2014 the one every round's `--findings` received \u2014 as `findingsPath` in the state JSON, and run compose-review again"
7456
+ );
7457
+ }
7458
+ }
7396
7459
  const contextUnavailable = toBool(
7397
7460
  input.contextUnavailable,
7398
7461
  "contextUnavailable"
@@ -7439,10 +7502,13 @@ function composeReviewBody(input, cliVersion) {
7439
7502
  }
7440
7503
  if (contextUnavailable) cappedBy.push("context-unavailable");
7441
7504
  if (criticalsUnverified) cappedBy.push("criticals-unverified");
7505
+ if (findingsUnverifiedAtCompose) {
7506
+ cappedBy.push("findings-unverified-at-compose");
7507
+ }
7442
7508
  let event2 = baseEvent;
7443
7509
  if (event2 === "APPROVE" && cappedBy.length > 0) event2 = "COMMENT";
7444
7510
  const deterministicBodyCriticals = bodyCriticals.length - nonDeterministicBodyCriticals;
7445
- if (event2 === "REQUEST_CHANGES" && criticalsUnverified && deterministicBodyCriticals === 0) {
7511
+ if (event2 === "REQUEST_CHANGES" && (criticalsUnverified || findingsUnverifiedAtCompose && criticalsNeedingVerify >= 1) && deterministicBodyCriticals === 0) {
7446
7512
  event2 = "COMMENT";
7447
7513
  }
7448
7514
  let downgraded = false;
@@ -7608,11 +7674,23 @@ ${footer}`;
7608
7674
  zh: `Test Plan\uFF08\u975E\u963B\u65AD\uFF09\uFF1A${testPlanNotes.join("; ")}\u3002`
7609
7675
  }
7610
7676
  ] : [];
7677
+ const unverifiedTagsBlock = !findingsUnverifiedAtCompose ? [] : findingsFileUnreadable ? [
7678
+ {
7679
+ en: "\u26A0\uFE0F The reverse-audit findings file could not be read at compose time, so this run cannot show its findings were verified.",
7680
+ zh: "\u26A0\uFE0F \u7EC4\u5408\u8BC4\u5BA1\u65F6\u65E0\u6CD5\u8BFB\u53D6\u53CD\u5411\u5BA1\u8BA1\u53D1\u73B0\u6587\u4EF6\uFF0C\u672C\u6B21\u8FD0\u884C\u65E0\u6CD5\u8BC1\u660E\u5176\u53D1\u73B0\u5DF2\u7ECF\u8FC7\u9A8C\u8BC1\u3002"
7681
+ }
7682
+ ] : [
7683
+ {
7684
+ en: `\u26A0\uFE0F ${unverifiedTagCount} finding(s) still carried the \`\u2014 [unverified]\` tag when the loop ended \u2014 the verifier never ruled on them, and they are not confirmed.`,
7685
+ zh: `\u26A0\uFE0F \u5FAA\u73AF\u7ED3\u675F\u65F6\u4ECD\u6709 ${unverifiedTagCount} \u6761\u53D1\u73B0\u5E26\u7740 \`\u2014 [unverified]\` \u6807\u8BB0\u2014\u2014\u9A8C\u8BC1\u8005\u4ECE\u672A\u5BF9\u5B83\u4EEC\u4F5C\u51FA\u88C1\u51B3\uFF0C\u5B83\u4EEC\u4E0D\u7B97\u5DF2\u786E\u8BA4\u3002`
7686
+ }
7687
+ ];
7611
7688
  if (event2 === "REQUEST_CHANGES") {
7612
7689
  const parts = [
7613
7690
  ...contextUnavailable ? [contextUnavailableClause] : [],
7614
7691
  ...cannotTellBlock,
7615
7692
  ...notReviewedParts,
7693
+ ...unverifiedTagsBlock,
7616
7694
  ...deferredBlock,
7617
7695
  ...testPlanBlock,
7618
7696
  ...bodyCriticalBlock
@@ -7661,8 +7739,9 @@ ${footer}`;
7661
7739
  } else {
7662
7740
  const canCertify = !downgraded && !downgradeApprove && !downgradeRequestChanges && c === 0 && cannotTell.length === 0 && uncoverable.length === 0 && unreviewed.length + coverageEntries.length === 0 && // A missing receipt caps the event but was left out of certification, so a
7663
7741
  // body could open "Reviewed — no blockers." two lines above "nobody read
7664
- // them." Nothing nobody read can be certified blocker-free.
7665
- missingReceipts.length === 0;
7742
+ // them." Nothing nobody read can be certified blocker-free — and neither
7743
+ // can a loop that ended with findings no verifier ever ruled on.
7744
+ missingReceipts.length === 0 && !findingsUnverifiedAtCompose;
7666
7745
  const disclosedChunkIds = /* @__PURE__ */ new Set();
7667
7746
  for (const e of coverageEntries) {
7668
7747
  const m = /^chunk (\d+)$/.exec(e.subject);
@@ -7687,6 +7766,7 @@ ${footer}`;
7687
7766
  }
7688
7767
  clauses.push(...cannotTellBlock);
7689
7768
  clauses.push(...notReviewedParts);
7769
+ clauses.push(...unverifiedTagsBlock);
7690
7770
  clauses.push(...deferredBlock);
7691
7771
  clauses.push(...testPlanBlock);
7692
7772
  if (downgradedFrom === "Request changes" || criticalsUnverified) {
@@ -8049,11 +8129,12 @@ function verdictLine(r) {
8049
8129
  "chunk-nobody-read": "part of the diff was never read",
8050
8130
  "uncoverable-chunk": "part of the diff cannot be read at all",
8051
8131
  "unreviewed-dimension": "a dimension nobody reviewed",
8052
- "context-unavailable": "the PR's existing discussion could not be read"
8132
+ "context-unavailable": "the PR's existing discussion could not be read",
8133
+ "findings-unverified-at-compose": "findings were still unverified when the loop ended"
8053
8134
  };
8054
8135
  let line = `Verdict: ${label2[r.event]}`;
8055
- if (r.baseEvent === "REQUEST_CHANGES" && r.event === "COMMENT" && r.cappedBy.includes("criticals-unverified")) {
8056
- line += " \u2014 a Request changes was NOT available: its blockers were never verified (they are posted, disclosed as unverified)";
8136
+ if (r.baseEvent === "REQUEST_CHANGES" && r.event === "COMMENT" && (r.cappedBy.includes("criticals-unverified") || r.cappedBy.includes("findings-unverified-at-compose"))) {
8137
+ line += " \u2014 a Request changes was NOT available: " + (r.cappedBy.includes("criticals-unverified") ? "its blockers were never verified (they are posted, disclosed as unverified)" : "findings were still unverified when the loop ended (they are posted, disclosed)");
8057
8138
  } else if (r.baseEvent === "APPROVE" && r.event !== "APPROVE") {
8058
8139
  const reasons = r.cappedBy.map((c) => why[c] ?? c);
8059
8140
  if (r.downgraded) reasons.push("a presubmit check failed");
@@ -8682,7 +8763,7 @@ __name(planEffortField, "planEffortField");
8682
8763
 
8683
8764
  // packages/cli/src/commands/review/lib/report.ts
8684
8765
  init_esbuild_shims();
8685
- import { statSync as statSync4 } from "node:fs";
8766
+ import { statSync as statSync5 } from "node:fs";
8686
8767
 
8687
8768
  // packages/cli/src/commands/review/lib/heavy.ts
8688
8769
  init_esbuild_shims();
@@ -8785,7 +8866,7 @@ __name(buildPlanReport, "buildPlanReport");
8785
8866
  function warnOnReportSize(path3, cap) {
8786
8867
  let size = 0;
8787
8868
  try {
8788
- size = statSync4(path3).size;
8869
+ size = statSync5(path3).size;
8789
8870
  } catch {
8790
8871
  return;
8791
8872
  }
@@ -9141,7 +9222,7 @@ import { dirname as dirname7, resolve as resolve8 } from "node:path";
9141
9222
 
9142
9223
  // packages/cli/src/commands/review/lib/local-diff.ts
9143
9224
  init_esbuild_shims();
9144
- import { lstatSync as lstatSync2, statSync as statSync5, realpathSync as realpathSync2 } from "node:fs";
9225
+ import { lstatSync as lstatSync2, statSync as statSync6, realpathSync as realpathSync2 } from "node:fs";
9145
9226
  import { join as join10, relative as relative2, resolve as resolve7, isAbsolute as isAbsolute2, sep as sep2 } from "node:path";
9146
9227
  var MAX_UNTRACKED_BYTES = 1e6;
9147
9228
  var MAX_UNTRACKED_FILES = 500;
@@ -9163,7 +9244,7 @@ function describeUndiffable(abs, st) {
9163
9244
  }
9164
9245
  if (st.isSymbolicLink()) {
9165
9246
  try {
9166
- return statSync5(abs).isDirectory() ? "is a symlink to a directory \u2014 git cannot diff it as a file" : null;
9247
+ return statSync6(abs).isDirectory() ? "is a symlink to a directory \u2014 git cannot diff it as a file" : null;
9167
9248
  } catch {
9168
9249
  return null;
9169
9250
  }
@@ -9709,9 +9790,9 @@ function blockerSection(roots, issueBlockers, repliesByRoot, ctx) {
9709
9790
  ""
9710
9791
  ];
9711
9792
  let spent = out.join("\n").length;
9712
- const charge = /* @__PURE__ */ __name((lines2) => {
9713
- spent += lines2.join("\n").length;
9714
- return lines2;
9793
+ const charge = /* @__PURE__ */ __name((lines) => {
9794
+ spent += lines.join("\n").length;
9795
+ return lines;
9715
9796
  }, "charge");
9716
9797
  const refsLine = /* @__PURE__ */ __name((body) => {
9717
9798
  const refs = extractCodeRefs(body);
@@ -10371,11 +10452,11 @@ function showFile(baseRef, path3) {
10371
10452
  }
10372
10453
  __name(showFile, "showFile");
10373
10454
  function extractCodeReviewSection(content) {
10374
- const lines2 = content.split("\n");
10455
+ const lines = content.split("\n");
10375
10456
  let start = -1;
10376
- let end = lines2.length;
10377
- for (let i = 0; i < lines2.length; i++) {
10378
- const line = lines2[i];
10457
+ let end = lines.length;
10458
+ for (let i = 0; i < lines.length; i++) {
10459
+ const line = lines[i];
10379
10460
  if (start < 0) {
10380
10461
  if (/^## Code Review\s*$/i.test(line)) start = i;
10381
10462
  } else if (/^## /.test(line)) {
@@ -10384,7 +10465,7 @@ function extractCodeReviewSection(content) {
10384
10465
  }
10385
10466
  }
10386
10467
  if (start < 0) return null;
10387
- return lines2.slice(start, end).join("\n").trim();
10468
+ return lines.slice(start, end).join("\n").trim();
10388
10469
  }
10389
10470
  __name(extractCodeReviewSection, "extractCodeReviewSection");
10390
10471
  function loadCombined(baseRef) {
@@ -10855,7 +10936,7 @@ var presubmitCommand = {
10855
10936
  // packages/cli/src/commands/review/publish-assets.ts
10856
10937
  init_esbuild_shims();
10857
10938
  import { createHash as createHash2 } from "node:crypto";
10858
- import { readFileSync as readFileSync16, statSync as statSync6, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "node:fs";
10939
+ import { readFileSync as readFileSync16, statSync as statSync7, writeFileSync as writeFileSync15, mkdirSync as mkdirSync15 } from "node:fs";
10859
10940
  import { basename as basename5, dirname as dirname11, resolve as resolve10 } from "node:path";
10860
10941
 
10861
10942
  // packages/cli/src/commands/review/lib/authorization.ts
@@ -11038,7 +11119,64 @@ __name(reviewWriteAuthorization, "reviewWriteAuthorization");
11038
11119
 
11039
11120
  // packages/cli/src/commands/review/lib/assets.ts
11040
11121
  init_esbuild_shims();
11041
- var ASSET_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp"]);
11122
+ var EXTENSION_FORMAT = {
11123
+ png: "png",
11124
+ jpg: "jpeg",
11125
+ jpeg: "jpeg",
11126
+ gif: "gif",
11127
+ webp: "webp"
11128
+ };
11129
+ var ASSET_EXTENSIONS = new Set(Object.keys(EXTENSION_FORMAT));
11130
+ function claimedExtension(basename6) {
11131
+ return basename6.includes(".") ? basename6.slice(basename6.lastIndexOf(".") + 1).toLowerCase() : "";
11132
+ }
11133
+ __name(claimedExtension, "claimedExtension");
11134
+ var ASSET_HEADER_BYTES = 16;
11135
+ function sniffImageFormat(header) {
11136
+ const at = /* @__PURE__ */ __name((i) => header[i] ?? -1, "at");
11137
+ const ascii = /* @__PURE__ */ __name((i, s) => [...s].every((ch, k) => at(i + k) === ch.charCodeAt(0)), "ascii");
11138
+ if (at(0) === 137 && ascii(1, "PNG") && at(4) === 13 && at(5) === 10 && at(6) === 26 && at(7) === 10) {
11139
+ return "png";
11140
+ }
11141
+ if (at(0) === 255 && at(1) === 216 && at(2) === 255) {
11142
+ return "jpeg";
11143
+ }
11144
+ if (ascii(0, "GIF87a") || ascii(0, "GIF89a")) {
11145
+ return "gif";
11146
+ }
11147
+ if (ascii(0, "RIFF") && ascii(8, "WEBP") && // The container claim is not the image: a RIFF box carrying WEBP at
11148
+ // offset 8 could still hold anything. Every spec-conformant WebP's
11149
+ // first chunk is VP8, VP8L or VP8X at byte 12, and the 16-byte read
11150
+ // this gate sniffs always covers it.
11151
+ (ascii(12, "VP8 ") || ascii(12, "VP8L") || ascii(12, "VP8X"))) {
11152
+ return "webp";
11153
+ }
11154
+ return null;
11155
+ }
11156
+ __name(sniffImageFormat, "sniffImageFormat");
11157
+ function refusedExtension(basename6, ext) {
11158
+ return {
11159
+ ok: false,
11160
+ reason: `${basename6}: extension ${JSON.stringify(ext)} is not an allowed evidence image type (${[...ASSET_EXTENSIONS].join(", ")})`
11161
+ };
11162
+ }
11163
+ __name(refusedExtension, "refusedExtension");
11164
+ function validateAssetContent(basename6, header) {
11165
+ const ext = claimedExtension(basename6);
11166
+ const claimed = Object.hasOwn(EXTENSION_FORMAT, ext) ? EXTENSION_FORMAT[ext] : void 0;
11167
+ if (claimed === void 0) {
11168
+ return refusedExtension(basename6, ext);
11169
+ }
11170
+ const actual = sniffImageFormat(header);
11171
+ if (actual !== claimed) {
11172
+ return {
11173
+ ok: false,
11174
+ reason: `content is ${actual ?? "not a recognized image"} but the extension claims ${claimed} \u2014 evidence is admitted by content, not by name`
11175
+ };
11176
+ }
11177
+ return { ok: true };
11178
+ }
11179
+ __name(validateAssetContent, "validateAssetContent");
11042
11180
  var MAX_ASSET_BYTES = 10 * 1024 * 1024;
11043
11181
  var MAX_TOTAL_ASSET_BYTES = 40 * 1024 * 1024;
11044
11182
  function assetsBranch(pr) {
@@ -11073,12 +11211,9 @@ function parseAssetsRepo(value) {
11073
11211
  }
11074
11212
  __name(parseAssetsRepo, "parseAssetsRepo");
11075
11213
  function validateAssetFile(basename6, bytes) {
11076
- const ext = basename6.includes(".") ? basename6.slice(basename6.lastIndexOf(".") + 1).toLowerCase() : "";
11214
+ const ext = claimedExtension(basename6);
11077
11215
  if (!ASSET_EXTENSIONS.has(ext)) {
11078
- return {
11079
- ok: false,
11080
- reason: `${basename6}: extension ${JSON.stringify(ext)} is not an allowed evidence image type (${[...ASSET_EXTENSIONS].join(", ")})`
11081
- };
11216
+ return refusedExtension(basename6, ext);
11082
11217
  }
11083
11218
  if (bytes <= 0) {
11084
11219
  return { ok: false, reason: `${basename6}: empty file` };
@@ -11279,7 +11414,7 @@ function runPublishAssets(args) {
11279
11414
  for (const file of unique) {
11280
11415
  const abs = resolve10(file);
11281
11416
  try {
11282
- const st = statSync6(abs);
11417
+ const st = statSync7(abs);
11283
11418
  if (!st.isFile()) throw new Error("not a regular file");
11284
11419
  stats.push({ file, abs, basename: basename5(abs), bytes: st.size });
11285
11420
  } catch (err) {
@@ -11305,6 +11440,14 @@ function runPublishAssets(args) {
11305
11440
  );
11306
11441
  return;
11307
11442
  }
11443
+ const contentRuling = validateAssetContent(
11444
+ st.basename,
11445
+ content.subarray(0, ASSET_HEADER_BYTES)
11446
+ );
11447
+ if (!contentRuling.ok) {
11448
+ refuse(`${JSON.stringify(st.file)}: ${contentRuling.reason}`);
11449
+ return;
11450
+ }
11308
11451
  const sha256 = createHash2("sha256").update(content).digest("hex");
11309
11452
  prepared.push({
11310
11453
  file: st.file,
@@ -11430,13 +11573,13 @@ import { dirname as dirname12, resolve as resolve11 } from "node:path";
11430
11573
  // packages/cli/src/commands/review/lib/anchors.ts
11431
11574
  init_esbuild_shims();
11432
11575
  function collectNewSideLines(diffText, file) {
11433
- const lines2 = diffText.split("\n");
11576
+ const lines = diffText.split("\n");
11434
11577
  const out = [];
11435
11578
  for (const hunk of file.hunks) {
11436
11579
  if (hunk.newCount === 0) continue;
11437
11580
  let newCursor = hunk.newStart;
11438
11581
  for (let n = hunk.diffStart + 1; n <= hunk.diffEnd; n++) {
11439
- const raw = lines2[n - 1];
11582
+ const raw = lines[n - 1];
11440
11583
  if (raw === void 0) break;
11441
11584
  if (raw.startsWith("+")) {
11442
11585
  out.push({ newLine: newCursor, text: raw.slice(1), added: true });
@@ -11464,20 +11607,20 @@ function normalizeLoose(s) {
11464
11607
  }
11465
11608
  __name(normalizeLoose, "normalizeLoose");
11466
11609
  function anchorVariants(anchor) {
11467
- const lines2 = anchor.replace(/\r\n/g, "\n").split("\n");
11468
- while (lines2.length > 0 && lines2[0].trim() === "") lines2.shift();
11469
- while (lines2.length > 0 && lines2[lines2.length - 1].trim() === "") lines2.pop();
11470
- if (lines2.length === 0) return [];
11471
- const variants = [lines2];
11472
- const meaningful = lines2.filter((l) => l.trim() !== "");
11610
+ const lines = anchor.replace(/\r\n/g, "\n").split("\n");
11611
+ while (lines.length > 0 && lines[0].trim() === "") lines.shift();
11612
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") lines.pop();
11613
+ if (lines.length === 0) return [];
11614
+ const variants = [lines];
11615
+ const meaningful = lines.filter((l) => l.trim() !== "");
11473
11616
  if (meaningful.length > 0 && meaningful.every((l) => /^\+/.test(l))) {
11474
- variants.push(lines2.map((l) => l.startsWith("+") ? l.slice(1) : l));
11617
+ variants.push(lines.map((l) => l.startsWith("+") ? l.slice(1) : l));
11475
11618
  }
11476
11619
  const NO_NEWLINE = /^\$/;
11477
- const marked = lines2.filter((l) => l !== "" && !NO_NEWLINE.test(l));
11620
+ const marked = lines.filter((l) => l !== "" && !NO_NEWLINE.test(l));
11478
11621
  if (marked.length > 0 && marked.every((l) => /^[+\- ]/.test(l)) && marked.some((l) => l.startsWith("+"))) {
11479
11622
  variants.push(
11480
- lines2.filter((l) => !l.startsWith("-") && !NO_NEWLINE.test(l)).map((l) => l.slice(1))
11623
+ lines.filter((l) => !l.startsWith("-") && !NO_NEWLINE.test(l)).map((l) => l.slice(1))
11481
11624
  );
11482
11625
  }
11483
11626
  return variants;
@@ -11856,6 +11999,170 @@ import { createHash as createHash3 } from "node:crypto";
11856
11999
  import { readFileSync as readFileSync18 } from "node:fs";
11857
12000
  import { dirname as dirname14, join as join13, resolve as resolve13 } from "node:path";
11858
12001
 
12002
+ // packages/cli/src/commands/review/lib/retirement.ts
12003
+ init_esbuild_shims();
12004
+ import { statSync as statSync8 } from "node:fs";
12005
+ var REVERSE_AUDIT_MAX_ROUNDS = 5;
12006
+ var RECORD_KEY_RE = /^reverse-audit--chunk-(\d+)--round-(\d+)--[0-9a-f]+$/;
12007
+ var REVERSE_AUDIT_MARKER = "reverse-audit";
12008
+ function bakedRanges(prompt, diffPath) {
12009
+ const out = [];
12010
+ if (diffPath === void 0) return out;
12011
+ for (const m of prompt.matchAll(
12012
+ /read_file\(\s*file_path="([^"]*)",\s*offset=(\d+),\s*limit=(\d+)/gi
12013
+ )) {
12014
+ if (m[1] !== diffPath) continue;
12015
+ const offset = Number(m[2]);
12016
+ const limit = Number(m[3]);
12017
+ if (limit > 0) out.push([offset + 1, offset + limit]);
12018
+ }
12019
+ return out;
12020
+ }
12021
+ __name(bakedRanges, "bakedRanges");
12022
+ var FILE_LINE_RE = /\*\*File:\*\*\s*([^\n]*)/g;
12023
+ var SEVERITY_LINE_RE = /\*\*Severity:\*\*/;
12024
+ var DRY_RECEIPT_RE = new RegExp(
12025
+ '(?:\\bno (?:new )?(?:issues?|findings?|gaps?)[ \\w()]{0,32}?|\u672A\u53D1\u73B0(?:\u65B0\u7684?)?(?:\u95EE\u9898|\u53D1\u73B0)|\u65E0\u65B0\u7684?(?:\u95EE\u9898|\u53D1\u73B0)|\u6CA1\u6709(?:\u53D1\u73B0)?(?:\u65B0\u7684?)?\u95EE\u9898)\\s*[*_)\\]"\u201D\u2019]*\\s*(?:[\u2014\u2013]+|[:\uFF1A]|--+|-+\\s)\\s*([\\s\\S]*)',
12026
+ "i"
12027
+ );
12028
+ var CJK_RE = /[一-鿿]/g;
12029
+ var EXAMPLE_RECEIPT_CLAUSE = (DRY_RECEIPT_RE.exec(REVERSE_AUDIT_EXAMPLE_RECEIPT)?.[1] ?? "").trim();
12030
+ function substantiveClause(clause) {
12031
+ const c = clause.replace(/\s+/g, " ").trim();
12032
+ if (c.length === 0) return false;
12033
+ if (EXAMPLE_RECEIPT_CLAUSE.length > 0 && c.includes(EXAMPLE_RECEIPT_CLAUSE)) {
12034
+ return false;
12035
+ }
12036
+ if (/`[^`]+`/.test(c)) return true;
12037
+ if (/\w[\w.-]+\/[\w.$-]+\/\w/.test(c)) return true;
12038
+ if (/\w[\w.-]+\/[\w$-]+\.\w+/.test(c)) return true;
12039
+ if ((c.match(CJK_RE) ?? []).length >= 4) return true;
12040
+ return c.length >= 20;
12041
+ }
12042
+ __name(substantiveClause, "substantiveClause");
12043
+ function classifyReturn(rec, territory) {
12044
+ const text = rec.finalText.trim();
12045
+ if (SEVERITY_LINE_RE.test(text)) {
12046
+ for (const m of text.matchAll(FILE_LINE_RE)) {
12047
+ const file = (m[1] ?? "").trim();
12048
+ if (file === "" || /^N\/A\b/i.test(file)) continue;
12049
+ if (rec.launchPrompt.includes(`**File:** ${file}`)) continue;
12050
+ return "yielded";
12051
+ }
12052
+ }
12053
+ const receipt = DRY_RECEIPT_RE.exec(text);
12054
+ if (rec.successfulToolCalls > 0 && rec.diffToolCalls > 0 && openedTheTerritory(rec.diffReads, territory) && receipt !== null && substantiveClause(receipt[1] ?? "")) {
12055
+ return "dry";
12056
+ }
12057
+ return "unknown";
12058
+ }
12059
+ __name(classifyReturn, "classifyReturn");
12060
+ function openedTheTerritory(diffReads, territory) {
12061
+ if (territory.length === 0) return true;
12062
+ return diffReads.some(
12063
+ ([s, e]) => territory.some(([ts, te]) => s <= te && ts <= e)
12064
+ );
12065
+ }
12066
+ __name(openedTheTerritory, "openedTheTerritory");
12067
+ function mergeOutcomes(outcomes) {
12068
+ if (outcomes.includes("yielded")) return "yielded";
12069
+ if (outcomes.includes("dry")) return "dry";
12070
+ return "unknown";
12071
+ }
12072
+ __name(mergeOutcomes, "mergeOutcomes");
12073
+ function scheduleReverseAuditRound(planPath, chunkIds, round, env = process.env, diffPath) {
12074
+ if (round < 3) {
12075
+ return {
12076
+ due: [...chunkIds],
12077
+ coldChecks: [],
12078
+ skipped: [],
12079
+ converged: false
12080
+ };
12081
+ }
12082
+ const since = statSync8(planPath).mtimeMs;
12083
+ const transcripts = readTranscripts(since, env, diffPath);
12084
+ const built = readRecordedPrompts(planPath, since);
12085
+ const records = [];
12086
+ for (const [key, prompt] of built) {
12087
+ const m = RECORD_KEY_RE.exec(key);
12088
+ if (!m) continue;
12089
+ const r = Number(m[2]);
12090
+ if (r >= round) continue;
12091
+ records.push({
12092
+ chunkId: Number(m[1]),
12093
+ round: r,
12094
+ // Flattened ONCE per record, beside the once-per-transcript flatten
12095
+ // below: the pairing walk pays neither half per (record, transcript)
12096
+ // pair.
12097
+ lines: promptLines(prompt),
12098
+ territory: bakedRanges(prompt, diffPath)
12099
+ });
12100
+ }
12101
+ const candidates = transcripts.filter((t2) => t2.launchPrompt.includes(REVERSE_AUDIT_MARKER)).map((t2) => ({ transcript: t2, flat: flattenPrompt(t2.launchPrompt) }));
12102
+ const matchesByRecord = records.map(
12103
+ (rec) => candidates.filter((c) => deliveredVerbatimLines(c.flat, rec.lines)).map((c) => c.transcript)
12104
+ );
12105
+ const recordsPerTranscript = /* @__PURE__ */ new Map();
12106
+ for (const matches of matchesByRecord) {
12107
+ for (const t2 of matches) {
12108
+ recordsPerTranscript.set(t2, (recordsPerTranscript.get(t2) ?? 0) + 1);
12109
+ }
12110
+ }
12111
+ const outcomesByRecord = matchesByRecord.map(
12112
+ (matches, i) => matches.filter((t2) => recordsPerTranscript.get(t2) === 1).map((t2) => classifyReturn(t2, records[i].territory))
12113
+ );
12114
+ const history = /* @__PURE__ */ new Map();
12115
+ records.forEach((rec, i) => {
12116
+ let byRound = history.get(rec.chunkId);
12117
+ if (!byRound) {
12118
+ byRound = /* @__PURE__ */ new Map();
12119
+ history.set(rec.chunkId, byRound);
12120
+ }
12121
+ byRound.set(rec.round, [
12122
+ ...byRound.get(rec.round) ?? [],
12123
+ ...outcomesByRecord[i]
12124
+ ]);
12125
+ });
12126
+ const due = [];
12127
+ const coldChecks = [];
12128
+ const skipped = [];
12129
+ for (const chunkId of chunkIds) {
12130
+ const audits = [...history.get(chunkId)?.entries() ?? []].map(([r, outcomes]) => ({ round: r, outcome: mergeOutcomes(outcomes) })).sort((a, b) => a.round - b.round);
12131
+ const lastTwo = audits.slice(-2);
12132
+ const retired = lastTwo.length === 2 && lastTwo.every((a) => a.outcome === "dry");
12133
+ if (!retired) {
12134
+ due.push(chunkId);
12135
+ continue;
12136
+ }
12137
+ if (round % 2 === 0) {
12138
+ due.push(chunkId);
12139
+ coldChecks.push(chunkId);
12140
+ } else {
12141
+ skipped.push({
12142
+ chunkId,
12143
+ dryRounds: [lastTwo[0].round, lastTwo[1].round],
12144
+ // The next even round — this branch only runs on odd rounds, so
12145
+ // that is always round + 1. Whether the cap allows it is the note
12146
+ // composer's question, not the schedule's (see
12147
+ // REVERSE_AUDIT_MAX_ROUNDS).
12148
+ nextColdCheck: round + 1
12149
+ });
12150
+ }
12151
+ }
12152
+ return {
12153
+ due,
12154
+ coldChecks,
12155
+ skipped,
12156
+ // An empty `chunkIds` empties `due` vacuously — nothing was ever under
12157
+ // audit, so nothing has proven itself cold. `runAllChunks` refuses a
12158
+ // chunkless plan long before scheduling, but this function is exported,
12159
+ // and convergence is an exit-5 termination rule: it must not be
12160
+ // reachable from nothing.
12161
+ converged: chunkIds.length > 0 && due.length === 0
12162
+ };
12163
+ }
12164
+ __name(scheduleReverseAuditRound, "scheduleReverseAuditRound");
12165
+
11859
12166
  // packages/cli/src/commands/review/lib/path-rules.ts
11860
12167
  init_esbuild_shims();
11861
12168
  var GITHUB_ACTIONS = {
@@ -12579,11 +12886,57 @@ function requireAuditableChunks(report) {
12579
12886
  return chunks;
12580
12887
  }
12581
12888
  __name(requireAuditableChunks, "requireAuditableChunks");
12889
+ function admitReverseAuditRound(planPath, round) {
12890
+ const spent = reverseAuditBudgetExhausted(
12891
+ process.env,
12892
+ expectedRoundSeconds(planPath, round)
12893
+ );
12894
+ if (spent !== null) {
12895
+ writeBudgetStop(planPath, spent, round);
12896
+ writeStderrLine(reverseAuditBudgetMessage(spent, round));
12897
+ process.exitCode = 4;
12898
+ return false;
12899
+ }
12900
+ return true;
12901
+ }
12902
+ __name(admitReverseAuditRound, "admitReverseAuditRound");
12903
+ function refuseConverged() {
12904
+ writeStderrLine(
12905
+ "CONVERGED: every chunk holds two consecutive substantive dry audits; the reverse audit has converged \u2014 stop the loop and proceed to Step 6. This is a clean convergence, not a gap: no unreviewedDimensions entry is owed."
12906
+ );
12907
+ process.exitCode = 5;
12908
+ }
12909
+ __name(refuseConverged, "refuseConverged");
12582
12910
  function runAllChunks(report, planPath, role, findingsContent, rules, round) {
12583
12911
  const chunks = requireAuditableChunks(report);
12912
+ let schedule = null;
12913
+ if (role === "reverse-audit" && round !== void 0 && round >= 3) {
12914
+ try {
12915
+ schedule = scheduleReverseAuditRound(
12916
+ planPath,
12917
+ chunks.map((c) => c.id),
12918
+ round,
12919
+ process.env,
12920
+ typeof report.diffPathAbsolute === "string" ? report.diffPathAbsolute : void 0
12921
+ );
12922
+ } catch {
12923
+ schedule = null;
12924
+ }
12925
+ }
12926
+ if (schedule !== null && schedule.converged) {
12927
+ refuseConverged();
12928
+ return;
12929
+ }
12930
+ if (role === "reverse-audit" && !admitReverseAuditRound(planPath, round)) {
12931
+ return;
12932
+ }
12933
+ const dueSet = schedule === null ? null : new Set(schedule.due);
12934
+ const dueChunks = dueSet === null ? chunks : chunks.filter((c) => dueSet.has(c.id));
12935
+ const coldSet = new Set(schedule?.coldChecks ?? []);
12936
+ const skipped = schedule?.skipped ?? [];
12584
12937
  const digest = findingsDigest(findingsContent, rules);
12585
12938
  const roundPart = round !== void 0 ? `--round-${round}` : "";
12586
- const blocks = chunks.map((c, i) => {
12939
+ const blocks = dueChunks.map((c, i) => {
12587
12940
  const key = `${role}--chunk-${c.id}${roundPart}--${digest}`;
12588
12941
  const { prompt } = buildLaunch(
12589
12942
  report,
@@ -12593,17 +12946,29 @@ function runAllChunks(report, planPath, role, findingsContent, rules, round) {
12593
12946
  );
12594
12947
  const printed = foldFindings(role, findingsContent, prompt);
12595
12948
  recordPrompt(planPath, key, printed);
12596
- return `\u2500\u2500\u2500\u2500\u2500 auditor ${i + 1} of ${chunks.length} \u2014 chunk ${c.id} \u2500\u2500\u2500\u2500\u2500
12949
+ const cold = coldSet.has(c.id) ? " (cold check)" : "";
12950
+ return `\u2500\u2500\u2500\u2500\u2500 auditor ${i + 1} of ${dueChunks.length} \u2014 chunk ${c.id}${cold} \u2500\u2500\u2500\u2500\u2500
12597
12951
 
12598
12952
  ` + printed;
12599
12953
  });
12954
+ const scope = skipped.length === 0 ? "one per chunk" : `one per chunk still under audit (${skipped.length} retired chunk(s) skipped; the retirement note after the end-of-round line says which \u2014 relay it to the terminal)`;
12955
+ const retirementNote = skipped.length === 0 ? [] : [
12956
+ `retirement: a chunk whose two most recent audits are substantive dry receipts is cold-checked on alternating rounds instead of audited on every one; a cold check that yields returns it to every-round auditing. Skipped this round:
12957
+ ` + skipped.map(
12958
+ (s) => `chunk ${s.chunkId} \u2014 retired: dry in rounds ${s.dryRounds[0]} and ${s.dryRounds[1]}, ` + (s.nextColdCheck > REVERSE_AUDIT_MAX_ROUNDS ? `certificate final \u2014 the ${REVERSE_AUDIT_MAX_ROUNDS}-round hard cap leaves the loop no round for a cold check` : `next cold check round ${s.nextColdCheck}`)
12959
+ ).join("\n")
12960
+ ];
12600
12961
  writeStdoutLine(
12601
12962
  [
12602
- `${chunks.length} auditors required this round \u2014 one per chunk. Launch one agent per block below, passing its block VERBATIM \u2014 copy, do not retype, and NEVER sample this output (no \`| head\`): the text IS the deliverable, and a launch reconstructed from a sample matches no record. Blocks are numbered \`auditor k of ${chunks.length}\` and the output ends with an end-of-round line \u2014 if either is missing, the output was truncated in transit; rebuild just the missing chunks with --chunk <id>. Write each Agent call's \`description\` (the task name the user watches) in your output language, translating the separator label \u2014 display only; the prompt stays the block VERBATIM.`,
12963
+ `${dueChunks.length} auditors required this round \u2014 ${scope}. Launch one agent per block below, passing its block VERBATIM \u2014 copy, do not retype, and NEVER sample this output (no \`| head\`): the text IS the deliverable, and a launch reconstructed from a sample matches no record. Blocks are numbered \`auditor k of ${dueChunks.length}\`, and the output ends with an end-of-round line \u2014 followed by the retirement note, when there is one. If either the numbering or the end-of-round line is missing, the output was truncated in transit; rebuild just the missing chunks with --chunk <id>. Write each Agent call's \`description\` (the task name the user watches) in your output language, translating the separator label \u2014 display only; the prompt stays the block VERBATIM.`,
12603
12964
  ...blocks,
12604
- `\u2500\u2500\u2500\u2500\u2500 end of round \u2014 ${chunks.length} auditors \u2500\u2500\u2500\u2500\u2500`
12965
+ `\u2500\u2500\u2500\u2500\u2500 end of round \u2014 ${dueChunks.length} auditors \u2500\u2500\u2500\u2500\u2500`,
12966
+ ...retirementNote
12605
12967
  ].join("\n\n")
12606
12968
  );
12969
+ if (role === "reverse-audit") {
12970
+ stampRound(planPath, round);
12971
+ }
12607
12972
  }
12608
12973
  __name(runAllChunks, "runAllChunks");
12609
12974
  function runAgentPrompt(args) {
@@ -12757,20 +13122,29 @@ function runAgentPrompt(args) {
12757
13122
  );
12758
13123
  }
12759
13124
  }
12760
- if (args.allChunks && args.role && findingsContent !== void 0) {
12761
- requireAuditableChunks(report);
13125
+ if (args.role === "reverse-audit" && !hasChunk && !args.allChunks && !admitReverseAuditRound(args.plan, args.round)) {
13126
+ return;
12762
13127
  }
12763
- if (args.role === "reverse-audit") {
12764
- const spent = reverseAuditBudgetExhausted(
12765
- process.env,
12766
- expectedRoundSeconds(args.plan, args.round)
12767
- );
12768
- if (spent !== null) {
12769
- writeBudgetStop(args.plan, spent, args.round);
12770
- writeStderrLine(reverseAuditBudgetMessage(spent, args.round));
12771
- process.exitCode = 4;
12772
- return;
13128
+ if (args.role === "reverse-audit" && hasChunk && !readRoundStamps(args.plan).some((s) => s.round === (args.round ?? null))) {
13129
+ if (args.round !== void 0) {
13130
+ let schedule = null;
13131
+ try {
13132
+ schedule = scheduleReverseAuditRound(
13133
+ args.plan,
13134
+ (Array.isArray(report.chunks) ? report.chunks : []).map((c) => c?.id).filter((id) => typeof id === "number"),
13135
+ args.round,
13136
+ process.env,
13137
+ typeof report.diffPathAbsolute === "string" ? report.diffPathAbsolute : void 0
13138
+ );
13139
+ } catch {
13140
+ schedule = null;
13141
+ }
13142
+ if (schedule !== null && schedule.converged) {
13143
+ refuseConverged();
13144
+ return;
13145
+ }
12773
13146
  }
13147
+ if (!admitReverseAuditRound(args.plan, args.round)) return;
12774
13148
  }
12775
13149
  if (args.allChunks && args.role && findingsContent !== void 0) {
12776
13150
  runAllChunks(
@@ -12781,9 +13155,6 @@ function runAgentPrompt(args) {
12781
13155
  rules,
12782
13156
  args.round
12783
13157
  );
12784
- if (args.role === "reverse-audit") {
12785
- stampRound(args.plan, args.round);
12786
- }
12787
13158
  return;
12788
13159
  }
12789
13160
  let prompt;
@@ -12821,7 +13192,7 @@ function runAgentPrompt(args) {
12821
13192
  __name(runAgentPrompt, "runAgentPrompt");
12822
13193
  var agentPromptCommand = {
12823
13194
  command: "agent-prompt",
12824
- describe: "Build a review agent's launch prompt from the plan (the diff path, its line ranges and the agent's own brief are welded in, not left to the caller to remember). Exit codes: 0 built; 4 the review time budget refused another reverse-audit round (a termination rule, not an error \u2014 see the BUDGET line on stderr); anything else is a bad call or a broken plan.",
13195
+ describe: "Build a review agent's launch prompt from the plan (the diff path, its line ranges and the agent's own brief are welded in, not left to the caller to remember). Exit codes: 0 built; 4 the review time budget refused another reverse-audit round (a termination rule, not an error \u2014 see the BUDGET line on stderr); 5 the reverse audit CONVERGED \u2014 every chunk holds two consecutive substantive dry audits and none is due a cold check, so stop the loop and proceed to Step 6 (also a termination rule, and a clean one: no disclosure is owed); anything else is a bad call or a broken plan.",
12825
13196
  builder: /* @__PURE__ */ __name((yargs) => yargs.option("plan", {
12826
13197
  type: "string",
12827
13198
  demandOption: true,
@@ -12832,13 +13203,13 @@ var agentPromptCommand = {
12832
13203
  describe: "The dimension this agent owns. Builds its WHOLE prompt \u2014 the diff's line ranges, the brief, the finding format, the severity definitions and the project rules. Pass it to the agent verbatim."
12833
13204
  }).option("chunk", {
12834
13205
  type: "number",
12835
- describe: "Which chunk id this agent owns (a Step 3B territory agent)"
13206
+ describe: "Which chunk id this agent owns (a Step 3B territory agent). With --role reverse-audit --round N it rebuilds ONE auditor of that round: a round already admitted is repaired without gates; a round never admitted answers to the same convergence and budget gates as --all-chunks."
12836
13207
  }).option("file", {
12837
13208
  type: "string",
12838
13209
  describe: "The heavily-rewritten file an invariant agent owns (--role invariant-a|invariant-b|invariant-c)"
12839
13210
  }).option("all-chunks", {
12840
13211
  type: "boolean",
12841
- describe: "With --role reverse-audit --findings: build one block per chunk in one call, labelled and separated (Step 5, 3B). Never sample the output; each block is pasted verbatim to its own agent."
13212
+ describe: "With --role reverse-audit --findings: build one block per chunk in one call, labelled and separated (Step 5, 3B). Never sample the output; each block is pasted verbatim to its own agent. From --round 3 on, a chunk whose two most recent audits were both substantive dry receipts is retired to alternating-round cold checks (the retirement note after the end-of-round line says which); a round where every chunk is retired and none is due exits 5 \u2014 the audit has converged."
12842
13213
  }).option("roster", {
12843
13214
  type: "boolean",
12844
13215
  describe: "Build EVERY prompt the plan requires \u2014 chunk, dimension and invariant agents alike \u2014 in one call, each labelled and separated. The list is the same one check-coverage reads out of the plan."
@@ -12894,9 +13265,10 @@ __name(isWorkspaceMember, "isWorkspaceMember");
12894
13265
  function workspaceDirFor(filePath, workspaceGlobs) {
12895
13266
  const norm = filePath.replace(/^\.\//, "");
12896
13267
  let owner = null;
13268
+ const previous = [];
12897
13269
  for (const glob of workspaceGlobs) {
12898
13270
  const negated = glob.startsWith("!");
12899
- const g = glob.replace(/^!/, "").replace(/\/$/, "");
13271
+ const g = glob.replace(/^!/, "").replace(/^\.\//, "").replace(/\/$/, "");
12900
13272
  let dir = null;
12901
13273
  if (g.endsWith("/*")) {
12902
13274
  const base = g.slice(0, -2);
@@ -12908,14 +13280,27 @@ function workspaceDirFor(filePath, workspaceGlobs) {
12908
13280
  dir = g;
12909
13281
  }
12910
13282
  if (dir === null) continue;
12911
- owner = negated ? null : dir;
13283
+ if (!negated) {
13284
+ if (dir !== owner) {
13285
+ previous.push(owner);
13286
+ owner = dir;
13287
+ }
13288
+ } else if (dir === owner) {
13289
+ owner = previous.pop() ?? null;
13290
+ }
12912
13291
  }
12913
13292
  return owner;
12914
13293
  }
12915
13294
  __name(workspaceDirFor, "workspaceDirFor");
13295
+ function isNegationExcluded(filePath, workspaceGlobs) {
13296
+ if (workspaceDirFor(filePath, workspaceGlobs) !== null) return false;
13297
+ const positives = workspaceGlobs.filter((g) => !g.startsWith("!"));
13298
+ return workspaceDirFor(filePath, positives) !== null;
13299
+ }
13300
+ __name(isNegationExcluded, "isNegationExcluded");
12916
13301
  function hasUnmodeledWorkspaceGlob(globs) {
12917
13302
  return globs.some((glob) => {
12918
- const g = glob.replace(/^!/, "");
13303
+ const g = glob.replace(/^!/, "").replace(/^\.\//, "");
12919
13304
  if (!g.includes("*")) return false;
12920
13305
  return !/^[^*]+\/\*$/.test(g);
12921
13306
  });
@@ -12941,27 +13326,47 @@ function readRootPackage(root) {
12941
13326
  } catch {
12942
13327
  return null;
12943
13328
  }
13329
+ if (pkg === null) return null;
12944
13330
  const scripts = Object.keys(pkg.scripts ?? {});
12945
13331
  if (!scripts.includes("build") && !scripts.includes("test")) return null;
13332
+ const scriptsText = {};
13333
+ for (const [k, v] of Object.entries(pkg.scripts ?? {})) {
13334
+ if (typeof v === "string") scriptsText[k] = v;
13335
+ }
12946
13336
  return {
12947
13337
  dir: ".",
12948
13338
  name: typeof pkg.name === "string" && pkg.name ? pkg.name : "root",
12949
13339
  scripts,
12950
- deps: []
13340
+ deps: declaredDeps(pkg),
13341
+ scriptsText
12951
13342
  };
12952
13343
  }
12953
13344
  __name(readRootPackage, "readRootPackage");
12954
- function readWorkspacePackages(root) {
12955
- const globs = readWorkspaceGlobs(root);
13345
+ function scriptFansOut(text) {
13346
+ return typeof text === "string" && /(^|\s)(--workspaces(?=\s|$)|--?ws(?=\s|$))/.test(text);
13347
+ }
13348
+ __name(scriptFansOut, "scriptFansOut");
13349
+ function declaredDeps(pkg) {
13350
+ return [
13351
+ ...Object.keys(pkg.dependencies ?? {}),
13352
+ ...Object.keys(pkg.devDependencies ?? {}),
13353
+ ...Object.keys(pkg.peerDependencies ?? {}),
13354
+ ...Object.keys(pkg.optionalDependencies ?? {})
13355
+ ];
13356
+ }
13357
+ __name(declaredDeps, "declaredDeps");
13358
+ function workspaceDirCandidates(root, globs) {
12956
13359
  const dirs = /* @__PURE__ */ new Set();
12957
13360
  for (const glob of globs) {
12958
13361
  if (glob.startsWith("!")) continue;
12959
- const g = glob.replace(/\/$/, "");
13362
+ const g = glob.replace(/^\.\//, "").replace(/\/$/, "");
12960
13363
  if (g.endsWith("/*")) {
12961
13364
  const base = g.slice(0, -2);
12962
13365
  let entries;
12963
13366
  try {
12964
- entries = readdirSync4(join14(root, base), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
13367
+ entries = readdirSync4(join14(root, base), { withFileTypes: true }).filter(
13368
+ (e) => e.isDirectory() || e.isSymbolicLink() && existsSync6(join14(root, base, e.name, "package.json"))
13369
+ ).map((e) => e.name);
12965
13370
  } catch {
12966
13371
  continue;
12967
13372
  }
@@ -12970,30 +13375,43 @@ function readWorkspacePackages(root) {
12970
13375
  dirs.add(g);
12971
13376
  }
12972
13377
  }
12973
- const pkgs = [];
12974
- for (const dir of dirs) {
12975
- if (workspaceDirFor(`${dir}/package.json`, globs) !== dir) continue;
13378
+ return [...dirs].sort();
13379
+ }
13380
+ __name(workspaceDirCandidates, "workspaceDirCandidates");
13381
+ function readWorkspacePackages(root) {
13382
+ const globs = readWorkspaceGlobs(root);
13383
+ const packages = [];
13384
+ const skipped = [];
13385
+ for (const dir of workspaceDirCandidates(root, globs)) {
12976
13386
  const manifest = join14(root, dir, "package.json");
12977
13387
  if (!existsSync6(manifest)) continue;
13388
+ if (workspaceDirFor(`${dir}/package.json`, globs) !== dir) {
13389
+ const positives = globs.filter((g) => !g.startsWith("!"));
13390
+ if (workspaceDirFor(`${dir}/package.json`, positives) === dir) continue;
13391
+ skipped.push(dir);
13392
+ continue;
13393
+ }
12978
13394
  let pkg;
12979
13395
  try {
12980
13396
  pkg = JSON.parse(readFileSync19(manifest, "utf8"));
12981
13397
  } catch {
13398
+ skipped.push(dir);
13399
+ continue;
13400
+ }
13401
+ if (pkg === null || typeof pkg.name !== "string" || !pkg.name) {
13402
+ skipped.push(dir);
12982
13403
  continue;
12983
13404
  }
12984
- if (typeof pkg.name !== "string" || !pkg.name) continue;
12985
- pkgs.push({
13405
+ packages.push({
12986
13406
  dir,
12987
13407
  name: pkg.name,
12988
13408
  scripts: Object.keys(pkg.scripts ?? {}),
12989
- deps: [
12990
- ...Object.keys(pkg.dependencies ?? {}),
12991
- ...Object.keys(pkg.devDependencies ?? {}),
12992
- ...Object.keys(pkg.peerDependencies ?? {})
12993
- ]
13409
+ deps: declaredDeps(pkg)
12994
13410
  });
12995
13411
  }
12996
- return pkgs.sort((a, b) => a.dir.localeCompare(b.dir));
13412
+ packages.sort((a, b) => a.dir.localeCompare(b.dir));
13413
+ skipped.sort();
13414
+ return { packages, skipped };
12997
13415
  }
12998
13416
  __name(readWorkspacePackages, "readWorkspacePackages");
12999
13417
  function affectedWorkspaces(changedFiles, workspaceGlobs) {
@@ -13005,8 +13423,7 @@ function affectedWorkspaces(changedFiles, workspaceGlobs) {
13005
13423
  return [...dirs].sort();
13006
13424
  }
13007
13425
  __name(affectedWorkspaces, "affectedWorkspaces");
13008
- function buildSetFor(affected, packages, alsoBuild = []) {
13009
- const byDir = new Map(packages.map((p) => [p.dir, p]));
13426
+ function dependencyEdges(packages) {
13010
13427
  const byName = new Map(packages.map((p) => [p.name, p]));
13011
13428
  const dependsOn = /* @__PURE__ */ new Map();
13012
13429
  for (const p of packages) {
@@ -13015,6 +13432,12 @@ function buildSetFor(affected, packages, alsoBuild = []) {
13015
13432
  p.deps.map((d) => byName.get(d)?.dir).filter((d) => !!d && d !== p.dir)
13016
13433
  );
13017
13434
  }
13435
+ return dependsOn;
13436
+ }
13437
+ __name(dependencyEdges, "dependencyEdges");
13438
+ function reverseDependencyClosure(affected, packages) {
13439
+ const byDir = new Map(packages.map((p) => [p.dir, p]));
13440
+ const dependsOn = dependencyEdges(packages);
13018
13441
  const consumers = new Set(affected.filter((a) => byDir.has(a)));
13019
13442
  let grew = true;
13020
13443
  while (grew) {
@@ -13027,6 +13450,13 @@ function buildSetFor(affected, packages, alsoBuild = []) {
13027
13450
  }
13028
13451
  }
13029
13452
  }
13453
+ return [...consumers].sort();
13454
+ }
13455
+ __name(reverseDependencyClosure, "reverseDependencyClosure");
13456
+ function buildSetFor(affected, packages, alsoBuild = []) {
13457
+ const byDir = new Map(packages.map((p) => [p.dir, p]));
13458
+ const dependsOn = dependencyEdges(packages);
13459
+ const consumers = reverseDependencyClosure(affected, packages);
13030
13460
  const wanted = /* @__PURE__ */ new Set();
13031
13461
  const addDeps = /* @__PURE__ */ __name((dir) => {
13032
13462
  if (wanted.has(dir)) return;
@@ -13051,13 +13481,81 @@ function buildSetFor(affected, packages, alsoBuild = []) {
13051
13481
  }
13052
13482
  __name(buildSetFor, "buildSetFor");
13053
13483
 
13484
+ // packages/cli/src/commands/review/lib/workspace-scope.ts
13485
+ init_esbuild_shims();
13486
+ var LICENSE_LIKE_RE = /(^|\/)(LICEN[CS]ES?|COPYING|NOTICES?)(-[^/.]+)?(\.(md|txt|rst))?$/;
13487
+ function isInertLicense(path3) {
13488
+ return LICENSE_LIKE_RE.test(path3);
13489
+ }
13490
+ __name(isInertLicense, "isInertLicense");
13491
+ var INERT_OUTSIDE_RE = /^(\.github\/|CHANGELOG\.md$|\.gitignore$|\.gitattributes$|\.editorconfig$|\.idea\/|\.vscode\/)/;
13492
+ function resolveTestScope(input) {
13493
+ const { changed, globs, packages, skipped } = input;
13494
+ const affected = affectedWorkspaces(changed, globs);
13495
+ const graph = input.rootPackage ? [input.rootPackage, ...packages] : packages;
13496
+ const scriptsOf = new Map(graph.map((p) => [p.dir, p.scripts]));
13497
+ const caveats = [];
13498
+ if (skipped.length > 0) {
13499
+ caveats.push(
13500
+ `the workspace graph could not be fully computed: ${skipped.join(", ")} ${skipped.length === 1 ? "has" : "have"} a package.json that does not parse, has no usable \`name\`, or is shadowed by a later workspace glob, so a reverse dependency may be missing from the scoped set`
13501
+ );
13502
+ }
13503
+ const unmapped = affected.filter(
13504
+ (d) => d !== "." && !scriptsOf.has(d) && !skipped.includes(d)
13505
+ );
13506
+ const outside = changed.filter((f) => workspaceDirFor(f, globs) === null);
13507
+ const excluded = outside.filter((f) => isNegationExcluded(f, globs));
13508
+ const influential = outside.filter(
13509
+ (f) => !isInertLicense(f) && !f.startsWith("docs/") && !INERT_OUTSIDE_RE.test(f) && !isNegationExcluded(f, globs)
13510
+ );
13511
+ if (unmapped.length > 0) {
13512
+ caveats.push(
13513
+ `the workspace globs claim ${unmapped.join(", ")}, but no readable package.json there makes a graph member \u2014 no suite covers a change inside, and a dependent of the diff may be missing from the scoped set`
13514
+ );
13515
+ }
13516
+ if (influential.length > 0) {
13517
+ caveats.push(
13518
+ `${influential.length} changed file(s) sit outside every workspace and are not inert (e.g. ${influential.slice(0, 3).join(", ")}); a root script or config can affect any package's tests, and the scoped set cannot cover them`
13519
+ );
13520
+ }
13521
+ if (excluded.length > 0) {
13522
+ caveats.push(
13523
+ `${excluded.length} changed file(s) sit in negated workspaces (e.g. ${excluded.slice(0, 3).join(", ")}) \u2014 excluded from the npm workspace graph (a separate toolchain and lockfile); their own toolchain's suites were not run`
13524
+ );
13525
+ }
13526
+ const closure = reverseDependencyClosure(affected, graph);
13527
+ let workspaces = closure.filter((d) => scriptsOf.get(d)?.includes("test"));
13528
+ let fanOutCaveat;
13529
+ if (input.rootTestFansOut && workspaces.includes(".")) {
13530
+ workspaces = workspaces.filter((d) => d !== ".");
13531
+ fanOutCaveat = "the root's `test` script fans out over every workspace (`--workspaces`), so the root suite did not run \u2014 it cannot finish inside one command deadline; the scoped member suites are the coverage";
13532
+ }
13533
+ {
13534
+ const rootRuns = input.rootPackage?.scripts.includes("test") && !input.rootTestFansOut ? 1 : 0;
13535
+ const testable = packages.filter((p) => p.scripts.includes("test")).length + rootRuns;
13536
+ const scoped = workspaces.length;
13537
+ if (scoped * 2 > testable) {
13538
+ caveats.push(
13539
+ `the diff's reverse-dependency closure covers ${scoped} of ${testable} testable ${rootRuns ? "suites (including the root)" : "workspaces"} \u2014 more than half, so the scoped set is not a meaningful narrowing`
13540
+ );
13541
+ }
13542
+ }
13543
+ if (fanOutCaveat) caveats.push(fanOutCaveat);
13544
+ return caveats.length > 0 ? { workspaces, caveat: caveats.join("; ") } : { workspaces };
13545
+ }
13546
+ __name(resolveTestScope, "resolveTestScope");
13547
+
13054
13548
  // packages/cli/src/commands/review/build-test.ts
13549
+ function shellArg(dir) {
13550
+ return `"${dir.replace(/[\\"$`]/g, "\\$&")}"`;
13551
+ }
13552
+ __name(shellArg, "shellArg");
13055
13553
  function buildCommand(dir) {
13056
- return dir === "." ? "npm run build" : `npm run build --workspace="${dir}"`;
13554
+ return dir === "." ? "npm run build" : `npm run build --workspace=${shellArg(dir)}`;
13057
13555
  }
13058
13556
  __name(buildCommand, "buildCommand");
13059
13557
  function testCommand(dir) {
13060
- return dir === "." ? "npm test" : `npm test --workspace="${dir}"`;
13558
+ return dir === "." ? "npm test" : `npm test --workspace=${shellArg(dir)}`;
13061
13559
  }
13062
13560
  __name(testCommand, "testCommand");
13063
13561
  var KEEP_HEAD = 2e3;
@@ -13092,6 +13590,7 @@ ${rescued.join("\n")}
13092
13590
  __name(trimOutput, "trimOutput");
13093
13591
  var INSTALL_MIN_FREE_BYTES = 3 * 1024 ** 3;
13094
13592
  var BUILD_MIN_FREE_BYTES = 1024 ** 3;
13593
+ var BUDGET_MIN_ATTEMPT_MS = 15e3;
13095
13594
  function freeDiskBytes(dir) {
13096
13595
  try {
13097
13596
  const s = statfsSync(dir);
@@ -13129,7 +13628,8 @@ function run(command, cwd, timeoutMs) {
13129
13628
  exitCode: r.status,
13130
13629
  seconds: Math.round((Date.now() - started) / 1e3),
13131
13630
  timedOut,
13132
- output: trimOutput(`${r.stdout ?? ""}${r.stderr ?? ""}`)
13631
+ output: trimOutput(`${r.stdout ?? ""}${r.stderr ?? ""}`),
13632
+ deadlineMs: timeoutMs
13133
13633
  };
13134
13634
  }
13135
13635
  __name(run, "run");
@@ -13169,6 +13669,10 @@ __name(changedFilesFrom, "changedFilesFrom");
13169
13669
  function runBuildTest(args) {
13170
13670
  const root = resolve14(args.worktree);
13171
13671
  const perCommandMs = args.timeout * 1e3;
13672
+ const callBudgetMs = (args.budget ?? Math.max(args.timeout, args.timeout * 2 - 30)) * 1e3;
13673
+ const runStarted = Date.now();
13674
+ const remainingMs = /* @__PURE__ */ __name(() => callBudgetMs - (Date.now() - runStarted), "remainingMs");
13675
+ const deadlineSecs = /* @__PURE__ */ __name((r) => Math.round((r.deadlineMs ?? perCommandMs) / 1e3), "deadlineSecs");
13172
13676
  const exec = args.exec ?? run;
13173
13677
  const changed = changedFilesFrom(args.plan);
13174
13678
  const unsupportedReport = /* @__PURE__ */ __name((note) => ({
@@ -13184,15 +13688,13 @@ function runBuildTest(args) {
13184
13688
  note
13185
13689
  }), "unsupportedReport");
13186
13690
  const globs = readWorkspaceGlobs(root);
13187
- let packages = readWorkspacePackages(root);
13691
+ let { packages, skipped } = readWorkspacePackages(root);
13692
+ const rootPkg = readRootPackage(root);
13188
13693
  let singleRoot = false;
13189
13694
  const unmodeled = globs.length > 0 && hasUnmodeledWorkspaceGlob(globs);
13190
- if (!unmodeled && globs.length === 0) {
13191
- const rootPkg = readRootPackage(root);
13192
- if (rootPkg) {
13193
- packages = [rootPkg];
13194
- singleRoot = true;
13195
- }
13695
+ if (!unmodeled && globs.length === 0 && rootPkg) {
13696
+ packages = [rootPkg];
13697
+ singleRoot = true;
13196
13698
  }
13197
13699
  if (unmodeled || !singleRoot && (globs.length === 0 || packages.length === 0)) {
13198
13700
  return unsupportedReport(
@@ -13200,6 +13702,15 @@ function runBuildTest(args) {
13200
13702
  );
13201
13703
  }
13202
13704
  const affected = singleRoot ? changed.length > 0 ? ["."] : [] : affectedWorkspaces(changed, globs);
13705
+ let testScope = singleRoot || args.buildOnly ? void 0 : resolveTestScope({
13706
+ changed,
13707
+ globs,
13708
+ packages,
13709
+ skipped,
13710
+ rootPackage: rootPkg,
13711
+ rootTestFansOut: rootPkg?.scripts.includes("test") ? scriptFansOut(rootPkg.scriptsText["test"]) : false
13712
+ });
13713
+ const scopeGraph = !singleRoot && rootPkg ? [rootPkg, ...packages] : packages;
13203
13714
  if (affected.length === 0) {
13204
13715
  return {
13205
13716
  toolchain: "npm",
@@ -13209,12 +13720,13 @@ function runBuildTest(args) {
13209
13720
  install: null,
13210
13721
  build: [],
13211
13722
  test: [],
13723
+ ...testScope ? { testScope } : {},
13212
13724
  ok: true,
13213
13725
  timedOut: [],
13214
- note: `The diff changes ${changed.length} file(s), none of them inside a workspace (docs, root config, CI). There is no package to build and no test to run \u2014 this is a complete answer, not a skipped step.`
13726
+ note: args.buildOnly ? `The diff changes ${changed.length} file(s), none of them inside a workspace. There is no package to build, and tests are out of scope for a build-only probe.` : testScope?.caveat ? `The diff changes ${changed.length} file(s), none of them inside a workspace. There is no package to build and no test to run, but the scope decision recorded a caveat: ${testScope.caveat}.` : `The diff changes ${changed.length} file(s), none of them inside a workspace (nothing the workspaces' tests can feel). There is no package to build and no test to run \u2014 this is a complete answer, not a skipped step.`
13215
13727
  };
13216
13728
  }
13217
- const byDir = new Map(packages.map((p) => [p.dir, p]));
13729
+ const byDir = new Map(scopeGraph.map((p) => [p.dir, p]));
13218
13730
  const unmapped = affected.filter((d) => d !== "." && !byDir.has(d));
13219
13731
  if (unmapped.length > 0) {
13220
13732
  return unsupportedReport(
@@ -13254,7 +13766,16 @@ function runBuildTest(args) {
13254
13766
  results.note = `Insufficient disk space (${gib(free)}G free, need ~${gib(INSTALL_MIN_FREE_BYTES)}G): skipped \`${installCmd}\`, so nothing could be built or tested. This is an environment issue, not a code finding \u2014 report it as informational.`;
13255
13767
  return results;
13256
13768
  }
13257
- const install = exec(installCmd, root, perCommandMs);
13769
+ if (remainingMs() < BUDGET_MIN_ATTEMPT_MS) {
13770
+ results.ok = false;
13771
+ results.note = `The whole-call budget was spent before the install could start (${args.budget != null ? `--budget ${args.budget}s` : "default budget"}), so nothing could be built or tested. This is an infrastructure result, not a defect in the diff \u2014 report it as informational.`;
13772
+ return results;
13773
+ }
13774
+ const install = exec(
13775
+ installCmd,
13776
+ root,
13777
+ Math.min(perCommandMs, remainingMs())
13778
+ );
13258
13779
  results.install = install;
13259
13780
  if (install.timedOut) results.timedOut.push(install.command);
13260
13781
  if (install.timedOut) {
@@ -13269,7 +13790,7 @@ function runBuildTest(args) {
13269
13790
  }
13270
13791
  if (install.timedOut || !installComplete()) {
13271
13792
  results.ok = false;
13272
- results.note = install.timedOut ? `\`${install.command}\` ran out of time (${args.timeout}s) and left an incomplete \`node_modules\`, so nothing could be built or tested against it. This is an infrastructure result, not a defect in the diff \u2014 report it as informational.` : "The install failed and left no usable `node_modules`, so nothing could be built or tested. This is an environment failure, not a defect in the diff \u2014 report it as informational.";
13793
+ results.note = install.timedOut ? `\`${install.command}\` ran out of time (${deadlineSecs(install)}s) and left an incomplete \`node_modules\`, so nothing could be built or tested against it. This is an infrastructure result, not a defect in the diff \u2014 report it as informational.` : "The install failed and left no usable `node_modules`, so nothing could be built or tested. This is an environment failure, not a defect in the diff \u2014 report it as informational.";
13273
13794
  return results;
13274
13795
  }
13275
13796
  }
@@ -13280,9 +13801,12 @@ function runBuildTest(args) {
13280
13801
  return results;
13281
13802
  }
13282
13803
  const alsoBuild = [];
13283
- let set = buildSetFor(affected, packages);
13804
+ let set = buildSetFor(affected, scopeGraph);
13284
13805
  const built = /* @__PURE__ */ new Set();
13285
13806
  const widened = /* @__PURE__ */ new Set();
13807
+ const rootBuildRuns = !!rootPkg?.scripts.includes("build") && !scriptFansOut(rootPkg.scriptsText["build"]);
13808
+ const rootBuildSkipped = !singleRoot && !rootBuildRuns;
13809
+ const notBuilt = [];
13286
13810
  for (let attempt = 0; attempt <= 3; attempt++) {
13287
13811
  let failure = null;
13288
13812
  for (const dir of set) {
@@ -13292,7 +13816,23 @@ function runBuildTest(args) {
13292
13816
  built.add(dir);
13293
13817
  continue;
13294
13818
  }
13295
- const r = exec(buildCommand(dir), root, perCommandMs);
13819
+ if (dir === "." && rootBuildSkipped) {
13820
+ built.add(dir);
13821
+ continue;
13822
+ }
13823
+ if (remainingMs() < BUDGET_MIN_ATTEMPT_MS) {
13824
+ notBuilt.push(
13825
+ ...set.filter(
13826
+ (d) => !built.has(d) && byDir.get(d)?.scripts.includes("build")
13827
+ )
13828
+ );
13829
+ break;
13830
+ }
13831
+ const r = exec(
13832
+ buildCommand(dir),
13833
+ root,
13834
+ Math.min(perCommandMs, remainingMs())
13835
+ );
13296
13836
  results.build.push(r);
13297
13837
  if (r.timedOut) results.timedOut.push(r.command);
13298
13838
  if (r.exitCode !== 0) {
@@ -13308,8 +13848,8 @@ function runBuildTest(args) {
13308
13848
  });
13309
13849
  if (missing.length === 0 || failure.timedOut || attempt === 3) {
13310
13850
  results.ok = false;
13311
- results.note = failure.timedOut ? `\`${failure.command}\` ran out of time (${args.timeout}s). That is an infrastructure result, not a defect in the diff \u2014 report it as informational.` : `\`${failure.command}\` failed. Correlate the errors below with the diff: a compile error in a file the PR changed is a Critical; one in a file it did not touch is a pre-existing failure, and belongs in the terminal, not on the PR.`;
13312
- results.buildSet = set;
13851
+ results.note = failure.timedOut ? `\`${failure.command}\` ran out of time (${deadlineSecs(failure)}s). That is an infrastructure result, not a defect in the diff \u2014 report it as informational.` : `\`${failure.command}\` failed. Correlate the errors below with the diff: a compile error in a file the PR changed is a Critical; one in a file it did not touch is a pre-existing failure, and belongs in the terminal, not on the PR.`;
13852
+ results.buildSet = (rootBuildSkipped ? set.filter((d) => d !== ".") : set).filter((d) => !notBuilt.includes(d));
13313
13853
  results.widenedWith = [...widened];
13314
13854
  return results;
13315
13855
  }
@@ -13319,31 +13859,85 @@ function runBuildTest(args) {
13319
13859
  const dir = packages.find((p) => p.name === name)?.dir;
13320
13860
  if (dir) alsoBuild.push(dir);
13321
13861
  }
13322
- set = buildSetFor(affected, packages, alsoBuild);
13862
+ set = buildSetFor(affected, scopeGraph, alsoBuild);
13323
13863
  }
13324
- results.buildSet = set;
13864
+ results.buildSet = (rootBuildSkipped ? set.filter((d) => d !== ".") : set).filter((d) => !notBuilt.includes(d));
13325
13865
  results.widenedWith = [...widened];
13326
- for (const dir of args.buildOnly ? [] : affected) {
13327
- const pkg = byDir.get(dir);
13328
- if (!pkg?.scripts.includes("test")) continue;
13329
- const r = exec(testCommand(dir), root, perCommandMs);
13866
+ if (notBuilt.length > 0) results.notBuilt = [...notBuilt].sort();
13867
+ const rootHasTest = !!rootPkg?.scripts.includes("test");
13868
+ const testDirs = args.buildOnly ? [] : !testScope ? affected : testScope.workspaces;
13869
+ const runnable = /* @__PURE__ */ __name((dir) => dir === "." ? rootHasTest : !!byDir.get(dir)?.scripts.includes("test"), "runnable");
13870
+ const affectedSet = new Set(affected);
13871
+ const runnableDirs = [
13872
+ ...testDirs.filter((d) => affectedSet.has(d) && runnable(d)),
13873
+ ...testDirs.filter((d) => !affectedSet.has(d) && runnable(d))
13874
+ ];
13875
+ const untestable = notBuilt.length > 0 ? new Set(reverseDependencyClosure(notBuilt, scopeGraph)) : /* @__PURE__ */ new Set();
13876
+ const notRun = [];
13877
+ for (let i = 0; i < runnableDirs.length; i++) {
13878
+ const dir = runnableDirs[i];
13879
+ if (untestable.has(dir)) {
13880
+ notRun.push(dir);
13881
+ continue;
13882
+ }
13883
+ const remaining = remainingMs();
13884
+ if (remaining < BUDGET_MIN_ATTEMPT_MS) {
13885
+ notRun.push(...runnableDirs.slice(i).filter((d) => !untestable.has(d)));
13886
+ break;
13887
+ }
13888
+ const r = exec(testCommand(dir), root, Math.min(perCommandMs, remaining));
13330
13889
  results.test.push(r);
13331
13890
  if (r.timedOut) results.timedOut.push(r.command);
13332
13891
  if (r.exitCode !== 0) results.ok = false;
13333
13892
  }
13893
+ notRun.sort();
13894
+ const partialNote = [
13895
+ notBuilt.length > 0 ? `the build phase reached the whole-call budget \u2014 not built: ` + notBuilt.join(", ") : "",
13896
+ notRun.length > 0 ? `the whole-call budget (${Math.round(callBudgetMs / 1e3)}s) was spent with ${notRun.length} suite(s) still to run \u2014 not run: ` + notRun.join(", ") : ""
13897
+ ].filter(Boolean).join("; ") || void 0;
13898
+ if (testScope && partialNote) {
13899
+ const ran = testScope.workspaces.filter((d) => !notRun.includes(d));
13900
+ testScope = {
13901
+ workspaces: ran,
13902
+ ...notRun.length > 0 ? { notRun } : {},
13903
+ caveat: testScope.caveat ? `${testScope.caveat}; ${partialNote}` : partialNote
13904
+ };
13905
+ }
13906
+ if (testScope) results.testScope = testScope;
13334
13907
  if (!results.note) {
13335
13908
  const failed = [...results.build, ...results.test].filter(
13336
13909
  (r) => r.exitCode !== 0
13337
13910
  );
13338
13911
  const realFailures = failed.filter((r) => !r.timedOut);
13339
13912
  if (results.ok) {
13340
- results.note = `Built ${results.buildSet.length} of ${packages.length} workspaces (the ${affected.length} the diff changes, plus what they compile against${widened.size ? `, plus ${[...widened].join(", ")} the compiler asked for` : ""})${args.buildOnly ? ". Tests were not run (build-only)." : " and ran the tests of the changed ones. Everything passed."}`;
13913
+ let testsClause;
13914
+ if (args.buildOnly) {
13915
+ testsClause = ". Tests were not run (build-only).";
13916
+ } else if (!testScope) {
13917
+ testsClause = results.test.length === 0 ? ", but the package defines no test script, so no tests ran." : " and ran the tests of the changed ones. Everything passed.";
13918
+ } else if (testScope.workspaces.length === 0) {
13919
+ testsClause = testScope.notRun?.length ? ", but the whole-call budget was spent before any suite could run." : ", but no workspace in scope defines a test script, so no tests ran.";
13920
+ } else {
13921
+ testsClause = ` and ran the tests scoped to ${testScope.workspaces.join(", ")} \u2014 the changed workspaces and every workspace declared to depend on them that defines a test script. Everything passed.`;
13922
+ }
13923
+ if (testScope?.caveat) testsClause += ` Caveat: ${testScope.caveat}.`;
13924
+ const builtWorkspaces = results.buildSet.filter(
13925
+ (d) => singleRoot || d !== "."
13926
+ ).length;
13927
+ const rootSuffix = !singleRoot && results.buildSet.includes(".") && !rootBuildSkipped ? " (plus the root package)" : "";
13928
+ results.note = `Built ${builtWorkspaces} of ${packages.length} workspaces${rootSuffix} (the ${affected.length} the diff changes, plus what they compile against${widened.size ? `, plus ${[...widened].join(", ")} the compiler asked for` : ""})${testsClause}`;
13341
13929
  } else if (realFailures.length === 0) {
13342
- results.note = `${failed.length} command(s) ran out of time (${args.timeout}s). A timeout is an infrastructure result, not a defect in the diff \u2014 report it as informational.`;
13930
+ results.note = `${failed.length} command(s) ran out of time (${deadlineSecs(failed[0])}s). A timeout is an infrastructure result, not a defect in the diff \u2014 report it as informational.`;
13343
13931
  } else {
13344
13932
  results.note = `${realFailures.length} command(s) failed. Correlate each error with the diff: a failure in a file the PR changed is a Critical; one in a file it did not touch is pre-existing.` + (failed.length > realFailures.length ? " (Commands that timed out are infrastructure, not findings.)" : "");
13345
13933
  }
13346
13934
  }
13935
+ if (results.testScope?.caveat && !results.note.includes("Caveat:")) {
13936
+ results.note += ` Caveat: ${results.testScope.caveat}.`;
13937
+ }
13938
+ if (partialNote && !results.testScope) {
13939
+ results.note = results.note ? `${results.note} ${partialNote}.` : partialNote;
13940
+ }
13347
13941
  if (results.install && results.install.exitCode !== 0) {
13348
13942
  results.note = `\`${results.install.command}\` exited ${results.install.exitCode} but left a usable \`node_modules\`, so the build and test below ran anyway and their results stand. The install failure is an environment/infrastructure result \u2014 report it as informational, never as a Critical, and never against this PR. ` + results.note;
13349
13943
  }
@@ -13352,7 +13946,7 @@ function runBuildTest(args) {
13352
13946
  __name(runBuildTest, "runBuildTest");
13353
13947
  var buildTestCommand = {
13354
13948
  command: "build-test",
13355
- describe: "Build and test the workspaces the diff changes (and what they compile against), with a deadline the commands can actually meet",
13949
+ describe: "Build the workspaces the diff changes (and what they compile against), test those plus their dependents, with a deadline the commands can actually meet",
13356
13950
  builder: /* @__PURE__ */ __name((yargs) => yargs.option("plan", {
13357
13951
  type: "string",
13358
13952
  demandOption: true,
@@ -13367,7 +13961,10 @@ var buildTestCommand = {
13367
13961
  }).option("timeout", {
13368
13962
  type: "number",
13369
13963
  default: 300,
13370
- describe: "Per-command deadline in seconds. Kept strictly below the 600s (600000ms) tool timeout the agent's brief welds onto the whole call, so a single hung command's own deadline fires \u2014 and build-test reports it as data \u2014 before the outer shell kill would discard the report. (A giant PR whose commands sum past the tool ceiling is a separate, acknowledged follow-up.)"
13964
+ describe: "Per-command deadline in seconds. Kept strictly below the 600s (600000ms) tool timeout the agent's brief welds onto the whole call, so a single hung command's own deadline fires \u2014 and build-test reports it as data \u2014 before the outer shell kill would discard the report. Commands that would SUM past the whole call are stopped and disclosed instead \u2014 see --budget."
13965
+ }).option("budget", {
13966
+ type: "number",
13967
+ describe: "Whole-call wall-clock budget in seconds, measured from the top of the call \u2014 install and build time count against it (default: 2\xD7 --timeout minus 30s of headroom for process startup and the report write). Each suite is attempted with whatever of the budget remains \u2014 a suite killed at the boundary is a timeout, reported as infrastructure \u2014 and only suites never attempted are named notRun. A partial report survives where the outer shell kill would discard the whole one."
13371
13968
  }).option("install", {
13372
13969
  type: "boolean",
13373
13970
  default: true,
@@ -13400,7 +13997,7 @@ import {
13400
13997
  mkdirSync as mkdirSync18,
13401
13998
  readFileSync as readFileSync21,
13402
13999
  rmSync as rmSync7,
13403
- statSync as statSync7,
14000
+ statSync as statSync9,
13404
14001
  writeFileSync as writeFileSync19
13405
14002
  } from "node:fs";
13406
14003
  import { dirname as dirname15, join as join16, resolve as resolve15 } from "node:path";
@@ -13500,7 +14097,7 @@ function runBaseTree(args) {
13500
14097
  }
13501
14098
  const lock = `${tree}.lock`;
13502
14099
  try {
13503
- const age = Date.now() - statSync7(lock).mtimeMs;
14100
+ const age = Date.now() - statSync9(lock).mtimeMs;
13504
14101
  if (age > 30 * 60 * 1e3) {
13505
14102
  rmSync7(lock, { recursive: true, force: true });
13506
14103
  }
@@ -13543,6 +14140,15 @@ function runBaseTree(args) {
13543
14140
  // tree to run against.
13544
14141
  buildOnly: true
13545
14142
  });
14143
+ if ((build.notBuilt?.length ?? 0) > 0) {
14144
+ return {
14145
+ available: false,
14146
+ path: tree,
14147
+ baseSha: baseSha2,
14148
+ build,
14149
+ note: `the base tree build at ${baseSha2.slice(0, 9)} was cut short by the whole-call budget (${build.notBuilt.join(", ")} not built), so a rerun against it would manufacture pre-existing failures; an A/B is not available for this review (this is an infrastructure result, never a finding against the PR)`
14150
+ };
14151
+ }
13546
14152
  if (!build.ok || build.toolchain !== "npm" || build.build.length === 0) {
13547
14153
  try {
13548
14154
  writeFileSync19(failedMarker(), `${baseSha2}
@@ -13846,7 +14452,7 @@ import {
13846
14452
  readFileSync as readFileSync23,
13847
14453
  existsSync as existsSync10,
13848
14454
  rmSync as rmSync8,
13849
- statSync as statSync8
14455
+ statSync as statSync10
13850
14456
  } from "node:fs";
13851
14457
  import { dirname as dirname17, join as join17, resolve as resolve17 } from "node:path";
13852
14458
  import { tmpdir as tmpdir2 } from "node:os";
@@ -13860,7 +14466,7 @@ var LOG_MAX_BYTES = 8 * 1024 * 1024;
13860
14466
  var POLL_MS = 250;
13861
14467
  function logBytes(p) {
13862
14468
  try {
13863
- return statSync8(p).size;
14469
+ return statSync10(p).size;
13864
14470
  } catch {
13865
14471
  return 0;
13866
14472
  }
@@ -15271,7 +15877,7 @@ import {
15271
15877
  rmSync as rmSync9,
15272
15878
  lstatSync as lstatSync4,
15273
15879
  existsSync as existsSync11,
15274
- statSync as statSync9,
15880
+ statSync as statSync11,
15275
15881
  symlinkSync
15276
15882
  } from "node:fs";
15277
15883
  import { createRequire } from "node:module";
@@ -15472,8 +16078,8 @@ function insideClassBody(codeLines, idx) {
15472
16078
  return false;
15473
16079
  }
15474
16080
  __name(insideClassBody, "insideClassBody");
15475
- function isRemovableStatement(lines2, codeLines, idx) {
15476
- const t2 = (lines2[idx] ?? "").trim();
16081
+ function isRemovableStatement(lines, codeLines, idx) {
16082
+ const t2 = (lines[idx] ?? "").trim();
15477
16083
  if (!(codeLines[idx] ?? "").endsWith(";")) return false;
15478
16084
  if ((codeLines[idx] ?? "").slice(0, -1).includes(";")) return false;
15479
16085
  if (!/^(?:await\s+)?[A-Za-z_$]/.test(t2)) return false;
@@ -15542,19 +16148,19 @@ function selectMutants(files, cap = MAX_MUTANTS) {
15542
16148
  const replRest = [];
15543
16149
  const derailed = [];
15544
16150
  for (const f of files) {
15545
- const lines2 = f.content.split("\n");
16151
+ const lines = f.content.split("\n");
15546
16152
  const { inLiteral, codeLines, endState } = scanFileLines(f.content);
15547
16153
  if (endState !== "code") {
15548
16154
  derailed.push(f.file);
15549
16155
  continue;
15550
16156
  }
15551
16157
  for (const n of [...f.addedLines].sort((a, b) => a - b)) {
15552
- const raw = lines2[n - 1];
16158
+ const raw = lines[n - 1];
15553
16159
  if (raw === void 0) continue;
15554
16160
  const t2 = raw.trim();
15555
16161
  if (inLiteral[n - 1]) continue;
15556
16162
  const code = codeLines[n - 1] ?? "";
15557
- if (SAFETY_VERB_RE.test(code) && isRemovableStatement(lines2, codeLines, n - 1)) {
16163
+ if (SAFETY_VERB_RE.test(code) && isRemovableStatement(lines, codeLines, n - 1)) {
15558
16164
  (f.hasNewTests ? preferred : rest).push({
15559
16165
  file: f.file,
15560
16166
  line: n,
@@ -15884,7 +16490,7 @@ function exposeDependencies(probeTree, dependencyRoot) {
15884
16490
  }
15885
16491
  if (sourceStats.isSymbolicLink()) {
15886
16492
  try {
15887
- if (!statSync9(sourceEntry).isDirectory()) continue;
16493
+ if (!statSync11(sourceEntry).isDirectory()) continue;
15888
16494
  } catch {
15889
16495
  continue;
15890
16496
  }
@@ -15958,34 +16564,34 @@ function runProbeSuite(probeTree, probes, deadlineAt, now = Date.now, dependency
15958
16564
  }
15959
16565
  __name(runProbeSuite, "runProbeSuite");
15960
16566
  function splitDiffIntoHunks(diffText) {
15961
- const lines2 = diffText.split("\n");
15962
- const first = lines2.findIndex((l) => l.startsWith("@@"));
16567
+ const lines = diffText.split("\n");
16568
+ const first = lines.findIndex((l) => l.startsWith("@@"));
15963
16569
  if (first < 0) return [];
15964
16570
  let headerStart = 0;
15965
16571
  for (let k = first - 1; k >= 0; k--) {
15966
- if (lines2[k].startsWith("diff --git ")) {
16572
+ if (lines[k].startsWith("diff --git ")) {
15967
16573
  headerStart = k;
15968
16574
  break;
15969
16575
  }
15970
16576
  }
15971
- let fileHeader = lines2.slice(headerStart, first);
16577
+ let fileHeader = lines.slice(headerStart, first);
15972
16578
  const out = [];
15973
16579
  let i = first;
15974
- while (i < lines2.length) {
15975
- if (lines2[i].startsWith("diff --git ")) {
16580
+ while (i < lines.length) {
16581
+ if (lines[i].startsWith("diff --git ")) {
15976
16582
  const start = i;
15977
- while (i < lines2.length && !lines2[i].startsWith("@@") && !(i > start && lines2[i].startsWith("diff --git ")))
16583
+ while (i < lines.length && !lines[i].startsWith("@@") && !(i > start && lines[i].startsWith("diff --git ")))
15978
16584
  i++;
15979
- fileHeader = lines2.slice(start, i);
16585
+ fileHeader = lines.slice(start, i);
15980
16586
  continue;
15981
16587
  }
15982
- if (!lines2[i].startsWith("@@")) {
16588
+ if (!lines[i].startsWith("@@")) {
15983
16589
  i++;
15984
16590
  continue;
15985
16591
  }
15986
- const header = lines2[i];
16592
+ const header = lines[i];
15987
16593
  let j = i + 1;
15988
- while (j < lines2.length && !lines2[j].startsWith("@@") && !lines2[j].startsWith("diff --git ")) {
16594
+ while (j < lines.length && !lines[j].startsWith("@@") && !lines[j].startsWith("diff --git ")) {
15989
16595
  j++;
15990
16596
  }
15991
16597
  let startLine = Number(
@@ -15993,18 +16599,18 @@ function splitDiffIntoHunks(diffText) {
15993
16599
  );
15994
16600
  let offset = 0;
15995
16601
  for (let k = i + 1; k < j; k++) {
15996
- if (lines2[k].startsWith("+")) {
16602
+ if (lines[k].startsWith("+")) {
15997
16603
  startLine += offset;
15998
16604
  break;
15999
16605
  }
16000
- if (!lines2[k].startsWith("-") && !lines2[k].startsWith("\\")) offset++;
16606
+ if (!lines[k].startsWith("-") && !lines[k].startsWith("\\")) offset++;
16001
16607
  }
16002
16608
  out.push({
16003
16609
  header: header.trim(),
16004
16610
  startLine,
16005
16611
  // `git apply` requires the trailing newline; a patch that ends mid-line is
16006
16612
  // rejected with `corrupt patch`.
16007
- patch: `${[...fileHeader, ...lines2.slice(i, j)].join("\n").replace(/\n+$/, "")}
16613
+ patch: `${[...fileHeader, ...lines.slice(i, j)].join("\n").replace(/\n+$/, "")}
16008
16614
  `
16009
16615
  });
16010
16616
  i = j;
@@ -16111,8 +16717,8 @@ __name(runControlMutant, "runControlMutant");
16111
16717
  function runOneMutant(probeTree, mutant, probes, deadlineAt, now = Date.now, dependencyRoot = probeTree) {
16112
16718
  const abs = join18(probeTree, mutant.file);
16113
16719
  const original = readFileSync26(abs, "utf8");
16114
- const lines2 = original.split("\n");
16115
- if ((lines2[mutant.line - 1] ?? "").trim() !== mutant.statement) {
16720
+ const lines = original.split("\n");
16721
+ if ((lines[mutant.line - 1] ?? "").trim() !== mutant.statement) {
16116
16722
  return {
16117
16723
  ...mutant,
16118
16724
  verdict: "inconclusive",
@@ -16121,12 +16727,12 @@ function runOneMutant(probeTree, mutant, probes, deadlineAt, now = Date.now, dep
16121
16727
  }
16122
16728
  const what = mutant.operator === "coalesce" ? "with its `?? fallback` dropped" : mutant.operator === "guard-true" ? "with its guard condition replaced by `true`" : mutant.operator === "term-drop" ? "with its `+ CONSTANT` term dropped" : "deleted";
16123
16729
  if (mutant.mutated !== void 0) {
16124
- lines2[mutant.line - 1] = mutant.mutated;
16730
+ lines[mutant.line - 1] = mutant.mutated;
16125
16731
  } else {
16126
- lines2.splice(mutant.line - 1, 1);
16732
+ lines.splice(mutant.line - 1, 1);
16127
16733
  }
16128
16734
  try {
16129
- writeFileSync24(abs, lines2.join("\n"), "utf8");
16735
+ writeFileSync24(abs, lines.join("\n"), "utf8");
16130
16736
  const { perFile } = runProbeSuite(
16131
16737
  probeTree,
16132
16738
  probes,
@@ -16643,11 +17249,11 @@ var PLAN_NAME_RE = /(test\s*plan|\btesting\b|how\s+(?:has\s+this|to)\s+(?:been\s
16643
17249
  var HEADING_LINE_RE = /^(#{1,6})(?:[ \t](.*))?$/;
16644
17250
  var BOLD_LINE_RE = /^\*\*([^*\n]+)\*\*:?\s*$/;
16645
17251
  function extractTestPlanSection(body) {
16646
- const lines2 = body.split(/\r?\n/);
16647
- const fenced = new Array(lines2.length).fill(false);
17252
+ const lines = body.split(/\r?\n/);
17253
+ const fenced = new Array(lines.length).fill(false);
16648
17254
  let fenceMarker = null;
16649
- for (let i = 0; i < lines2.length; i++) {
16650
- const m = /^\s*(```|~~~)/.exec(lines2[i]);
17255
+ for (let i = 0; i < lines.length; i++) {
17256
+ const m = /^\s*(```|~~~)/.exec(lines[i]);
16651
17257
  if (m) {
16652
17258
  fenced[i] = true;
16653
17259
  if (!fenceMarker) fenceMarker = m[1];
@@ -16656,27 +17262,27 @@ function extractTestPlanSection(body) {
16656
17262
  }
16657
17263
  fenced[i] = fenceMarker !== null;
16658
17264
  }
16659
- for (let i = 0; i < lines2.length; i++) {
17265
+ for (let i = 0; i < lines.length; i++) {
16660
17266
  if (fenced[i]) continue;
16661
- const hash = HEADING_LINE_RE.exec(lines2[i]);
16662
- const bold = BOLD_LINE_RE.exec(lines2[i]);
17267
+ const hash = HEADING_LINE_RE.exec(lines[i]);
17268
+ const bold = BOLD_LINE_RE.exec(lines[i]);
16663
17269
  const name = (hash?.[2] ?? bold?.[1])?.trim();
16664
17270
  if (!name || !PLAN_NAME_RE.test(name)) continue;
16665
17271
  const level = hash ? hash[1].length : Infinity;
16666
17272
  const out = [];
16667
- for (let j = i + 1; j < lines2.length; j++) {
17273
+ for (let j = i + 1; j < lines.length; j++) {
16668
17274
  if (!fenced[j]) {
16669
- const next = HEADING_LINE_RE.exec(lines2[j]);
17275
+ const next = HEADING_LINE_RE.exec(lines[j]);
16670
17276
  if (next && !next[2]?.trim()) {
16671
- out.push(lines2[j]);
17277
+ out.push(lines[j]);
16672
17278
  continue;
16673
17279
  }
16674
17280
  if (next && next[1].length <= level) break;
16675
- if (!hash && (next || BOLD_LINE_RE.test(lines2[j]))) break;
17281
+ if (!hash && (next || BOLD_LINE_RE.test(lines[j]))) break;
16676
17282
  }
16677
- out.push(lines2[j]);
17283
+ out.push(lines[j]);
16678
17284
  }
16679
- return { heading: lines2[i].trim(), content: out.join("\n").trim() };
17285
+ return { heading: lines[i].trim(), content: out.join("\n").trim() };
16680
17286
  }
16681
17287
  return null;
16682
17288
  }
@@ -16918,9 +17524,21 @@ function ruleCommand(text, worktree, buildTest) {
16918
17524
  } catch {
16919
17525
  }
16920
17526
  const defined = new Set(rootScripts);
16921
- for (const pkg of readWorkspacePackages(worktree)) {
17527
+ const { packages, skipped } = readWorkspacePackages(worktree);
17528
+ for (const pkg of packages) {
16922
17529
  for (const s of pkg.scripts) defined.add(s);
16923
17530
  }
17531
+ const unreadable = [];
17532
+ for (const dir of skipped) {
17533
+ try {
17534
+ const pkg = JSON.parse(
17535
+ readFileSync27(join19(worktree, dir, "package.json"), "utf8")
17536
+ );
17537
+ for (const s of Object.keys(pkg?.scripts ?? {})) defined.add(s);
17538
+ } catch {
17539
+ unreadable.push(dir);
17540
+ }
17541
+ }
16924
17542
  if (defined.size === 0) {
16925
17543
  return {
16926
17544
  kind: "command",
@@ -16929,12 +17547,31 @@ function ruleCommand(text, worktree, buildTest) {
16929
17547
  note: "no package manifest could be read"
16930
17548
  };
16931
17549
  }
16932
- return defined.has(script) ? {
16933
- kind: "command",
16934
- text,
16935
- verdict: "reproduces",
16936
- note: `\`${script}\` is a defined script`
16937
- } : {
17550
+ if (defined.has(script)) {
17551
+ return {
17552
+ kind: "command",
17553
+ text,
17554
+ verdict: "reproduces",
17555
+ note: `\`${script}\` is a defined script`
17556
+ };
17557
+ }
17558
+ if (hasUnmodeledWorkspaceGlob(readWorkspaceGlobs(worktree))) {
17559
+ return {
17560
+ kind: "command",
17561
+ text,
17562
+ verdict: "unchecked",
17563
+ note: "the workspace globs use a shape this check does not model, so the script table may be incomplete"
17564
+ };
17565
+ }
17566
+ if (unreadable.length > 0) {
17567
+ return {
17568
+ kind: "command",
17569
+ text,
17570
+ verdict: "unchecked",
17571
+ note: `${unreadable.join(", ")} ${unreadable.length === 1 ? "has" : "have"} a package.json this check could not read, so the script table may be incomplete`
17572
+ };
17573
+ }
17574
+ return {
16938
17575
  kind: "command",
16939
17576
  text,
16940
17577
  verdict: "contradicted",
@@ -17342,11 +17979,324 @@ var cleanupCommand = {
17342
17979
  }, "handler")
17343
17980
  };
17344
17981
 
17982
+ // packages/cli/src/commands/review/cost-ledger.ts
17983
+ init_esbuild_shims();
17984
+ import { mkdirSync as mkdirSync26, readFileSync as readFileSync29, statSync as statSync12, writeFileSync as writeFileSync26 } from "node:fs";
17985
+ import { dirname as dirname22, join as join21, resolve as resolve21 } from "node:path";
17986
+ function readUsage(file, floorMs) {
17987
+ const raw = readFileSync29(file, "utf8");
17988
+ const events = [];
17989
+ let launch = "";
17990
+ for (const line of raw.split("\n")) {
17991
+ if (line.trim() === "") continue;
17992
+ for (const rec of parseLineTolerant(line, file)) {
17993
+ if (launch === "" && rec["type"] === "user") {
17994
+ launch = textOf(rec);
17995
+ }
17996
+ if (rec["type"] !== "assistant") continue;
17997
+ const usage = rec["usageMetadata"];
17998
+ if (usage === null || typeof usage !== "object") continue;
17999
+ if (Array.isArray(usage)) continue;
18000
+ const u = usage;
18001
+ const ts = rec["timestamp"];
18002
+ if (typeof ts !== "string") continue;
18003
+ const tsMs = Date.parse(ts);
18004
+ if (!Number.isFinite(tsMs) || tsMs < floorMs) continue;
18005
+ const rawCount = /* @__PURE__ */ __name((k) => {
18006
+ const v = u[k];
18007
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : null;
18008
+ }, "rawCount");
18009
+ const rawPrompt = rawCount("promptTokenCount");
18010
+ const rawTotal = rawCount("totalTokenCount");
18011
+ const prompt = rawPrompt ?? 0;
18012
+ const candidates = rawCount("candidatesTokenCount") ?? 0;
18013
+ events.push({
18014
+ timestampMs: tsMs,
18015
+ timestamp: ts,
18016
+ input: prompt,
18017
+ // Cached is part of the prompt it is reported with; a broken proxy
18018
+ // can report the pair inverted, and the inversion would otherwise
18019
+ // land in BOTH the rendered share and the archived --out JSON.
18020
+ cached: Math.min(rawCount("cachedContentTokenCount") ?? 0, prompt),
18021
+ // `total − prompt` is the output including thinking under BOTH usage
18022
+ // conventions — reasoning inside candidates, and thoughts disjoint
18023
+ // from them — the same derivation tokenEstimation uses. Candidates
18024
+ // alone is the fallback when the provider reported no total; it stays
18025
+ // correct for the providers this CLI converts, which clamp thoughts
18026
+ // inside candidates. Derive it only when BOTH operands survived the
18027
+ // provider intact: a mixed-sign record coerces prompt to 0 while
18028
+ // keeping a positive total, and the subtraction would bill the
18029
+ // call's whole total as output.
18030
+ output: rawPrompt !== null && rawTotal !== null && rawTotal > rawPrompt ? rawTotal - rawPrompt : candidates,
18031
+ thoughts: rawCount("thoughtsTokenCount") ?? 0
18032
+ });
18033
+ }
18034
+ }
18035
+ return { events, launch };
18036
+ }
18037
+ __name(readUsage, "readUsage");
18038
+ var AUDIT_BRIEF_RE = /read_file\(file_path="[^"]*reverse-audit--chunk-(\d+)--round-(\d+)--[0-9a-f][^"]*\.brief\.md"\)/g;
18039
+ function labelOf(launch, fallback) {
18040
+ const nl = launch.indexOf("\n");
18041
+ const identity = nl === -1 ? launch : launch.slice(0, nl);
18042
+ if (!identity.startsWith("You are review agent `")) return fallback;
18043
+ let auditChunk = null;
18044
+ for (const m of launch.matchAll(AUDIT_BRIEF_RE)) auditChunk = m;
18045
+ if (auditChunk) {
18046
+ return `audit chunk ${auditChunk[1]} (round ${auditChunk[2]})`;
18047
+ }
18048
+ const role = /^You are review agent `([^`]+)`/.exec(identity);
18049
+ if (!role) return fallback;
18050
+ const round = /\(round (\d+)\)/.exec(identity);
18051
+ const chunk2 = CHUNK_RE.exec(role[1]);
18052
+ if (chunk2) return `chunk ${chunk2[1]}`;
18053
+ if (round) {
18054
+ return `agent ${role[1]} (round ${round[1]})`;
18055
+ }
18056
+ const file = /Your file: `([^`]+)`/.exec(identity);
18057
+ if (file) return `agent ${role[1]} (${file[1]})`;
18058
+ return `agent ${role[1]}`;
18059
+ }
18060
+ __name(labelOf, "labelOf");
18061
+ function foldEvents(id, label2, events) {
18062
+ const s = {
18063
+ id,
18064
+ label: label2,
18065
+ calls: 0,
18066
+ inputTokens: 0,
18067
+ cachedTokens: 0,
18068
+ outputTokens: 0,
18069
+ thoughtsTokens: 0,
18070
+ firstAt: null,
18071
+ lastAt: null
18072
+ };
18073
+ let firstMs = Number.POSITIVE_INFINITY;
18074
+ let lastMs = Number.NEGATIVE_INFINITY;
18075
+ for (const e of events) {
18076
+ s.calls += 1;
18077
+ s.inputTokens += e.input;
18078
+ s.cachedTokens += e.cached;
18079
+ s.outputTokens += e.output;
18080
+ s.thoughtsTokens += e.thoughts;
18081
+ if (e.timestampMs < firstMs) {
18082
+ firstMs = e.timestampMs;
18083
+ s.firstAt = e.timestamp;
18084
+ }
18085
+ if (e.timestampMs > lastMs) {
18086
+ lastMs = e.timestampMs;
18087
+ s.lastAt = e.timestamp;
18088
+ }
18089
+ }
18090
+ return s;
18091
+ }
18092
+ __name(foldEvents, "foldEvents");
18093
+ function human(n) {
18094
+ if (n >= 9995e5) return `${(n / 1e9).toFixed(1)}B`;
18095
+ if (n >= 999500) return `${(n / 1e6).toFixed(1)}M`;
18096
+ if (n >= 1e3) return `${Math.round(n / 1e3)}k`;
18097
+ return String(n);
18098
+ }
18099
+ __name(human, "human");
18100
+ var plural = /* @__PURE__ */ __name((n, word) => `${n} ${word}${n === 1 ? "" : "s"}`, "plural");
18101
+ function planFloorMs(planPath) {
18102
+ let raw;
18103
+ let floorMs;
18104
+ try {
18105
+ raw = readFileSync29(planPath, "utf8");
18106
+ floorMs = statSync12(planPath).mtimeMs;
18107
+ } catch (err) {
18108
+ throw new Error(
18109
+ `could not read the plan report ${planPath}: ${err.message}`
18110
+ );
18111
+ }
18112
+ let parsed;
18113
+ try {
18114
+ parsed = JSON.parse(raw);
18115
+ } catch {
18116
+ parsed = null;
18117
+ }
18118
+ const plan = parsed !== null && typeof parsed === "object" ? parsed : void 0;
18119
+ if (typeof plan?.["diffLines"] !== "number" || !Array.isArray(plan?.["chunks"])) {
18120
+ throw new Error(`not a review plan report: ${planPath}`);
18121
+ }
18122
+ return floorMs;
18123
+ }
18124
+ __name(planFloorMs, "planFloorMs");
18125
+ function computeLedger(planPath, env = process.env) {
18126
+ const floorMs = planFloorMs(planPath);
18127
+ const { projectDir, sessionId, dir } = transcriptPaths(env);
18128
+ const chatFile = join21(projectDir, "chats", `${sessionId}.jsonl`);
18129
+ let mainEvents;
18130
+ try {
18131
+ mainEvents = readUsage(chatFile, floorMs).events;
18132
+ } catch (err) {
18133
+ throw new Error(
18134
+ `could not read the chat transcript ${chatFile}: ${err.message}`
18135
+ );
18136
+ }
18137
+ const main = mainEvents.length > 0 ? foldEvents("main", "main loop", mainEvents) : null;
18138
+ let files;
18139
+ try {
18140
+ files = listAgentTranscriptFiles(dir);
18141
+ } catch (err) {
18142
+ if (err.code === "ENOENT") {
18143
+ files = [];
18144
+ } else {
18145
+ throw new Error(
18146
+ `could not list the subagent transcripts at ${dir}: ${err.message}`
18147
+ );
18148
+ }
18149
+ }
18150
+ const agents = [];
18151
+ const agentEvents = [];
18152
+ for (const f of files) {
18153
+ const full = join21(dir, f);
18154
+ let mtimeMs;
18155
+ try {
18156
+ mtimeMs = statSync12(full).mtimeMs;
18157
+ } catch {
18158
+ continue;
18159
+ }
18160
+ if (mtimeMs < floorMs) continue;
18161
+ let read;
18162
+ try {
18163
+ read = readUsage(full, floorMs);
18164
+ } catch {
18165
+ continue;
18166
+ }
18167
+ if (read.events.length === 0) continue;
18168
+ const id = f.replace(/^agent-/, "").replace(/\.jsonl$/, "");
18169
+ agents.push(foldEvents(id, labelOf(read.launch, id), read.events));
18170
+ agentEvents.push(...read.events);
18171
+ }
18172
+ agents.sort((a, b) => b.inputTokens - a.inputTokens);
18173
+ if (mainEvents.length === 0) {
18174
+ throw new Error(
18175
+ `could not read the chat transcript ${chatFile}: no main-loop usage records at or after the plan`
18176
+ );
18177
+ }
18178
+ const totals = foldEvents("totals", "totals", [
18179
+ ...mainEvents,
18180
+ ...agentEvents
18181
+ ]);
18182
+ const wallSeconds = totals.firstAt !== null && totals.lastAt !== null ? Math.max(
18183
+ 0,
18184
+ Math.round(
18185
+ (Date.parse(totals.lastAt) - Date.parse(totals.firstAt)) / 1e3
18186
+ )
18187
+ ) : 0;
18188
+ const { id: _i, label: _l, ...totalsRest } = totals;
18189
+ return { totals: { ...totalsRest, wallSeconds }, main, agents };
18190
+ }
18191
+ __name(computeLedger, "computeLedger");
18192
+ function renderLedger(ledger) {
18193
+ const t2 = ledger.totals;
18194
+ const cachedPct = t2.inputTokens > 0 ? Math.round(t2.cachedTokens / t2.inputTokens * 100) : 0;
18195
+ const lines = [];
18196
+ lines.push(
18197
+ `Cost ledger: ${plural(t2.calls, "model call")} \xB7 ${human(t2.inputTokens)} input (${cachedPct}% cached) \xB7 ${human(t2.outputTokens)} output (${human(t2.thoughtsTokens)} thinking) \xB7 ${Math.round(t2.wallSeconds / 60)} min wall`
18198
+ );
18199
+ if (ledger.main !== null) {
18200
+ const m = ledger.main;
18201
+ lines.push(
18202
+ ` main loop: ${plural(m.calls, "call")} \xB7 ${human(m.inputTokens)} in \xB7 ${human(m.outputTokens)} out`
18203
+ );
18204
+ }
18205
+ if (ledger.agents.length > 0) {
18206
+ const rows = [];
18207
+ for (const a of ledger.agents) {
18208
+ const row = rows.find((r) => r.label === a.label);
18209
+ if (row) {
18210
+ row.calls += a.calls;
18211
+ row.inputTokens += a.inputTokens;
18212
+ row.outputTokens += a.outputTokens;
18213
+ row.count += 1;
18214
+ } else {
18215
+ rows.push({
18216
+ label: a.label,
18217
+ calls: a.calls,
18218
+ inputTokens: a.inputTokens,
18219
+ outputTokens: a.outputTokens,
18220
+ count: 1
18221
+ });
18222
+ }
18223
+ }
18224
+ rows.sort((a, b) => b.inputTokens - a.inputTokens);
18225
+ lines.push(` agent runs: ${ledger.agents.length}`);
18226
+ for (const r of rows.slice(0, 8)) {
18227
+ const label2 = r.count > 1 ? `${r.label} (\xD7${r.count})` : r.label;
18228
+ lines.push(
18229
+ ` ${label2}: ${plural(r.calls, "call")} \xB7 ${human(r.inputTokens)} in \xB7 ${human(r.outputTokens)} out`
18230
+ );
18231
+ }
18232
+ if (rows.length > 8) {
18233
+ const rest = rows.slice(8);
18234
+ const restIn = rest.reduce((n, r) => n + r.inputTokens, 0);
18235
+ const restAgents = rest.reduce((n, r) => n + r.count, 0);
18236
+ lines.push(
18237
+ ` \u2026and ${plural(restAgents, "more agent")} \xB7 ${human(restIn)} in combined`
18238
+ );
18239
+ }
18240
+ }
18241
+ return lines.join("\n");
18242
+ }
18243
+ __name(renderLedger, "renderLedger");
18244
+ function runCostLedger(args) {
18245
+ const stdoutErrorHandler = /* @__PURE__ */ __name((err) => {
18246
+ if (err.code === "EPIPE") process.stdout.destroy();
18247
+ }, "stdoutErrorHandler");
18248
+ const stderrErrorHandler = /* @__PURE__ */ __name((err) => {
18249
+ if (err.code === "EPIPE") process.stderr.destroy();
18250
+ }, "stderrErrorHandler");
18251
+ process.stdout.on("error", stdoutErrorHandler);
18252
+ process.stderr.on("error", stderrErrorHandler);
18253
+ try {
18254
+ let ledger;
18255
+ try {
18256
+ ledger = computeLedger(args.plan, process.env);
18257
+ } catch (err) {
18258
+ const why = err instanceof TranscriptsUnavailableError ? err.message : err.message;
18259
+ writeStderrLineSafe(`cost-ledger unavailable \u2014 ${why}`);
18260
+ return;
18261
+ }
18262
+ if (args.out !== void 0 && args.out.length > 0) {
18263
+ try {
18264
+ mkdirSync26(dirname22(resolve21(args.out)), { recursive: true });
18265
+ writeFileSync26(args.out, JSON.stringify(ledger, null, 2));
18266
+ } catch (err) {
18267
+ writeStderrLineSafe(
18268
+ `cost-ledger: could not write ${args.out} \u2014 ${err.message}`
18269
+ );
18270
+ }
18271
+ }
18272
+ writeStdoutLineSafe(renderLedger(ledger));
18273
+ } finally {
18274
+ process.stdout.removeListener("error", stdoutErrorHandler);
18275
+ process.stderr.removeListener("error", stderrErrorHandler);
18276
+ }
18277
+ }
18278
+ __name(runCostLedger, "runCostLedger");
18279
+ var costLedgerCommand = {
18280
+ command: "cost-ledger",
18281
+ describe: "Aggregate this review's model-call cost from the harness's usage records",
18282
+ builder: /* @__PURE__ */ __name((yargs) => yargs.option("plan", {
18283
+ type: "string",
18284
+ demandOption: true,
18285
+ describe: "The plan report from Step 1 \u2014 its mtime marks the review start"
18286
+ }).option("out", {
18287
+ type: "string",
18288
+ describe: "Also write the full ledger as JSON to this path"
18289
+ }), "builder"),
18290
+ handler: /* @__PURE__ */ __name((args) => {
18291
+ runCostLedger(args);
18292
+ }, "handler")
18293
+ };
18294
+
17345
18295
  // packages/cli/src/commands/review/run.ts
17346
18296
  init_esbuild_shims();
17347
18297
  import { spawn, execFileSync as execFileSync6 } from "node:child_process";
17348
- import { readdirSync as readdirSync7, readFileSync as readFileSync29, realpathSync as realpathSync3, statSync as statSync10 } from "node:fs";
17349
- import { dirname as dirname22, join as join21, resolve as resolve21 } from "node:path";
18298
+ import { readdirSync as readdirSync7, readFileSync as readFileSync30, realpathSync as realpathSync3, statSync as statSync13 } from "node:fs";
18299
+ import { dirname as dirname23, join as join22, resolve as resolve22 } from "node:path";
17350
18300
  var COMPOSED_PATTERN = /^qwen-review-.*composed\.json$/;
17351
18301
  var COMPOSED_POLL_MS = 250;
17352
18302
  var SIGNAL_EXIT_CODES = {
@@ -17380,10 +18330,10 @@ function newestArtifactSince(dir, pattern, startMs) {
17380
18330
  }
17381
18331
  for (const name of names) {
17382
18332
  if (!pattern.test(name)) continue;
17383
- const path3 = join21(dir, name);
18333
+ const path3 = join22(dir, name);
17384
18334
  let mtime;
17385
18335
  try {
17386
- mtime = statSync10(path3).mtimeMs;
18336
+ mtime = statSync13(path3).mtimeMs;
17387
18337
  } catch {
17388
18338
  continue;
17389
18339
  }
@@ -17401,7 +18351,7 @@ function exitCodeFor(completed, event2, failOn) {
17401
18351
  __name(exitCodeFor, "exitCodeFor");
17402
18352
  function readComposed(path3) {
17403
18353
  try {
17404
- const parsed = JSON.parse(readFileSync29(path3, "utf8"));
18354
+ const parsed = JSON.parse(readFileSync30(path3, "utf8"));
17405
18355
  return typeof parsed.event === "string" ? parsed : null;
17406
18356
  } catch {
17407
18357
  return null;
@@ -17432,7 +18382,7 @@ function childEnv() {
17432
18382
  return env;
17433
18383
  }
17434
18384
  try {
17435
- if (dirname22(realpathSync3(inherited)) === dirname22(realpathSync3(ownEntry))) {
18385
+ if (dirname23(realpathSync3(inherited)) === dirname23(realpathSync3(ownEntry))) {
17436
18386
  return env;
17437
18387
  }
17438
18388
  } catch {
@@ -17554,8 +18504,8 @@ async function runReview(args) {
17554
18504
  downgraded: composed?.downgraded ?? false,
17555
18505
  downgradedFrom: composed?.downgradedFrom ?? null,
17556
18506
  remediation: composed?.remediation ?? [],
17557
- composedPath: composedPath ? resolve21(composedPath) : null,
17558
- reportPath: reportPath ? resolve21(reportPath) : null,
18507
+ composedPath: composedPath ? resolve22(composedPath) : null,
18508
+ reportPath: reportPath ? resolve22(reportPath) : null,
17559
18509
  childExitCode,
17560
18510
  childSignal,
17561
18511
  timedOut,
@@ -17569,7 +18519,7 @@ async function runReview(args) {
17569
18519
  writeStdoutLine(result.verdictLine ?? `Event: ${result.event}`);
17570
18520
  if (result.reportPath) writeStdoutLine(`Report: ${result.reportPath}`);
17571
18521
  } else {
17572
- const detail = composedPath !== null ? `a composed verdict was found at ${resolve21(composedPath)} but could not be parsed` : "no composed verdict was produced";
18522
+ const detail = composedPath !== null ? `a composed verdict was found at ${resolve22(composedPath)} but could not be parsed` : "no composed verdict was produced";
17573
18523
  writeStdoutLine(
17574
18524
  timedOut ? "Review did not complete: timed out." : `Review did not complete: ${detail}${childExitCode !== null ? ` (CLI exit ${childExitCode})` : ""}${childSignal !== null ? ` (killed by ${childSignal})` : ""}.`
17575
18525
  );
@@ -17637,22 +18587,22 @@ init_esbuild_shims();
17637
18587
  import {
17638
18588
  existsSync as existsSync14,
17639
18589
  lstatSync as lstatSync5,
17640
- mkdirSync as mkdirSync26,
17641
- readFileSync as readFileSync30,
17642
- statSync as statSync11
18590
+ mkdirSync as mkdirSync27,
18591
+ readFileSync as readFileSync31,
18592
+ statSync as statSync14
17643
18593
  } from "node:fs";
17644
18594
  import {
17645
- dirname as dirname23,
18595
+ dirname as dirname24,
17646
18596
  isAbsolute as isAbsolute4,
17647
- join as join22,
18597
+ join as join23,
17648
18598
  relative as relative3,
17649
- resolve as resolve22,
18599
+ resolve as resolve23,
17650
18600
  sep as sep4,
17651
18601
  toNamespacedPath
17652
18602
  } from "node:path";
17653
18603
  import { isDeepStrictEqual } from "node:util";
17654
18604
  function workspaceRoot() {
17655
- return resolve22(process.env["QWEN_CODE_PROJECT_DIR"] ?? process.cwd());
18605
+ return resolve23(process.env["QWEN_CODE_PROJECT_DIR"] ?? process.cwd());
17656
18606
  }
17657
18607
  __name(workspaceRoot, "workspaceRoot");
17658
18608
  function isWithin(parent, child) {
@@ -17661,7 +18611,7 @@ function isWithin(parent, child) {
17661
18611
  }
17662
18612
  __name(isWithin, "isWithin");
17663
18613
  function workspacePath(root, value, label2) {
17664
- const absolute = resolve22(root, value);
18614
+ const absolute = resolve23(root, value);
17665
18615
  if (!isWithin(root, absolute)) {
17666
18616
  throw new Error(
17667
18617
  `${label2} must be inside the workspace: ${JSON.stringify(value)}.`
@@ -17674,7 +18624,7 @@ function rejectSymlinkPath(root, path3, label2) {
17674
18624
  const rel = relative3(root, path3);
17675
18625
  let current = root;
17676
18626
  for (const segment of rel.split(sep4)) {
17677
- current = join22(current, segment);
18627
+ current = join23(current, segment);
17678
18628
  if (existsSync14(current) && lstatSync5(current).isSymbolicLink()) {
17679
18629
  throw new Error(`${label2} must not traverse a symbolic link.`);
17680
18630
  }
@@ -17684,14 +18634,14 @@ __name(rejectSymlinkPath, "rejectSymlinkPath");
17684
18634
  function sameFile(left, right) {
17685
18635
  if (left === right) return true;
17686
18636
  if (!existsSync14(left) || !existsSync14(right)) return false;
17687
- const leftStat = statSync11(left);
17688
- const rightStat = statSync11(right);
18637
+ const leftStat = statSync14(left);
18638
+ const rightStat = statSync14(right);
17689
18639
  return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
17690
18640
  }
17691
18641
  __name(sameFile, "sameFile");
17692
18642
  function readText(path3, label2) {
17693
18643
  try {
17694
- return readFileSync30(path3, "utf8");
18644
+ return readFileSync31(path3, "utf8");
17695
18645
  } catch (error) {
17696
18646
  throw new Error(
17697
18647
  `Could not read the ${label2} file at ${JSON.stringify(path3)}: ${error instanceof Error ? error.message : String(error)}`
@@ -17817,7 +18767,7 @@ function saveReviewArtifact(args) {
17817
18767
  const composedPath = workspacePath(root, args.composed, "Composed input");
17818
18768
  const reportPath = workspacePath(root, args.report, "Markdown report");
17819
18769
  const outputPath = workspacePath(root, args.out, "Output");
17820
- const reviewsRoot = resolve22(root, REVIEWS_DIR);
18770
+ const reviewsRoot = resolve23(root, REVIEWS_DIR);
17821
18771
  if (!isWithin(reviewsRoot, reportPath) || reportPath === reviewsRoot) {
17822
18772
  throw new Error(
17823
18773
  `Markdown report must be a file under ${JSON.stringify(REVIEWS_DIR)}: ${JSON.stringify(args.report)}.`
@@ -17858,7 +18808,7 @@ function saveReviewArtifact(args) {
17858
18808
  const verdict = validateVerdict(readJson2(composedPath, "composed verdict"));
17859
18809
  let reportIsFile;
17860
18810
  try {
17861
- reportIsFile = statSync11(reportPath).isFile();
18811
+ reportIsFile = statSync14(reportPath).isFile();
17862
18812
  } catch {
17863
18813
  }
17864
18814
  if (reportIsFile === false) {
@@ -17878,7 +18828,7 @@ function saveReviewArtifact(args) {
17878
18828
  outcomesRecorded: findings.outcomesRecorded,
17879
18829
  markdownReportPath
17880
18830
  };
17881
- mkdirSync26(dirname23(outputPath), { recursive: true });
18831
+ mkdirSync27(dirname24(outputPath), { recursive: true });
17882
18832
  atomicWriteFileSync(
17883
18833
  toNamespacedPath(outputPath),
17884
18834
  `${JSON.stringify(document, null, 2)}
@@ -17931,9 +18881,9 @@ var saveArtifactCommand = {
17931
18881
  var reviewCommand = {
17932
18882
  command: "review",
17933
18883
  describe: "Run a review non-interactively (`run`), plus the internal helpers used by the /review skill (PR worktree setup, context fetch, rules loading, presubmit checks, cleanup)",
17934
- builder: /* @__PURE__ */ __name((yargs) => yargs.command(runCommand).command(parseArgsCommand).command(fetchPrCommand).command(captureLocalCommand).command(planDiffCommand).command(prContextCommand).command(commentStatusCommand).command(loadRulesCommand).command(agentPromptCommand).command(buildTestCommand).command(baseTreeCommand).command(testDeltaCommand).command(driveCommand).command(mockProviderCommand).command(extractStepCommand).command(scriptLintCommand).command(resolveAnchorsCommand).command(checkCoverageCommand).command(presubmitCommand).command(testEfficacyCommand).command(testPlanCommand).command(findingsCommand).command(publishAssetsCommand).command(composeReviewCommand).command(saveArtifactCommand).command(submitCommand).command(cleanupCommand).demandCommand(
18884
+ builder: /* @__PURE__ */ __name((yargs) => yargs.command(runCommand).command(parseArgsCommand).command(fetchPrCommand).command(captureLocalCommand).command(planDiffCommand).command(prContextCommand).command(commentStatusCommand).command(loadRulesCommand).command(agentPromptCommand).command(buildTestCommand).command(baseTreeCommand).command(testDeltaCommand).command(driveCommand).command(mockProviderCommand).command(extractStepCommand).command(scriptLintCommand).command(resolveAnchorsCommand).command(checkCoverageCommand).command(costLedgerCommand).command(presubmitCommand).command(testEfficacyCommand).command(testPlanCommand).command(findingsCommand).command(publishAssetsCommand).command(composeReviewCommand).command(saveArtifactCommand).command(submitCommand).command(cleanupCommand).demandCommand(
17935
18885
  1,
17936
- "Specify a subcommand: run, parse-args, fetch-pr, capture-local, plan-diff, pr-context, comment-status, load-rules, agent-prompt, build-test, base-tree, test-delta, drive, mock-provider, extract-step, script-lint, resolve-anchors, check-coverage, presubmit, test-efficacy, test-plan, findings, publish-assets, compose-review, save-artifact, submit, or cleanup."
18886
+ "Specify a subcommand: run, parse-args, fetch-pr, capture-local, plan-diff, pr-context, comment-status, load-rules, agent-prompt, build-test, base-tree, test-delta, drive, mock-provider, extract-step, script-lint, resolve-anchors, check-coverage, cost-ledger, presubmit, test-efficacy, test-plan, findings, publish-assets, compose-review, save-artifact, submit, or cleanup."
17937
18887
  ).version(false), "builder"),
17938
18888
  handler: /* @__PURE__ */ __name(() => {
17939
18889
  }, "handler")
@@ -18133,11 +19083,11 @@ var updateCommand3 = {
18133
19083
  stdioHelpers,
18134
19084
  { updateEventEmitter }
18135
19085
  ] = await Promise.all([
18136
- import("./settings-NX4EUIE6.js"),
18137
- import("./updateCheck-FDAVGOFT.js"),
18138
- import("./installationInfo-AEGIIQAT.js"),
18139
- import("./standalone-update-ICW7H5IF.js"),
18140
- import("./stdioHelpers-HGIYTWAY.js"),
19086
+ import("./settings-AI2BTBOZ.js"),
19087
+ import("./updateCheck-UOVZSTP7.js"),
19088
+ import("./installationInfo-PO4Z3ES7.js"),
19089
+ import("./standalone-update-WVINHRNS.js"),
19090
+ import("./stdioHelpers-7A2EE64Z.js"),
18141
19091
  import("./updateEventEmitter-5MKC7BLQ.js")
18142
19092
  ]);
18143
19093
  const { formatUpdateInstructions, getInstallationInfo } = installationInfoModule;
@@ -19303,7 +20253,7 @@ async function loadCliConfig(settings, argv, cwd = process.cwd(), overrideExtens
19303
20253
  disabledSlashCommands: disabledSlashCommands.length > 0 ? disabledSlashCommands : void 0,
19304
20254
  disabledSkillNamesProvider: bareMode || safeMode ? void 0 : disabledSkillNamesProvider,
19305
20255
  terminalImageRenderSupportProvider: interactive ? async () => {
19306
- const { getTerminalImageRenderSupport } = await import("./terminal-image-renderer-PW6Z6VFY.js");
20256
+ const { getTerminalImageRenderSupport } = await import("./terminal-image-renderer-II74TFVW.js");
19307
20257
  return getTerminalImageRenderSupport();
19308
20258
  } : void 0,
19309
20259
  disabledSkillLevels: bareMode || safeMode || !Array.isArray(settings.skills?.disabledLevels) ? void 0 : settings.skills.disabledLevels.filter(isSkillLevel),